1 // Copyright 2015 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/base_api_handler.h"
6
7 #include <base/strings/string_number_conversions.h>
8 #include <base/time/default_clock.h>
9 #include <base/values.h>
10 #include <gtest/gtest.h>
11 #include <weave/provider/test/fake_task_runner.h>
12 #include <weave/provider/test/mock_config_store.h>
13 #include <weave/provider/test/mock_http_client.h>
14 #include <weave/test/mock_device.h>
15 #include <weave/test/unittest_utils.h>
16
17 #include "src/component_manager_impl.h"
18 #include "src/config.h"
19 #include "src/device_registration_info.h"
20
21 using testing::_;
22 using testing::AnyOf;
23 using testing::Eq;
24 using testing::Invoke;
25 using testing::Return;
26 using testing::ReturnRef;
27 using testing::StrictMock;
28
29 namespace weave {
30
31 class BaseApiHandlerTest : public ::testing::Test {
32 protected:
SetUp()33 void SetUp() override {
34 EXPECT_CALL(device_, AddTraitDefinitionsFromJson(_))
35 .WillRepeatedly(Invoke([this](const std::string& json) {
36 EXPECT_TRUE(component_manager_.LoadTraits(json, nullptr));
37 }));
38 EXPECT_CALL(device_, SetStateProperties(_, _, _))
39 .WillRepeatedly(
40 Invoke(&component_manager_, &ComponentManager::SetStateProperties));
41 EXPECT_CALL(device_, SetStateProperty(_, _, _, _))
42 .WillRepeatedly(
43 Invoke(&component_manager_, &ComponentManager::SetStateProperty));
44 EXPECT_CALL(device_, AddComponent(_, _, _))
45 .WillRepeatedly(Invoke([this](const std::string& name,
46 const std::vector<std::string>& traits,
47 ErrorPtr* error) {
48 return component_manager_.AddComponent("", name, traits, error);
49 }));
50
51 EXPECT_CALL(device_,
52 AddCommandHandler(_, AnyOf("base.updateBaseConfiguration",
53 "base.updateDeviceInfo"),
54 _))
55 .WillRepeatedly(
56 Invoke(&component_manager_, &ComponentManager::AddCommandHandler));
57
58 dev_reg_.reset(new DeviceRegistrationInfo(&config_, &component_manager_,
59 nullptr, &http_client_, nullptr,
60 nullptr));
61
62 EXPECT_CALL(device_, GetSettings())
63 .WillRepeatedly(ReturnRef(dev_reg_->GetSettings()));
64
65 handler_.reset(new BaseApiHandler{dev_reg_.get(), &device_});
66 }
67
AddCommand(const std::string & command)68 void AddCommand(const std::string& command) {
69 std::string id;
70 auto command_instance = component_manager_.ParseCommandInstance(
71 *test::CreateDictionaryValue(command.c_str()), Command::Origin::kLocal,
72 UserRole::kOwner, &id, nullptr);
73 ASSERT_NE(nullptr, command_instance.get());
74 component_manager_.AddCommand(std::move(command_instance));
75 EXPECT_EQ(Command::State::kDone,
76 component_manager_.FindCommand(id)->GetState());
77 }
78
GetBaseState()79 std::unique_ptr<base::DictionaryValue> GetBaseState() {
80 std::unique_ptr<base::DictionaryValue> state;
81 std::string path = component_manager_.FindComponentWithTrait("base");
82 EXPECT_FALSE(path.empty());
83 const auto* component = component_manager_.FindComponent(path, nullptr);
84 CHECK(component);
85 const base::DictionaryValue* base_state = nullptr;
86 if (component->GetDictionary("state.base", &base_state))
87 state.reset(base_state->DeepCopy());
88 else
89 state.reset(new base::DictionaryValue);
90 return state;
91 }
92
93 provider::test::MockConfigStore config_store_;
94 Config config_{&config_store_};
95 StrictMock<provider::test::MockHttpClient> http_client_;
96 std::unique_ptr<DeviceRegistrationInfo> dev_reg_;
97 StrictMock<provider::test::FakeTaskRunner> task_runner_;
98 ComponentManagerImpl component_manager_{&task_runner_};
99 std::unique_ptr<BaseApiHandler> handler_;
100 StrictMock<test::MockDevice> device_;
101 };
102
TEST_F(BaseApiHandlerTest,Initialization)103 TEST_F(BaseApiHandlerTest, Initialization) {
104 const base::DictionaryValue* trait = nullptr;
105 ASSERT_TRUE(component_manager_.GetTraits().GetDictionary("base", &trait));
106
107 auto expected = R"({
108 "commands": {
109 "updateBaseConfiguration": {
110 "minimalRole": "manager",
111 "parameters": {
112 "localAnonymousAccessMaxRole": {
113 "enum": [ "none", "viewer", "user" ],
114 "type": "string"
115 },
116 "localDiscoveryEnabled": {
117 "type": "boolean"
118 },
119 "localPairingEnabled": {
120 "type": "boolean"
121 }
122 }
123 },
124 "updateDeviceInfo": {
125 "minimalRole": "manager",
126 "parameters": {
127 "description": {
128 "type": "string"
129 },
130 "location": {
131 "type": "string"
132 },
133 "name": {
134 "type": "string"
135 }
136 }
137 },
138 "reboot": {
139 "minimalRole": "user",
140 "parameters": {},
141 "errors": ["notEnoughBattery"]
142 },
143 "identify": {
144 "minimalRole": "user",
145 "parameters": {}
146 }
147 },
148 "state": {
149 "firmwareVersion": {
150 "type": "string",
151 "isRequired": true
152 },
153 "localDiscoveryEnabled": {
154 "type": "boolean",
155 "isRequired": true
156 },
157 "localAnonymousAccessMaxRole": {
158 "type": "string",
159 "enum": [ "none", "viewer", "user" ],
160 "isRequired": true
161 },
162 "localPairingEnabled": {
163 "type": "boolean",
164 "isRequired": true
165 },
166 "connectionStatus": {
167 "type": "string"
168 },
169 "network": {
170 "type": "object",
171 "additionalProperties": false,
172 "properties": {
173 "name": { "type": "string" }
174 }
175 }
176 }
177 })";
178 EXPECT_JSON_EQ(expected, *trait);
179 }
180
TEST_F(BaseApiHandlerTest,UpdateBaseConfiguration)181 TEST_F(BaseApiHandlerTest, UpdateBaseConfiguration) {
182 const Settings& settings = dev_reg_->GetSettings();
183
184 AddCommand(R"({
185 'name' : 'base.updateBaseConfiguration',
186 'component': 'base',
187 'parameters': {
188 'localDiscoveryEnabled': false,
189 'localAnonymousAccessMaxRole': 'none',
190 'localPairingEnabled': false
191 }
192 })");
193 EXPECT_EQ(AuthScope::kNone, settings.local_anonymous_access_role);
194 EXPECT_FALSE(settings.local_discovery_enabled);
195 EXPECT_FALSE(settings.local_pairing_enabled);
196
197 auto expected = R"({
198 'firmwareVersion': 'TEST_FIRMWARE',
199 'localAnonymousAccessMaxRole': 'none',
200 'localDiscoveryEnabled': false,
201 'localPairingEnabled': false
202 })";
203 EXPECT_JSON_EQ(expected, *GetBaseState());
204
205 AddCommand(R"({
206 'name' : 'base.updateBaseConfiguration',
207 'component': 'base',
208 'parameters': {
209 'localDiscoveryEnabled': true,
210 'localAnonymousAccessMaxRole': 'user',
211 'localPairingEnabled': true
212 }
213 })");
214 EXPECT_EQ(AuthScope::kUser, settings.local_anonymous_access_role);
215 EXPECT_TRUE(settings.local_discovery_enabled);
216 EXPECT_TRUE(settings.local_pairing_enabled);
217 expected = R"({
218 'firmwareVersion': 'TEST_FIRMWARE',
219 'localAnonymousAccessMaxRole': 'user',
220 'localDiscoveryEnabled': true,
221 'localPairingEnabled': true
222 })";
223 EXPECT_JSON_EQ(expected, *GetBaseState());
224
225 {
226 Config::Transaction change{dev_reg_->GetMutableConfig()};
227 change.set_local_anonymous_access_role(AuthScope::kViewer);
228 }
229 expected = R"({
230 'firmwareVersion': 'TEST_FIRMWARE',
231 'localAnonymousAccessMaxRole': 'viewer',
232 'localDiscoveryEnabled': true,
233 'localPairingEnabled': true
234 })";
235 EXPECT_JSON_EQ(expected, *GetBaseState());
236 }
237
TEST_F(BaseApiHandlerTest,UpdateDeviceInfo)238 TEST_F(BaseApiHandlerTest, UpdateDeviceInfo) {
239 AddCommand(R"({
240 'name' : 'base.updateDeviceInfo',
241 'component': 'base',
242 'parameters': {
243 'name': 'testName',
244 'description': 'testDescription',
245 'location': 'testLocation'
246 }
247 })");
248
249 const Settings& config = dev_reg_->GetSettings();
250 EXPECT_EQ("testName", config.name);
251 EXPECT_EQ("testDescription", config.description);
252 EXPECT_EQ("testLocation", config.location);
253
254 AddCommand(R"({
255 'name' : 'base.updateDeviceInfo',
256 'component': 'base',
257 'parameters': {
258 'location': 'newLocation'
259 }
260 })");
261
262 EXPECT_EQ("testName", config.name);
263 EXPECT_EQ("testDescription", config.description);
264 EXPECT_EQ("newLocation", config.location);
265 }
266
267 } // namespace weave
268