1 // Copyright 2016 The Weave Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/access_api_handler.h"
6
7 #include <gtest/gtest.h>
8 #include <weave/provider/test/fake_task_runner.h>
9 #include <weave/test/mock_device.h>
10 #include <weave/test/unittest_utils.h>
11
12 #include "src/component_manager_impl.h"
13 #include "src/access_black_list_manager.h"
14 #include "src/data_encoding.h"
15
16 using testing::_;
17 using testing::AnyOf;
18 using testing::Invoke;
19 using testing::Return;
20 using testing::StrictMock;
21 using testing::WithArgs;
22
23 namespace weave {
24
25 class MockAccessBlackListManager : public AccessBlackListManager {
26 public:
27 MOCK_METHOD4(Block,
28 void(const std::vector<uint8_t>&,
29 const std::vector<uint8_t>&,
30 const base::Time&,
31 const DoneCallback&));
32 MOCK_METHOD3(Unblock,
33 void(const std::vector<uint8_t>&,
34 const std::vector<uint8_t>&,
35 const DoneCallback&));
36 MOCK_CONST_METHOD2(IsBlocked,
37 bool(const std::vector<uint8_t>&,
38 const std::vector<uint8_t>&));
39 MOCK_CONST_METHOD0(GetEntries, std::vector<Entry>());
40 MOCK_CONST_METHOD0(GetSize, size_t());
41 MOCK_CONST_METHOD0(GetCapacity, size_t());
42 };
43
44 class AccessApiHandlerTest : public ::testing::Test {
45 protected:
SetUp()46 void SetUp() override {
47 EXPECT_CALL(device_, AddTraitDefinitionsFromJson(_))
48 .WillRepeatedly(Invoke([this](const std::string& json) {
49 EXPECT_TRUE(component_manager_.LoadTraits(json, nullptr));
50 }));
51 EXPECT_CALL(device_, SetStateProperties(_, _, _))
52 .WillRepeatedly(
53 Invoke(&component_manager_, &ComponentManager::SetStateProperties));
54 EXPECT_CALL(device_, SetStateProperty(_, _, _, _))
55 .WillRepeatedly(
56 Invoke(&component_manager_, &ComponentManager::SetStateProperty));
57 EXPECT_CALL(device_, AddComponent(_, _, _))
58 .WillRepeatedly(Invoke([this](const std::string& name,
59 const std::vector<std::string>& traits,
60 ErrorPtr* error) {
61 return component_manager_.AddComponent("", name, traits, error);
62 }));
63
64 EXPECT_CALL(device_,
65 AddCommandHandler(_, AnyOf("_accessControlBlackList.block",
66 "_accessControlBlackList.unblock",
67 "_accessControlBlackList.list"),
68 _))
69 .WillRepeatedly(
70 Invoke(&component_manager_, &ComponentManager::AddCommandHandler));
71
72 EXPECT_CALL(access_manager_, GetSize()).WillRepeatedly(Return(0));
73
74 EXPECT_CALL(access_manager_, GetCapacity()).WillRepeatedly(Return(10));
75
76 handler_.reset(new AccessApiHandler{&device_, &access_manager_});
77 }
78
AddCommand(const std::string & command)79 const base::DictionaryValue& AddCommand(const std::string& command) {
80 std::string id;
81 auto command_instance = component_manager_.ParseCommandInstance(
82 *test::CreateDictionaryValue(command.c_str()), Command::Origin::kLocal,
83 UserRole::kOwner, &id, nullptr);
84 EXPECT_NE(nullptr, command_instance.get());
85 component_manager_.AddCommand(std::move(command_instance));
86 EXPECT_EQ(Command::State::kDone,
87 component_manager_.FindCommand(id)->GetState());
88 return component_manager_.FindCommand(id)->GetResults();
89 }
90
GetState()91 std::unique_ptr<base::DictionaryValue> GetState() {
92 std::string path =
93 component_manager_.FindComponentWithTrait("_accessControlBlackList");
94 EXPECT_FALSE(path.empty());
95 const auto* component = component_manager_.FindComponent(path, nullptr);
96 EXPECT_TRUE(component);
97 const base::DictionaryValue* state = nullptr;
98 EXPECT_TRUE(
99 component->GetDictionary("state._accessControlBlackList", &state));
100 return std::unique_ptr<base::DictionaryValue>{state->DeepCopy()};
101 }
102
103 StrictMock<provider::test::FakeTaskRunner> task_runner_;
104 ComponentManagerImpl component_manager_{&task_runner_};
105 StrictMock<test::MockDevice> device_;
106 StrictMock<MockAccessBlackListManager> access_manager_;
107 std::unique_ptr<AccessApiHandler> handler_;
108 };
109
TEST_F(AccessApiHandlerTest,Initialization)110 TEST_F(AccessApiHandlerTest, Initialization) {
111 const base::DictionaryValue* trait = nullptr;
112 ASSERT_TRUE(component_manager_.GetTraits().GetDictionary(
113 "_accessControlBlackList", &trait));
114
115 auto expected = R"({
116 "commands": {
117 "block": {
118 "minimalRole": "owner",
119 "parameters": {
120 "userId": {
121 "type": "string"
122 },
123 "applicationId": {
124 "type": "string"
125 },
126 "expirationTimeoutSec": {
127 "type": "integer"
128 }
129 }
130 },
131 "unblock": {
132 "minimalRole": "owner",
133 "parameters": {
134 "userId": {
135 "type": "string"
136 },
137 "applicationId": {
138 "type": "string"
139 }
140 }
141 },
142 "list": {
143 "minimalRole": "owner",
144 "parameters": {},
145 "results": {
146 "blackList": {
147 "type": "array",
148 "items": {
149 "type": "object",
150 "properties": {
151 "userId": {
152 "type": "string"
153 },
154 "applicationId": {
155 "type": "string"
156 }
157 },
158 "additionalProperties": false
159 }
160 }
161 }
162 }
163 },
164 "state": {
165 "size": {
166 "type": "integer",
167 "isRequired": true
168 },
169 "capacity": {
170 "type": "integer",
171 "isRequired": true
172 }
173 }
174 })";
175 EXPECT_JSON_EQ(expected, *trait);
176
177 expected = R"({
178 "capacity": 10,
179 "size": 0
180 })";
181 EXPECT_JSON_EQ(expected, *GetState());
182 }
183
TEST_F(AccessApiHandlerTest,Block)184 TEST_F(AccessApiHandlerTest, Block) {
185 EXPECT_CALL(access_manager_, Block(std::vector<uint8_t>{1, 2, 3},
186 std::vector<uint8_t>{3, 4, 5}, _, _))
187 .WillOnce(WithArgs<3>(
188 Invoke([](const DoneCallback& callback) { callback.Run(nullptr); })));
189 EXPECT_CALL(access_manager_, GetSize()).WillRepeatedly(Return(1));
190
191 AddCommand(R"({
192 'name' : '_accessControlBlackList.block',
193 'component': 'accessControl',
194 'parameters': {
195 'userId': 'AQID',
196 'applicationId': 'AwQF',
197 'expirationTimeoutSec': 1234
198 }
199 })");
200
201 auto expected = R"({
202 "capacity": 10,
203 "size": 1
204 })";
205 EXPECT_JSON_EQ(expected, *GetState());
206 }
207
TEST_F(AccessApiHandlerTest,Unblock)208 TEST_F(AccessApiHandlerTest, Unblock) {
209 EXPECT_CALL(access_manager_, Unblock(std::vector<uint8_t>{1, 2, 3},
210 std::vector<uint8_t>{3, 4, 5}, _))
211 .WillOnce(WithArgs<2>(
212 Invoke([](const DoneCallback& callback) { callback.Run(nullptr); })));
213 EXPECT_CALL(access_manager_, GetSize()).WillRepeatedly(Return(4));
214
215 AddCommand(R"({
216 'name' : '_accessControlBlackList.unblock',
217 'component': 'accessControl',
218 'parameters': {
219 'userId': 'AQID',
220 'applicationId': 'AwQF',
221 'expirationTimeoutSec': 1234
222 }
223 })");
224
225 auto expected = R"({
226 "capacity": 10,
227 "size": 4
228 })";
229 EXPECT_JSON_EQ(expected, *GetState());
230 }
231
TEST_F(AccessApiHandlerTest,List)232 TEST_F(AccessApiHandlerTest, List) {
233 std::vector<AccessBlackListManager::Entry> entries{
234 {{11, 12, 13}, {21, 22, 23}, base::Time::FromTimeT(1410000000)},
235 {{31, 32, 33}, {41, 42, 43}, base::Time::FromTimeT(1420000000)},
236 };
237 EXPECT_CALL(access_manager_, GetEntries()).WillOnce(Return(entries));
238 EXPECT_CALL(access_manager_, GetSize()).WillRepeatedly(Return(4));
239
240 auto expected = R"({
241 "blackList": [ {
242 "applicationId": "FRYX",
243 "userId": "CwwN"
244 }, {
245 "applicationId": "KSor",
246 "userId": "HyAh"
247 } ]
248 })";
249
250 const auto& results = AddCommand(R"({
251 'name' : '_accessControlBlackList.list',
252 'component': 'accessControl',
253 'parameters': {
254 }
255 })");
256
257 EXPECT_JSON_EQ(expected, results);
258 }
259 } // namespace weave
260