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