blob: 97dc00d6152add99e60ec50dfb34e68474c9eeee [file] [log] [blame]
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -08001// 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
Alex Vakulenkoba981152015-12-05 13:58:22 -08005#include "src/component_manager_impl.h"
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -08006
7#include <map>
8
9#include <gtest/gtest.h>
Alex Vakulenko98d1fee2016-02-01 12:25:21 -080010#include <weave/provider/test/fake_task_runner.h>
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080011#include <weave/test/unittest_utils.h>
12
13#include "src/bind_lambda.h"
14#include "src/commands/schema_constants.h"
Alex Vakulenkoba981152015-12-05 13:58:22 -080015#include "src/mock_component_manager.h"
Vitaly Bukaece713e2015-12-09 10:59:33 -080016#include "src/test/mock_clock.h"
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080017
18namespace weave {
19
20using test::CreateDictionaryValue;
Vitaly Bukaece713e2015-12-09 10:59:33 -080021using testing::Return;
Vitaly Bukabcd3f6a2016-01-19 17:09:02 -080022using testing::StrictMock;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080023
24namespace {
25
26bool HasTrait(const base::DictionaryValue& comp, const std::string& trait) {
27 const base::ListValue* list = nullptr;
28 if (!comp.GetList("traits", &list))
29 return false;
30 for (const base::Value* item : *list) {
31 std::string value;
32 if (item->GetAsString(&value) && value == trait)
33 return true;
34 }
35 return false;
36}
37
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080038// Creates sample trait/component trees:
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -080039// {
40// "traits": {
41// "t1": {},
42// "t2": {},
43// "t3": {},
44// "t4": {},
45// "t5": {},
46// "t6": {},
47// },
48// "components": {
49// "comp1": {
50// "traits": [ "t1" ],
51// "components": {
52// "comp2": [
53// { "traits": [ "t2" ] },
54// {
55// "traits": [ "t3" ],
56// "components": {
57// "comp3": {
58// "traits": [ "t4" ],
59// "components": {
60// "comp4": {
61// "traits": [ "t5", "t6" ]
62// }
63// }
64// }
65// }
66// }
67// ],
68// }
69// }
70// }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080071// }
Vitaly Bukaece713e2015-12-09 10:59:33 -080072class ComponentManagerTest : public ::testing::Test {
73 protected:
Vitaly Bukabcd3f6a2016-01-19 17:09:02 -080074 void SetUp() override {
75 EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(base::Time::Now()));
76 }
77
Vitaly Bukaece713e2015-12-09 10:59:33 -080078 void CreateTestComponentTree(ComponentManager* manager) {
79 const char kTraits[] =
80 R"({"t1":{},"t2":{},"t3":{},"t4":{},"t5":{},"t6":{}})";
81 auto json = CreateDictionaryValue(kTraits);
82 ASSERT_TRUE(manager->LoadTraits(*json, nullptr));
83 EXPECT_TRUE(manager->AddComponent("", "comp1", {"t1"}, nullptr));
84 EXPECT_TRUE(
85 manager->AddComponentArrayItem("comp1", "comp2", {"t2"}, nullptr));
86 EXPECT_TRUE(
87 manager->AddComponentArrayItem("comp1", "comp2", {"t3"}, nullptr));
88 EXPECT_TRUE(
89 manager->AddComponent("comp1.comp2[1]", "comp3", {"t4"}, nullptr));
90 EXPECT_TRUE(manager->AddComponent("comp1.comp2[1].comp3", "comp4",
91 {"t5", "t6"}, nullptr));
92 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080093
Alex Vakulenko98d1fee2016-02-01 12:25:21 -080094 StrictMock<provider::test::FakeTaskRunner> task_runner_;
Vitaly Bukabcd3f6a2016-01-19 17:09:02 -080095 StrictMock<test::MockClock> clock_;
Alex Vakulenko98d1fee2016-02-01 12:25:21 -080096 ComponentManagerImpl manager_{&task_runner_, &clock_};
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080097};
98
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080099} // anonymous namespace
100
Vitaly Bukaece713e2015-12-09 10:59:33 -0800101TEST_F(ComponentManagerTest, Empty) {
102 EXPECT_TRUE(manager_.GetTraits().empty());
103 EXPECT_TRUE(manager_.GetComponents().empty());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800104}
105
Vitaly Bukaece713e2015-12-09 10:59:33 -0800106TEST_F(ComponentManagerTest, LoadTraits) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800107 const char kTraits[] = R"({
108 "trait1": {
109 "commands": {
110 "command1": {
111 "minimalRole": "user",
112 "parameters": {"height": {"type": "integer"}}
113 }
114 },
115 "state": {
116 "property1": {"type": "boolean"}
117 }
118 },
119 "trait2": {
120 "state": {
121 "property2": {"type": "string"}
122 }
123 }
124 })";
125 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800126 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
127 EXPECT_JSON_EQ(kTraits, manager_.GetTraits());
128 EXPECT_TRUE(manager_.GetComponents().empty());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800129}
130
Vitaly Bukaece713e2015-12-09 10:59:33 -0800131TEST_F(ComponentManagerTest, LoadTraitsDuplicateIdentical) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800132 const char kTraits1[] = R"({
133 "trait1": {
134 "commands": {
135 "command1": {
136 "minimalRole": "user",
137 "parameters": {"height": {"type": "integer"}}
138 }
139 },
140 "state": {
141 "property1": {"type": "boolean"}
142 }
143 },
144 "trait2": {
145 "state": {
146 "property2": {"type": "string"}
147 }
148 }
149 })";
150 auto json = CreateDictionaryValue(kTraits1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800151 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800152 const char kTraits2[] = R"({
153 "trait1": {
154 "commands": {
155 "command1": {
156 "minimalRole": "user",
157 "parameters": {"height": {"type": "integer"}}
158 }
159 },
160 "state": {
161 "property1": {"type": "boolean"}
162 }
163 },
164 "trait3": {
165 "state": {
166 "property3": {"type": "string"}
167 }
168 }
169 })";
170 json = CreateDictionaryValue(kTraits2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800171 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800172 const char kExpected[] = R"({
173 "trait1": {
174 "commands": {
175 "command1": {
176 "minimalRole": "user",
177 "parameters": {"height": {"type": "integer"}}
178 }
179 },
180 "state": {
181 "property1": {"type": "boolean"}
182 }
183 },
184 "trait2": {
185 "state": {
186 "property2": {"type": "string"}
187 }
188 },
189 "trait3": {
190 "state": {
191 "property3": {"type": "string"}
192 }
193 }
194 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800195 EXPECT_JSON_EQ(kExpected, manager_.GetTraits());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800196}
197
Vitaly Bukaece713e2015-12-09 10:59:33 -0800198TEST_F(ComponentManagerTest, LoadTraitsDuplicateOverride) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800199 const char kTraits1[] = R"({
200 "trait1": {
201 "commands": {
202 "command1": {
203 "minimalRole": "user",
204 "parameters": {"height": {"type": "integer"}}
205 }
206 },
207 "state": {
208 "property1": {"type": "boolean"}
209 }
210 },
211 "trait2": {
212 "state": {
213 "property2": {"type": "string"}
214 }
215 }
216 })";
217 auto json = CreateDictionaryValue(kTraits1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800218 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800219 const char kTraits2[] = R"({
220 "trait1": {
221 "commands": {
222 "command1": {
223 "minimalRole": "user",
224 "parameters": {"height": {"type": "string"}}
225 }
226 },
227 "state": {
228 "property1": {"type": "boolean"}
229 }
230 },
231 "trait3": {
232 "state": {
233 "property3": {"type": "string"}
234 }
235 }
236 })";
237 json = CreateDictionaryValue(kTraits2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800238 EXPECT_FALSE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800239}
240
Vitaly Bukaece713e2015-12-09 10:59:33 -0800241TEST_F(ComponentManagerTest, AddTraitDefChangedCallback) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800242 int count = 0;
243 int count2 = 0;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800244 manager_.AddTraitDefChangedCallback(base::Bind([&count]() { count++; }));
245 manager_.AddTraitDefChangedCallback(base::Bind([&count2]() { count2++; }));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800246 EXPECT_EQ(1, count);
247 EXPECT_EQ(1, count2);
248 // New definitions.
249 const char kTraits1[] = R"({
250 "trait1": {
251 "state": {
252 "property1": {"type": "boolean"}
253 }
254 },
255 "trait2": {
256 "state": {
257 "property2": {"type": "string"}
258 }
259 }
260 })";
261 auto json = CreateDictionaryValue(kTraits1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800262 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800263 EXPECT_EQ(2, count);
264 // Duplicate definition, shouldn't call the callback.
265 const char kTraits2[] = R"({
266 "trait1": {
267 "state": {
268 "property1": {"type": "boolean"}
269 }
270 }
271 })";
272 json = CreateDictionaryValue(kTraits2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800273 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800274 EXPECT_EQ(2, count);
275 // New definition, should call the callback now.
276 const char kTraits3[] = R"({
277 "trait3": {
278 "state": {
279 "property3": {"type": "string"}
280 }
281 }
282 })";
283 json = CreateDictionaryValue(kTraits3);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800284 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800285 EXPECT_EQ(3, count);
286 // Wrong definition, shouldn't call the callback.
287 const char kTraits4[] = R"({
288 "trait4": "foo"
289 })";
290 json = CreateDictionaryValue(kTraits4);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800291 EXPECT_FALSE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800292 EXPECT_EQ(3, count);
293 // Make sure both callbacks were called the same number of times.
294 EXPECT_EQ(count2, count);
295}
296
Vitaly Bukaece713e2015-12-09 10:59:33 -0800297TEST_F(ComponentManagerTest, LoadTraitsNotAnObject) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800298 const char kTraits1[] = R"({"trait1": 0})";
299 auto json = CreateDictionaryValue(kTraits1);
300 ErrorPtr error;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800301 EXPECT_FALSE(manager_.LoadTraits(*json, &error));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800302 EXPECT_EQ(errors::commands::kTypeMismatch, error->GetCode());
303}
304
Vitaly Bukaece713e2015-12-09 10:59:33 -0800305TEST_F(ComponentManagerTest, FindTraitDefinition) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800306 const char kTraits[] = R"({
307 "trait1": {
308 "commands": {
309 "command1": {
310 "minimalRole": "user",
311 "parameters": {"height": {"type": "integer"}}
312 }
313 },
314 "state": {
315 "property1": {"type": "boolean"}
316 }
317 },
318 "trait2": {
319 "state": {
320 "property2": {"type": "string"}
321 }
322 }
323 })";
324 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800325 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800326
Vitaly Bukaece713e2015-12-09 10:59:33 -0800327 const base::DictionaryValue* trait = manager_.FindTraitDefinition("trait1");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800328 ASSERT_NE(nullptr, trait);
329 const char kExpected1[] = R"({
330 "commands": {
331 "command1": {
332 "minimalRole": "user",
333 "parameters": {"height": {"type": "integer"}}
334 }
335 },
336 "state": {
337 "property1": {"type": "boolean"}
338 }
339 })";
340 EXPECT_JSON_EQ(kExpected1, *trait);
341
Vitaly Bukaece713e2015-12-09 10:59:33 -0800342 trait = manager_.FindTraitDefinition("trait2");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800343 ASSERT_NE(nullptr, trait);
344 const char kExpected2[] = R"({
345 "state": {
346 "property2": {"type": "string"}
347 }
348 })";
349 EXPECT_JSON_EQ(kExpected2, *trait);
350
Vitaly Bukaece713e2015-12-09 10:59:33 -0800351 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait3"));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800352}
353
Vitaly Bukaece713e2015-12-09 10:59:33 -0800354TEST_F(ComponentManagerTest, FindCommandDefinition) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800355 const char kTraits[] = R"({
356 "trait1": {
357 "commands": {
358 "command1": {
359 "minimalRole": "user",
360 "parameters": {"height": {"type": "integer"}}
361 }
362 }
363 },
364 "trait2": {
365 "commands": {
366 "command1": {
367 "minimalRole": "manager"
368 },
369 "command2": {
370 "minimalRole": "owner"
371 }
372 }
373 }
374 })";
375 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800376 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800377
Vitaly Bukaece713e2015-12-09 10:59:33 -0800378 const auto* cmd_def = manager_.FindCommandDefinition("trait1.command1");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800379 ASSERT_NE(nullptr, cmd_def);
380 const char kExpected1[] = R"({
381 "minimalRole": "user",
382 "parameters": {"height": {"type": "integer"}}
383 })";
384 EXPECT_JSON_EQ(kExpected1, *cmd_def);
385
Vitaly Bukaece713e2015-12-09 10:59:33 -0800386 cmd_def = manager_.FindCommandDefinition("trait2.command1");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800387 ASSERT_NE(nullptr, cmd_def);
388 const char kExpected2[] = R"({
389 "minimalRole": "manager"
390 })";
391 EXPECT_JSON_EQ(kExpected2, *cmd_def);
392
Vitaly Bukaece713e2015-12-09 10:59:33 -0800393 cmd_def = manager_.FindCommandDefinition("trait2.command2");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800394 ASSERT_NE(nullptr, cmd_def);
395 const char kExpected3[] = R"({
396 "minimalRole": "owner"
397 })";
398 EXPECT_JSON_EQ(kExpected3, *cmd_def);
399
Vitaly Bukaece713e2015-12-09 10:59:33 -0800400 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait1.command2"));
401 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait3.command1"));
402 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait"));
403 EXPECT_EQ(nullptr,
404 manager_.FindTraitDefinition("trait1.command1.parameters"));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800405}
406
Vitaly Bukaece713e2015-12-09 10:59:33 -0800407TEST_F(ComponentManagerTest, GetMinimalRole) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800408 const char kTraits[] = R"({
409 "trait1": {
410 "commands": {
411 "command1": { "minimalRole": "user" },
412 "command2": { "minimalRole": "viewer" }
413 }
414 },
415 "trait2": {
416 "commands": {
417 "command1": { "minimalRole": "manager" },
418 "command2": { "minimalRole": "owner" }
419 }
420 }
421 })";
422 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800423 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800424
425 UserRole role;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800426 ASSERT_TRUE(manager_.GetMinimalRole("trait1.command1", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800427 EXPECT_EQ(UserRole::kUser, role);
428
Vitaly Bukaece713e2015-12-09 10:59:33 -0800429 ASSERT_TRUE(manager_.GetMinimalRole("trait1.command2", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800430 EXPECT_EQ(UserRole::kViewer, role);
431
Vitaly Bukaece713e2015-12-09 10:59:33 -0800432 ASSERT_TRUE(manager_.GetMinimalRole("trait2.command1", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800433 EXPECT_EQ(UserRole::kManager, role);
434
Vitaly Bukaece713e2015-12-09 10:59:33 -0800435 ASSERT_TRUE(manager_.GetMinimalRole("trait2.command2", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800436 EXPECT_EQ(UserRole::kOwner, role);
437
Vitaly Bukaece713e2015-12-09 10:59:33 -0800438 EXPECT_FALSE(manager_.GetMinimalRole("trait1.command3", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800439}
440
Vitaly Bukaece713e2015-12-09 10:59:33 -0800441TEST_F(ComponentManagerTest, AddComponent) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800442 const char kTraits[] = R"({"trait1": {}, "trait2": {}, "trait3": {}})";
443 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800444 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
445 EXPECT_TRUE(
446 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
447 EXPECT_TRUE(manager_.AddComponent("", "comp2", {"trait3"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800448 const char kExpected[] = R"({
449 "comp1": {
450 "traits": ["trait1", "trait2"]
451 },
452 "comp2": {
453 "traits": ["trait3"]
454 }
455 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800456 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800457
458 // 'trait4' is undefined, so can't add a component referring to it.
Vitaly Bukaece713e2015-12-09 10:59:33 -0800459 EXPECT_FALSE(manager_.AddComponent("", "comp3", {"trait4"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800460}
461
Vitaly Bukaece713e2015-12-09 10:59:33 -0800462TEST_F(ComponentManagerTest, AddSubComponent) {
463 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
464 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
465 EXPECT_TRUE(manager_.AddComponent("comp1", "comp3", {}, nullptr));
466 EXPECT_TRUE(manager_.AddComponent("comp1.comp2", "comp4", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800467 const char kExpected[] = R"({
468 "comp1": {
469 "traits": [],
470 "components": {
471 "comp2": {
472 "traits": [],
473 "components": {
474 "comp4": {
475 "traits": []
476 }
477 }
478 },
479 "comp3": {
480 "traits": []
481 }
482 }
483 }
484 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800485 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800486}
487
Vitaly Bukaece713e2015-12-09 10:59:33 -0800488TEST_F(ComponentManagerTest, AddComponentArrayItem) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800489 const char kTraits[] = R"({"foo": {}, "bar": {}})";
490 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800491 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800492
Vitaly Bukaece713e2015-12-09 10:59:33 -0800493 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
494 EXPECT_TRUE(
495 manager_.AddComponentArrayItem("comp1", "comp2", {"foo"}, nullptr));
496 EXPECT_TRUE(
497 manager_.AddComponentArrayItem("comp1", "comp2", {"bar"}, nullptr));
498 EXPECT_TRUE(manager_.AddComponent("comp1.comp2[1]", "comp3", {}, nullptr));
499 EXPECT_TRUE(
500 manager_.AddComponent("comp1.comp2[1].comp3", "comp4", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800501 const char kExpected[] = R"({
502 "comp1": {
503 "traits": [],
504 "components": {
505 "comp2": [
506 {
507 "traits": ["foo"]
508 },
509 {
510 "traits": ["bar"],
511 "components": {
512 "comp3": {
513 "traits": [],
514 "components": {
515 "comp4": {
516 "traits": []
517 }
518 }
519 }
520 }
521 }
522 ]
523 }
524 }
525 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800526 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800527}
528
Alex Vakulenkoce850b52016-01-04 09:27:50 -0800529TEST_F(ComponentManagerTest, RemoveComponent) {
530 CreateTestComponentTree(&manager_);
531 EXPECT_TRUE(manager_.RemoveComponent("comp1.comp2[1].comp3", "comp4",
532 nullptr));
533 const char kExpected1[] = R"({
534 "comp1": {
535 "traits": [ "t1" ],
536 "components": {
537 "comp2": [
538 {
539 "traits": [ "t2" ]
540 },
541 {
542 "traits": [ "t3" ],
543 "components": {
544 "comp3": {
545 "traits": [ "t4" ],
546 "components": {}
547 }
548 }
549 }
550 ]
551 }
552 }
553 })";
554 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
555 EXPECT_TRUE(manager_.RemoveComponentArrayItem("comp1", "comp2", 1, nullptr));
556 const char kExpected2[] = R"({
557 "comp1": {
558 "traits": [ "t1" ],
559 "components": {
560 "comp2": [
561 {
562 "traits": [ "t2" ]
563 }
564 ]
565 }
566 }
567 })";
568 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
569}
570
Vitaly Bukaece713e2015-12-09 10:59:33 -0800571TEST_F(ComponentManagerTest, AddComponentExist) {
572 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
573 EXPECT_FALSE(manager_.AddComponent("", "comp1", {}, nullptr));
574 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
575 EXPECT_FALSE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800576}
577
Vitaly Bukaece713e2015-12-09 10:59:33 -0800578TEST_F(ComponentManagerTest, AddComponentDoesNotExist) {
579 EXPECT_FALSE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800580}
581
Vitaly Bukaece713e2015-12-09 10:59:33 -0800582TEST_F(ComponentManagerTest, AddComponentTreeChangedCallback) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800583 int count = 0;
584 int count2 = 0;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800585 manager_.AddComponentTreeChangedCallback(base::Bind([&count]() { count++; }));
586 manager_.AddComponentTreeChangedCallback(
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800587 base::Bind([&count2]() { count2++; }));
588 EXPECT_EQ(1, count);
589 EXPECT_EQ(1, count2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800590 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800591 EXPECT_EQ(2, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800592 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800593 EXPECT_EQ(3, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800594 EXPECT_TRUE(manager_.AddComponent("comp1.comp2", "comp4", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800595 EXPECT_EQ(4, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800596 EXPECT_TRUE(manager_.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800597 EXPECT_EQ(5, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800598 EXPECT_TRUE(manager_.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800599 EXPECT_EQ(6, count);
Alex Vakulenkoce850b52016-01-04 09:27:50 -0800600 EXPECT_TRUE(manager_.RemoveComponentArrayItem("comp1", "comp3", 1, nullptr));
601 EXPECT_EQ(7, count);
602 EXPECT_TRUE(manager_.RemoveComponent("", "comp1", nullptr));
603 EXPECT_EQ(8, count);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800604 // Make sure both callbacks were called the same number of times.
605 EXPECT_EQ(count2, count);
606}
607
Vitaly Bukaece713e2015-12-09 10:59:33 -0800608TEST_F(ComponentManagerTest, FindComponent) {
609 CreateTestComponentTree(&manager_);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800610
Vitaly Bukaece713e2015-12-09 10:59:33 -0800611 const base::DictionaryValue* comp = manager_.FindComponent("comp1", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800612 ASSERT_NE(nullptr, comp);
613 EXPECT_TRUE(HasTrait(*comp, "t1"));
614
Vitaly Bukaece713e2015-12-09 10:59:33 -0800615 comp = manager_.FindComponent("comp1.comp2[0]", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800616 ASSERT_NE(nullptr, comp);
617 EXPECT_TRUE(HasTrait(*comp, "t2"));
618
Vitaly Bukaece713e2015-12-09 10:59:33 -0800619 comp = manager_.FindComponent("comp1.comp2[1]", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800620 ASSERT_NE(nullptr, comp);
621 EXPECT_TRUE(HasTrait(*comp, "t3"));
622
Vitaly Bukaece713e2015-12-09 10:59:33 -0800623 comp = manager_.FindComponent("comp1.comp2[1].comp3", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800624 ASSERT_NE(nullptr, comp);
625 EXPECT_TRUE(HasTrait(*comp, "t4"));
626
Vitaly Bukaece713e2015-12-09 10:59:33 -0800627 comp = manager_.FindComponent("comp1.comp2[1].comp3.comp4", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800628 ASSERT_NE(nullptr, comp);
629 EXPECT_TRUE(HasTrait(*comp, "t5"));
630
631 // Some whitespaces don't hurt.
Vitaly Bukaece713e2015-12-09 10:59:33 -0800632 comp = manager_.FindComponent(" comp1 . comp2 [ \t 1 ] . comp3.comp4 ",
633 nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800634 EXPECT_NE(nullptr, comp);
635
636 // Now check some failure cases.
637 ErrorPtr error;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800638 EXPECT_EQ(nullptr, manager_.FindComponent("", &error));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800639 EXPECT_NE(nullptr, error.get());
640 // 'comp2' doesn't exist:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800641 EXPECT_EQ(nullptr, manager_.FindComponent("comp2", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800642 // 'comp1.comp2' is an array, not a component:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800643 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800644 // 'comp1.comp2[3]' doesn't exist:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800645 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[3]", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800646 // Empty component names:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800647 EXPECT_EQ(nullptr, manager_.FindComponent(".comp2[1]", nullptr));
648 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.[1]", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800649 // Invalid array indices:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800650 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[s]", nullptr));
651 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[-2]", nullptr));
652 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[1e1]", nullptr));
653 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[1", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800654}
655
Vitaly Bukaece713e2015-12-09 10:59:33 -0800656TEST_F(ComponentManagerTest, ParseCommandInstance) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800657 const char kTraits[] = R"({
658 "trait1": {
659 "commands": {
660 "command1": { "minimalRole": "user" },
661 "command2": { "minimalRole": "viewer" }
662 }
663 },
664 "trait2": {
665 "commands": {
666 "command1": { "minimalRole": "manager" },
667 "command2": { "minimalRole": "owner" }
668 }
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800669 },
670 "trait3": {
671 "commands": {
672 "command1": { "minimalRole": "manager" },
673 "command2": { "minimalRole": "owner" }
674 }
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800675 }
676 })";
677 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800678 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
679 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
680 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait2"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800681
682 std::string id;
683 const char kCommand1[] = R"({
684 "name": "trait1.command1",
Alex Vakulenkob736c982015-12-05 14:09:27 -0800685 "id": "1234-12345",
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800686 "component": "comp1",
687 "parameters": {}
688 })";
689 auto command1 = CreateDictionaryValue(kCommand1);
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800690 EXPECT_NE(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800691 manager_.ParseCommandInstance(*command1, Command::Origin::kLocal,
692 UserRole::kUser, &id, nullptr)
693 .get());
Alex Vakulenkob736c982015-12-05 14:09:27 -0800694 EXPECT_EQ("1234-12345", id);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800695 // Not enough access rights
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800696 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800697 manager_.ParseCommandInstance(*command1, Command::Origin::kLocal,
698 UserRole::kViewer, &id, nullptr)
699 .get());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800700
701 const char kCommand2[] = R"({
702 "name": "trait1.command3",
703 "component": "comp1",
704 "parameters": {}
705 })";
706 auto command2 = CreateDictionaryValue(kCommand2);
707 // trait1.command3 doesn't exist
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800708 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800709 manager_.ParseCommandInstance(*command2, Command::Origin::kLocal,
710 UserRole::kOwner, &id, nullptr)
711 .get());
Alex Vakulenkob736c982015-12-05 14:09:27 -0800712 EXPECT_TRUE(id.empty());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800713
714 const char kCommand3[] = R"({
715 "name": "trait2.command1",
716 "component": "comp1",
717 "parameters": {}
718 })";
719 auto command3 = CreateDictionaryValue(kCommand3);
720 // Component comp1 doesn't have trait2.
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800721 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800722 manager_.ParseCommandInstance(*command3, Command::Origin::kLocal,
723 UserRole::kOwner, &id, nullptr)
724 .get());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800725
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800726 // No component specified, find the suitable component
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800727 const char kCommand4[] = R"({
728 "name": "trait1.command1",
729 "parameters": {}
730 })";
731 auto command4 = CreateDictionaryValue(kCommand4);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800732 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800733 *command4, Command::Origin::kLocal, UserRole::kOwner, &id, nullptr);
734 EXPECT_NE(nullptr, command_instance.get());
735 EXPECT_EQ("comp1", command_instance->GetComponent());
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800736
737 const char kCommand5[] = R"({
738 "name": "trait2.command1",
739 "parameters": {}
740 })";
741 auto command5 = CreateDictionaryValue(kCommand5);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800742 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800743 *command5, Command::Origin::kLocal, UserRole::kOwner, &id, nullptr);
744 EXPECT_NE(nullptr, command_instance.get());
745 EXPECT_EQ("comp2", command_instance->GetComponent());
746
747 // Cannot route the command, no component with 'trait3'.
748 const char kCommand6[] = R"({
749 "name": "trait3.command1",
750 "parameters": {}
751 })";
752 auto command6 = CreateDictionaryValue(kCommand6);
753 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800754 manager_.ParseCommandInstance(*command6, Command::Origin::kLocal,
755 UserRole::kOwner, &id, nullptr)
756 .get());
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800757}
758
Vitaly Bukaece713e2015-12-09 10:59:33 -0800759TEST_F(ComponentManagerTest, AddCommand) {
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800760 const char kTraits[] = R"({
761 "trait1": {
762 "commands": {
763 "command1": { "minimalRole": "user" }
764 }
765 }
766 })";
767 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800768 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
769 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800770
771 std::string id;
772 const char kCommand[] = R"({
773 "name": "trait1.command1",
774 "id": "1234-12345",
775 "component": "comp1",
776 "parameters": {}
777 })";
778 auto command = CreateDictionaryValue(kCommand);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800779 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800780 *command, Command::Origin::kLocal, UserRole::kUser, &id, nullptr);
781 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800782 manager_.AddCommand(std::move(command_instance));
783 const auto* queued_command = manager_.FindCommand(id);
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800784 ASSERT_NE(nullptr, queued_command);
785 EXPECT_EQ("trait1.command1", queued_command->GetName());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800786}
787
Vitaly Bukaece713e2015-12-09 10:59:33 -0800788TEST_F(ComponentManagerTest, AddCommandHandler) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800789 const char kTraits[] = R"({
790 "trait1": {
791 "commands": {
792 "command1": { "minimalRole": "user" }
793 }
794 },
795 "trait2": {
796 "commands": {
797 "command2": { "minimalRole": "user" }
798 }
799 }
800 })";
801 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800802 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
803 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
804 ASSERT_TRUE(
805 manager_.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800806
807 std::string last_tags;
808 auto handler = [&last_tags](int tag, const std::weak_ptr<Command>& command) {
809 if (!last_tags.empty())
810 last_tags += ',';
811 last_tags += std::to_string(tag);
812 };
813
Vitaly Bukaece713e2015-12-09 10:59:33 -0800814 manager_.AddCommandHandler("comp1", "trait1.command1",
815 base::Bind(handler, 1));
816 manager_.AddCommandHandler("comp2", "trait1.command1",
817 base::Bind(handler, 2));
818 manager_.AddCommandHandler("comp2", "trait2.command2",
819 base::Bind(handler, 3));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800820 EXPECT_TRUE(last_tags.empty());
821
822 const char kCommand1[] = R"({
823 "name": "trait1.command1",
824 "component": "comp1"
825 })";
826 auto command1 = CreateDictionaryValue(kCommand1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800827 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800828 *command1, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
829 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800830 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800831 EXPECT_EQ("1", last_tags);
832 last_tags.clear();
833
834 const char kCommand2[] = R"({
835 "name": "trait1.command1",
836 "component": "comp2"
837 })";
838 auto command2 = CreateDictionaryValue(kCommand2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800839 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800840 *command2, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
841 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800842 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800843 EXPECT_EQ("2", last_tags);
844 last_tags.clear();
845
846 const char kCommand3[] = R"({
847 "name": "trait2.command2",
848 "component": "comp2",
849 "parameters": {}
850 })";
851 auto command3 = CreateDictionaryValue(kCommand3);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800852 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800853 *command3, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
854 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800855 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800856 EXPECT_EQ("3", last_tags);
857 last_tags.clear();
858}
859
Vitaly Bukaece713e2015-12-09 10:59:33 -0800860TEST_F(ComponentManagerTest, AddDefaultCommandHandler) {
Alex Vakulenko20334332015-12-08 13:19:49 -0800861 const char kTraits[] = R"({
862 "trait1": {
863 "commands": {
864 "command1": { "minimalRole": "user" }
865 }
866 },
867 "trait2": {
868 "commands": {
869 "command2": { "minimalRole": "user" }
870 }
871 }
872 })";
873 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800874 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
875 ASSERT_TRUE(manager_.AddComponent("", "comp", {"trait1", "trait2"}, nullptr));
Alex Vakulenko20334332015-12-08 13:19:49 -0800876
877 int count = 0;
878 auto handler = [&count](int tag, const std::weak_ptr<Command>& command) {
879 count++;
880 };
881
Vitaly Bukaece713e2015-12-09 10:59:33 -0800882 manager_.AddCommandHandler("", "", base::Bind(handler, 1));
Alex Vakulenko20334332015-12-08 13:19:49 -0800883 EXPECT_EQ(0, count);
884
885 const char kCommand1[] = R"({
886 "name": "trait1.command1",
887 "component": "comp"
888 })";
889 auto command1 = CreateDictionaryValue(kCommand1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800890 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenko20334332015-12-08 13:19:49 -0800891 *command1, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
892 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800893 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko20334332015-12-08 13:19:49 -0800894 EXPECT_EQ(1, count);
895
896 const char kCommand2[] = R"({
897 "name": "trait2.command2",
898 "component": "comp"
899 })";
900 auto command2 = CreateDictionaryValue(kCommand2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800901 command_instance = manager_.ParseCommandInstance(
Alex Vakulenko20334332015-12-08 13:19:49 -0800902 *command2, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
903 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800904 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko20334332015-12-08 13:19:49 -0800905 EXPECT_EQ(2, count);
906}
907
Vitaly Bukaece713e2015-12-09 10:59:33 -0800908TEST_F(ComponentManagerTest, SetStateProperties) {
909 CreateTestComponentTree(&manager_);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800910
911 const char kState1[] = R"({"t1": {"p1": 0, "p2": "foo"}})";
912 auto state1 = CreateDictionaryValue(kState1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800913 ASSERT_TRUE(manager_.SetStateProperties("comp1", *state1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800914 const char kExpected1[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800915 "comp1": {
916 "traits": [ "t1" ],
917 "state": {"t1": {"p1": 0, "p2": "foo"}},
918 "components": {
919 "comp2": [
920 {
921 "traits": [ "t2" ]
922 },
923 {
924 "traits": [ "t3" ],
925 "components": {
926 "comp3": {
927 "traits": [ "t4" ],
928 "components": {
929 "comp4": {
930 "traits": [ "t5", "t6" ]
931 }
932 }
933 }
934 }
935 }
936 ]
937 }
938 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800939 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800940 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800941
942 const char kState2[] = R"({"t1": {"p1": {"bar": "baz"}}})";
943 auto state2 = CreateDictionaryValue(kState2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800944 ASSERT_TRUE(manager_.SetStateProperties("comp1", *state2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800945
946 const char kExpected2[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800947 "comp1": {
948 "traits": [ "t1" ],
949 "state": {"t1": {"p1": {"bar": "baz"}, "p2": "foo"}},
950 "components": {
951 "comp2": [
952 {
953 "traits": [ "t2" ]
954 },
955 {
956 "traits": [ "t3" ],
957 "components": {
958 "comp3": {
959 "traits": [ "t4" ],
960 "components": {
961 "comp4": {
962 "traits": [ "t5", "t6" ]
963 }
964 }
965 }
966 }
967 }
968 ]
969 }
970 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800971 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800972 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800973
974 const char kState3[] = R"({"t5": {"p1": 1}})";
975 auto state3 = CreateDictionaryValue(kState3);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800976 ASSERT_TRUE(manager_.SetStateProperties("comp1.comp2[1].comp3.comp4", *state3,
977 nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800978
979 const char kExpected3[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800980 "comp1": {
981 "traits": [ "t1" ],
982 "state": {"t1": {"p1": {"bar": "baz"}, "p2": "foo"}},
983 "components": {
984 "comp2": [
985 {
986 "traits": [ "t2" ]
987 },
988 {
989 "traits": [ "t3" ],
990 "components": {
991 "comp3": {
992 "traits": [ "t4" ],
993 "components": {
994 "comp4": {
995 "traits": [ "t5", "t6" ],
996 "state": { "t5": { "p1": 1 } }
997 }
998 }
999 }
1000 }
1001 }
1002 ]
1003 }
1004 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001005 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001006 EXPECT_JSON_EQ(kExpected3, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001007}
1008
Vitaly Bukaece713e2015-12-09 10:59:33 -08001009TEST_F(ComponentManagerTest, SetStatePropertiesFromJson) {
1010 CreateTestComponentTree(&manager_);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001011
Vitaly Bukaece713e2015-12-09 10:59:33 -08001012 ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
Vitaly Buka34668e72015-12-15 14:46:47 -08001013 "comp1.comp2[1].comp3.comp4",
1014 R"({"t5": {"p1": 3}, "t6": {"p2": 5}})", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001015
1016 const char kExpected[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001017 "comp1": {
1018 "traits": [ "t1" ],
1019 "components": {
1020 "comp2": [
1021 {
1022 "traits": [ "t2" ]
1023 },
1024 {
1025 "traits": [ "t3" ],
1026 "components": {
1027 "comp3": {
1028 "traits": [ "t4" ],
1029 "components": {
1030 "comp4": {
1031 "traits": [ "t5", "t6" ],
1032 "state": {
1033 "t5": { "p1": 3 },
1034 "t6": { "p2": 5 }
1035 }
1036 }
1037 }
1038 }
1039 }
1040 }
1041 ]
1042 }
1043 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001044 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001045 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001046}
1047
Vitaly Bukaece713e2015-12-09 10:59:33 -08001048TEST_F(ComponentManagerTest, SetGetStateProperty) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001049 const char kTraits[] = R"({
1050 "trait1": {
1051 "state": {
1052 "prop1": { "type": "string" },
1053 "prop2": { "type": "integer" }
1054 }
1055 },
1056 "trait2": {
1057 "state": {
1058 "prop3": { "type": "string" },
1059 "prop4": { "type": "string" }
1060 }
1061 }
1062 })";
1063 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001064 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1065 ASSERT_TRUE(
1066 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001067
1068 base::StringValue p1("foo");
Vitaly Bukaece713e2015-12-09 10:59:33 -08001069 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001070
1071 const char kExpected1[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001072 "comp1": {
1073 "traits": [ "trait1", "trait2" ],
1074 "state": {
1075 "trait1": { "prop1": "foo" }
1076 }
1077 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001078 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001079 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001080
1081 base::FundamentalValue p2(2);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001082 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait2.prop3", p2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001083
1084 const char kExpected2[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001085 "comp1": {
1086 "traits": [ "trait1", "trait2" ],
1087 "state": {
1088 "trait1": { "prop1": "foo" },
1089 "trait2": { "prop3": 2 }
1090 }
1091 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001092 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001093 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001094 // Just the package name without property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001095 EXPECT_FALSE(manager_.SetStateProperty("comp1", "trait2", p2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001096
Vitaly Bukaece713e2015-12-09 10:59:33 -08001097 const base::Value* value =
1098 manager_.GetStateProperty("comp1", "trait1.prop1", nullptr);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001099 ASSERT_NE(nullptr, value);
1100 EXPECT_TRUE(p1.Equals(value));
Vitaly Bukaece713e2015-12-09 10:59:33 -08001101 value = manager_.GetStateProperty("comp1", "trait2.prop3", nullptr);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001102 ASSERT_NE(nullptr, value);
1103 EXPECT_TRUE(p2.Equals(value));
1104
1105 // Non-existing property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001106 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp1", "trait2.p", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001107 // Non-existing component
Vitaly Bukaece713e2015-12-09 10:59:33 -08001108 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp2", "trait.prop", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001109 // Just the package name without property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001110 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp1", "trait2", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001111}
1112
Vitaly Bukaece713e2015-12-09 10:59:33 -08001113TEST_F(ComponentManagerTest, AddStateChangedCallback) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001114 const char kTraits[] = R"({
1115 "trait1": {
1116 "state": {
1117 "prop1": { "type": "string" },
1118 "prop2": { "type": "string" }
1119 }
1120 }
1121 })";
1122 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001123 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1124 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001125
1126 int count = 0;
1127 int count2 = 0;
Vitaly Bukaece713e2015-12-09 10:59:33 -08001128 manager_.AddStateChangedCallback(base::Bind([&count]() { count++; }));
1129 manager_.AddStateChangedCallback(base::Bind([&count2]() { count2++; }));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001130 EXPECT_EQ(1, count);
1131 EXPECT_EQ(1, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001132 EXPECT_EQ(0u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001133
1134 base::StringValue p1("foo");
Vitaly Bukaece713e2015-12-09 10:59:33 -08001135 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001136 EXPECT_EQ(2, count);
1137 EXPECT_EQ(2, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001138 EXPECT_EQ(1u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001139
Vitaly Bukaece713e2015-12-09 10:59:33 -08001140 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001141 EXPECT_EQ(3, count);
1142 EXPECT_EQ(3, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001143 EXPECT_EQ(2u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001144
1145 // Fail - no component.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001146 ASSERT_FALSE(manager_.SetStateProperty("comp2", "trait1.prop2", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001147 EXPECT_EQ(3, count);
1148 EXPECT_EQ(3, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001149 EXPECT_EQ(2u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001150}
1151
Vitaly Bukaece713e2015-12-09 10:59:33 -08001152TEST_F(ComponentManagerTest, ComponentStateUpdates) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001153 const char kTraits[] = R"({
1154 "trait1": {
1155 "state": {
1156 "prop1": { "type": "string" },
1157 "prop2": { "type": "string" }
1158 }
1159 },
1160 "trait2": {
1161 "state": {
1162 "prop3": { "type": "string" },
1163 "prop4": { "type": "string" }
1164 }
1165 }
1166 })";
1167 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001168 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1169 ASSERT_TRUE(
1170 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
1171 ASSERT_TRUE(
1172 manager_.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001173
1174 std::vector<ComponentManager::UpdateID> updates1;
1175 auto callback1 = [&updates1](ComponentManager::UpdateID id) {
1176 updates1.push_back(id);
1177 };
1178 // State change queue is empty, callback should be called immediately.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001179 auto token1 = manager_.AddServerStateUpdatedCallback(base::Bind(callback1));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001180 ASSERT_EQ(1u, updates1.size());
Vitaly Bukaece713e2015-12-09 10:59:33 -08001181 EXPECT_EQ(manager_.GetLastStateChangeId(), updates1.front());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001182 updates1.clear();
1183
1184 base::StringValue foo("foo");
1185 base::Time time1 = base::Time::Now();
Vitaly Bukaece713e2015-12-09 10:59:33 -08001186 EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(time1));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001187 // These three updates should be grouped into two separate state change queue
1188 // items, since they all happen at the same time, but for two different
1189 // components.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001190 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", foo, nullptr));
1191 ASSERT_TRUE(manager_.SetStateProperty("comp2", "trait2.prop3", foo, nullptr));
1192 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", foo, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001193
1194 std::vector<ComponentManager::UpdateID> updates2;
1195 auto callback2 = [&updates2](ComponentManager::UpdateID id) {
1196 updates2.push_back(id);
1197 };
1198 // State change queue is not empty, so callback will be called later.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001199 auto token2 = manager_.AddServerStateUpdatedCallback(base::Bind(callback2));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001200 EXPECT_TRUE(updates2.empty());
1201
1202 base::StringValue bar("bar");
1203 base::Time time2 = time1 + base::TimeDelta::FromSeconds(1);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001204 EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(time2));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001205 // Two more update events (as above) but at |time2|.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001206 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", bar, nullptr));
1207 ASSERT_TRUE(manager_.SetStateProperty("comp2", "trait2.prop3", bar, nullptr));
1208 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", bar, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001209
Vitaly Bukaece713e2015-12-09 10:59:33 -08001210 auto snapshot = manager_.GetAndClearRecordedStateChanges();
1211 EXPECT_EQ(manager_.GetLastStateChangeId(), snapshot.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001212 ASSERT_EQ(4u, snapshot.state_changes.size());
1213
1214 EXPECT_EQ("comp1", snapshot.state_changes[0].component);
1215 EXPECT_EQ(time1, snapshot.state_changes[0].timestamp);
1216 EXPECT_JSON_EQ(R"({"trait1":{"prop1":"foo","prop2":"foo"}})",
1217 *snapshot.state_changes[0].changed_properties);
1218
1219 EXPECT_EQ("comp2", snapshot.state_changes[1].component);
1220 EXPECT_EQ(time1, snapshot.state_changes[1].timestamp);
1221 EXPECT_JSON_EQ(R"({"trait2":{"prop3":"foo"}})",
1222 *snapshot.state_changes[1].changed_properties);
1223
1224 EXPECT_EQ("comp1", snapshot.state_changes[2].component);
1225 EXPECT_EQ(time2, snapshot.state_changes[2].timestamp);
1226 EXPECT_JSON_EQ(R"({"trait1":{"prop1":"bar","prop2":"bar"}})",
1227 *snapshot.state_changes[2].changed_properties);
1228
1229 EXPECT_EQ("comp2", snapshot.state_changes[3].component);
1230 EXPECT_EQ(time2, snapshot.state_changes[3].timestamp);
1231 EXPECT_JSON_EQ(R"({"trait2":{"prop3":"bar"}})",
1232 *snapshot.state_changes[3].changed_properties);
1233
1234 // Make sure previous GetAndClearRecordedStateChanges() clears the queue.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001235 auto snapshot2 = manager_.GetAndClearRecordedStateChanges();
1236 EXPECT_EQ(manager_.GetLastStateChangeId(), snapshot2.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001237 EXPECT_TRUE(snapshot2.state_changes.empty());
1238
1239 // Now indicate that we have update the changes on the server.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001240 manager_.NotifyStateUpdatedOnServer(snapshot.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001241 ASSERT_EQ(1u, updates1.size());
1242 EXPECT_EQ(snapshot.update_id, updates1.front());
1243 ASSERT_EQ(1u, updates2.size());
1244 EXPECT_EQ(snapshot.update_id, updates2.front());
1245}
1246
Vitaly Bukaece713e2015-12-09 10:59:33 -08001247TEST_F(ComponentManagerTest, FindComponentWithTrait) {
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001248 const char kTraits[] = R"({
1249 "trait1": {},
1250 "trait2": {},
1251 "trait3": {}
1252 })";
1253 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001254 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1255 ASSERT_TRUE(
1256 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
1257 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait3"}, nullptr));
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001258
Vitaly Bukaece713e2015-12-09 10:59:33 -08001259 EXPECT_EQ("comp1", manager_.FindComponentWithTrait("trait1"));
1260 EXPECT_EQ("comp1", manager_.FindComponentWithTrait("trait2"));
1261 EXPECT_EQ("comp2", manager_.FindComponentWithTrait("trait3"));
1262 EXPECT_EQ("", manager_.FindComponentWithTrait("trait4"));
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001263}
1264
Vitaly Bukaece713e2015-12-09 10:59:33 -08001265TEST_F(ComponentManagerTest, AddLegacyCommandAndStateDefinitions) {
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001266 const char kCommandDefs1[] = R"({
1267 "package1": {
1268 "command1": {
1269 "minimalRole": "user",
1270 "parameters": {"height": {"type": "integer"}}
1271 },
1272 "command2": {
1273 "minimalRole": "owner",
1274 "parameters": {}
1275 }
1276 },
1277 "package2": {
1278 "command1": { "minimalRole": "user" },
1279 "command2": { "minimalRole": "owner" }
1280 }
1281 })";
1282 auto json = CreateDictionaryValue(kCommandDefs1);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001283 EXPECT_TRUE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001284 const char kExpected1[] = R"({
1285 "package1": {
1286 "commands": {
1287 "command1": {
1288 "minimalRole": "user",
1289 "parameters": {"height": {"type": "integer"}}
1290 },
1291 "command2": {
1292 "minimalRole": "owner",
1293 "parameters": {}
1294 }
1295 }
1296 },
1297 "package2": {
1298 "commands": {
1299 "command1": { "minimalRole": "user" },
1300 "command2": { "minimalRole": "owner" }
1301 }
1302 }
1303 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001304 EXPECT_JSON_EQ(kExpected1, manager_.GetTraits());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001305 const char kExpectedComponents1[] = R"({
1306 "__weave__": { "traits": ["package1", "package2"] }
1307 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001308 EXPECT_JSON_EQ(kExpectedComponents1, manager_.GetComponents());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001309
1310 const char kCommandDefs2[] = R"({
1311 "package2": {
1312 "command3": { "minimalRole": "user" }
1313 },
1314 "package3": {
1315 "command1": { "minimalRole": "user" },
1316 "command2": { "minimalRole": "owner" }
1317 }
1318 })";
1319 json = CreateDictionaryValue(kCommandDefs2);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001320 EXPECT_TRUE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001321 const char kExpected2[] = R"({
1322 "package1": {
1323 "commands": {
1324 "command1": {
1325 "minimalRole": "user",
1326 "parameters": {"height": {"type": "integer"}}
1327 },
1328 "command2": {
1329 "minimalRole": "owner",
1330 "parameters": {}
1331 }
1332 }
1333 },
1334 "package2": {
1335 "commands": {
1336 "command1": { "minimalRole": "user" },
1337 "command2": { "minimalRole": "owner" },
1338 "command3": { "minimalRole": "user" }
1339 }
1340 },
1341 "package3": {
1342 "commands": {
1343 "command1": { "minimalRole": "user" },
1344 "command2": { "minimalRole": "owner" }
1345 }
1346 }
1347 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001348 EXPECT_JSON_EQ(kExpected2, manager_.GetTraits());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001349 const char kExpectedComponents2[] = R"({
1350 "__weave__": { "traits": ["package1", "package2", "package3"] }
1351 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001352 EXPECT_JSON_EQ(kExpectedComponents2, manager_.GetComponents());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001353
1354 // Redefining existing commands.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001355 EXPECT_FALSE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001356
1357 const char kStateDefs1[] = R"({
1358 "package1": {
1359 "prop1": { "type": "string" },
1360 "prop2": { "type": "string" }
1361 },
1362 "package4": {
1363 "prop3": { "type": "string" },
1364 "prop4": { "type": "string" }
1365 }
1366 })";
1367 json = CreateDictionaryValue(kStateDefs1);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001368 EXPECT_TRUE(manager_.AddLegacyStateDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001369 const char kExpectedComponents3[] = R"({
1370 "__weave__": { "traits": ["package1", "package2", "package3", "package4"] }
1371 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001372 EXPECT_JSON_EQ(kExpectedComponents3, manager_.GetComponents());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001373
1374 const char kExpected3[] = R"({
1375 "package1": {
1376 "commands": {
1377 "command1": {
1378 "minimalRole": "user",
1379 "parameters": {"height": {"type": "integer"}}
1380 },
1381 "command2": {
1382 "minimalRole": "owner",
1383 "parameters": {}
1384 }
1385 },
1386 "state": {
1387 "prop1": { "type": "string" },
1388 "prop2": { "type": "string" }
1389 }
1390 },
1391 "package2": {
1392 "commands": {
1393 "command1": { "minimalRole": "user" },
1394 "command2": { "minimalRole": "owner" },
1395 "command3": { "minimalRole": "user" }
1396 }
1397 },
1398 "package3": {
1399 "commands": {
1400 "command1": { "minimalRole": "user" },
1401 "command2": { "minimalRole": "owner" }
1402 }
1403 },
1404 "package4": {
1405 "state": {
1406 "prop3": { "type": "string" },
1407 "prop4": { "type": "string" }
1408 }
1409 }
1410 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001411 EXPECT_JSON_EQ(kExpected3, manager_.GetTraits());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001412 const char kExpectedComponents4[] = R"({
1413 "__weave__": { "traits": ["package1", "package2", "package3", "package4"] }
1414 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001415 EXPECT_JSON_EQ(kExpectedComponents4, manager_.GetComponents());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001416
1417 // Redefining existing commands.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001418 EXPECT_FALSE(manager_.AddLegacyStateDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001419
1420 const char kExpected4[] = R"({
1421 "package1": {
1422 "command1": {
1423 "minimalRole": "user",
1424 "parameters": {"height": {"type": "integer"}}
1425 },
1426 "command2": {
1427 "minimalRole": "owner",
1428 "parameters": {}
1429 }
1430 },
1431 "package2": {
1432 "command1": { "minimalRole": "user" },
1433 "command2": { "minimalRole": "owner" },
1434 "command3": { "minimalRole": "user" }
1435 },
1436 "package3": {
1437 "command1": { "minimalRole": "user" },
1438 "command2": { "minimalRole": "owner" }
1439 }
1440 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001441 EXPECT_JSON_EQ(kExpected4, manager_.GetLegacyCommandDefinitions());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001442}
1443
Vitaly Bukaece713e2015-12-09 10:59:33 -08001444TEST_F(ComponentManagerTest, GetLegacyState) {
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001445 const char kTraits[] = R"({
1446 "trait1": {
1447 "state": {
1448 "prop1": { "type": "string" },
1449 "prop2": { "type": "string" }
1450 }
1451 },
1452 "trait2": {
1453 "state": {
1454 "prop3": { "type": "string" },
1455 "prop4": { "type": "string" }
1456 }
1457 }
1458 })";
1459 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001460 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1461 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
1462 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait2"}, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001463
Vitaly Bukaece713e2015-12-09 10:59:33 -08001464 ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001465 "comp1", R"({"trait1": {"prop1": "foo", "prop2": "bar"}})", nullptr));
Vitaly Bukaece713e2015-12-09 10:59:33 -08001466 ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001467 "comp2", R"({"trait2": {"prop3": "baz", "prop4": "quux"}})", nullptr));
1468
1469 const char kExpected[] = R"({
1470 "trait1": {
1471 "prop1": "foo",
1472 "prop2": "bar"
1473 },
1474 "trait2": {
1475 "prop3": "baz",
1476 "prop4": "quux"
1477 }
1478 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001479 EXPECT_JSON_EQ(kExpected, manager_.GetLegacyState());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001480}
1481
Vitaly Bukaece713e2015-12-09 10:59:33 -08001482TEST_F(ComponentManagerTest, TestMockComponentManager) {
Alex Vakulenkoba981152015-12-05 13:58:22 -08001483 // Check that all the virtual methods are mocked out.
1484 MockComponentManager mock;
1485}
1486
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -08001487} // namespace weave