blob: 8c9b38652ce3068e7ff40e81533c5d002cfeb114 [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>
10#include <weave/test/unittest_utils.h>
11
12#include "src/bind_lambda.h"
13#include "src/commands/schema_constants.h"
Alex Vakulenkoba981152015-12-05 13:58:22 -080014#include "src/mock_component_manager.h"
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080015
16namespace weave {
17
18using test::CreateDictionaryValue;
19
20namespace {
21
22bool HasTrait(const base::DictionaryValue& comp, const std::string& trait) {
23 const base::ListValue* list = nullptr;
24 if (!comp.GetList("traits", &list))
25 return false;
26 for (const base::Value* item : *list) {
27 std::string value;
28 if (item->GetAsString(&value) && value == trait)
29 return true;
30 }
31 return false;
32}
33
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080034// Creates sample trait/component trees:
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -080035// {
36// "traits": {
37// "t1": {},
38// "t2": {},
39// "t3": {},
40// "t4": {},
41// "t5": {},
42// "t6": {},
43// },
44// "components": {
45// "comp1": {
46// "traits": [ "t1" ],
47// "components": {
48// "comp2": [
49// { "traits": [ "t2" ] },
50// {
51// "traits": [ "t3" ],
52// "components": {
53// "comp3": {
54// "traits": [ "t4" ],
55// "components": {
56// "comp4": {
57// "traits": [ "t5", "t6" ]
58// }
59// }
60// }
61// }
62// }
63// ],
64// }
65// }
66// }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080067// }
68void CreateTestComponentTree(ComponentManager* manager) {
69 const char kTraits[] = R"({"t1":{},"t2":{},"t3":{},"t4":{},"t5":{},"t6":{}})";
70 auto json = CreateDictionaryValue(kTraits);
71 ASSERT_TRUE(manager->LoadTraits(*json, nullptr));
72 EXPECT_TRUE(manager->AddComponent("", "comp1", {"t1"}, nullptr));
73 EXPECT_TRUE(manager->AddComponentArrayItem("comp1", "comp2", {"t2"},
74 nullptr));
75 EXPECT_TRUE(manager->AddComponentArrayItem("comp1", "comp2", {"t3"},
76 nullptr));
77 EXPECT_TRUE(manager->AddComponent("comp1.comp2[1]", "comp3", {"t4"},
78 nullptr));
79 EXPECT_TRUE(manager->AddComponent("comp1.comp2[1].comp3", "comp4",
80 {"t5", "t6"}, nullptr));
81}
82
83// Test clock class to record predefined time intervals.
84// Implementation from base/test/simple_test_clock.{h|cc}
85class SimpleTestClock : public base::Clock {
86 public:
87 base::Time Now() override { return now_; }
88
89 // Advances the clock by |delta|.
90 void Advance(base::TimeDelta delta) { now_ += delta; }
91
92 // Sets the clock to the given time.
93 void SetNow(base::Time now) { now_ = now; }
94
95 private:
96 base::Time now_;
97};
98
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080099} // anonymous namespace
100
101TEST(ComponentManager, Empty) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800102 ComponentManagerImpl manager;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800103 EXPECT_TRUE(manager.GetTraits().empty());
104 EXPECT_TRUE(manager.GetComponents().empty());
105}
106
107TEST(ComponentManager, LoadTraits) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800108 ComponentManagerImpl manager;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800109 const char kTraits[] = R"({
110 "trait1": {
111 "commands": {
112 "command1": {
113 "minimalRole": "user",
114 "parameters": {"height": {"type": "integer"}}
115 }
116 },
117 "state": {
118 "property1": {"type": "boolean"}
119 }
120 },
121 "trait2": {
122 "state": {
123 "property2": {"type": "string"}
124 }
125 }
126 })";
127 auto json = CreateDictionaryValue(kTraits);
128 EXPECT_TRUE(manager.LoadTraits(*json, nullptr));
129 EXPECT_JSON_EQ(kTraits, manager.GetTraits());
130 EXPECT_TRUE(manager.GetComponents().empty());
131}
132
133TEST(ComponentManager, LoadTraitsDuplicateIdentical) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800134 ComponentManagerImpl manager;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800135 const char kTraits1[] = R"({
136 "trait1": {
137 "commands": {
138 "command1": {
139 "minimalRole": "user",
140 "parameters": {"height": {"type": "integer"}}
141 }
142 },
143 "state": {
144 "property1": {"type": "boolean"}
145 }
146 },
147 "trait2": {
148 "state": {
149 "property2": {"type": "string"}
150 }
151 }
152 })";
153 auto json = CreateDictionaryValue(kTraits1);
154 EXPECT_TRUE(manager.LoadTraits(*json, nullptr));
155 const char kTraits2[] = R"({
156 "trait1": {
157 "commands": {
158 "command1": {
159 "minimalRole": "user",
160 "parameters": {"height": {"type": "integer"}}
161 }
162 },
163 "state": {
164 "property1": {"type": "boolean"}
165 }
166 },
167 "trait3": {
168 "state": {
169 "property3": {"type": "string"}
170 }
171 }
172 })";
173 json = CreateDictionaryValue(kTraits2);
174 EXPECT_TRUE(manager.LoadTraits(*json, nullptr));
175 const char kExpected[] = R"({
176 "trait1": {
177 "commands": {
178 "command1": {
179 "minimalRole": "user",
180 "parameters": {"height": {"type": "integer"}}
181 }
182 },
183 "state": {
184 "property1": {"type": "boolean"}
185 }
186 },
187 "trait2": {
188 "state": {
189 "property2": {"type": "string"}
190 }
191 },
192 "trait3": {
193 "state": {
194 "property3": {"type": "string"}
195 }
196 }
197 })";
198 EXPECT_JSON_EQ(kExpected, manager.GetTraits());
199}
200
201TEST(ComponentManager, LoadTraitsDuplicateOverride) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800202 ComponentManagerImpl manager;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800203 const char kTraits1[] = R"({
204 "trait1": {
205 "commands": {
206 "command1": {
207 "minimalRole": "user",
208 "parameters": {"height": {"type": "integer"}}
209 }
210 },
211 "state": {
212 "property1": {"type": "boolean"}
213 }
214 },
215 "trait2": {
216 "state": {
217 "property2": {"type": "string"}
218 }
219 }
220 })";
221 auto json = CreateDictionaryValue(kTraits1);
222 EXPECT_TRUE(manager.LoadTraits(*json, nullptr));
223 const char kTraits2[] = R"({
224 "trait1": {
225 "commands": {
226 "command1": {
227 "minimalRole": "user",
228 "parameters": {"height": {"type": "string"}}
229 }
230 },
231 "state": {
232 "property1": {"type": "boolean"}
233 }
234 },
235 "trait3": {
236 "state": {
237 "property3": {"type": "string"}
238 }
239 }
240 })";
241 json = CreateDictionaryValue(kTraits2);
242 EXPECT_FALSE(manager.LoadTraits(*json, nullptr));
243}
244
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800245TEST(ComponentManager, AddTraitDefChangedCallback) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800246 ComponentManagerImpl manager;
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800247 int count = 0;
248 int count2 = 0;
249 manager.AddTraitDefChangedCallback(base::Bind([&count]() { count++; }));
250 manager.AddTraitDefChangedCallback(base::Bind([&count2]() { count2++; }));
251 EXPECT_EQ(1, count);
252 EXPECT_EQ(1, count2);
253 // New definitions.
254 const char kTraits1[] = R"({
255 "trait1": {
256 "state": {
257 "property1": {"type": "boolean"}
258 }
259 },
260 "trait2": {
261 "state": {
262 "property2": {"type": "string"}
263 }
264 }
265 })";
266 auto json = CreateDictionaryValue(kTraits1);
267 EXPECT_TRUE(manager.LoadTraits(*json, nullptr));
268 EXPECT_EQ(2, count);
269 // Duplicate definition, shouldn't call the callback.
270 const char kTraits2[] = R"({
271 "trait1": {
272 "state": {
273 "property1": {"type": "boolean"}
274 }
275 }
276 })";
277 json = CreateDictionaryValue(kTraits2);
278 EXPECT_TRUE(manager.LoadTraits(*json, nullptr));
279 EXPECT_EQ(2, count);
280 // New definition, should call the callback now.
281 const char kTraits3[] = R"({
282 "trait3": {
283 "state": {
284 "property3": {"type": "string"}
285 }
286 }
287 })";
288 json = CreateDictionaryValue(kTraits3);
289 EXPECT_TRUE(manager.LoadTraits(*json, nullptr));
290 EXPECT_EQ(3, count);
291 // Wrong definition, shouldn't call the callback.
292 const char kTraits4[] = R"({
293 "trait4": "foo"
294 })";
295 json = CreateDictionaryValue(kTraits4);
296 EXPECT_FALSE(manager.LoadTraits(*json, nullptr));
297 EXPECT_EQ(3, count);
298 // Make sure both callbacks were called the same number of times.
299 EXPECT_EQ(count2, count);
300}
301
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800302TEST(ComponentManager, LoadTraitsNotAnObject) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800303 ComponentManagerImpl manager;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800304 const char kTraits1[] = R"({"trait1": 0})";
305 auto json = CreateDictionaryValue(kTraits1);
306 ErrorPtr error;
307 EXPECT_FALSE(manager.LoadTraits(*json, &error));
308 EXPECT_EQ(errors::commands::kTypeMismatch, error->GetCode());
309}
310
311TEST(ComponentManager, FindTraitDefinition) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800312 ComponentManagerImpl manager;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800313 const char kTraits[] = R"({
314 "trait1": {
315 "commands": {
316 "command1": {
317 "minimalRole": "user",
318 "parameters": {"height": {"type": "integer"}}
319 }
320 },
321 "state": {
322 "property1": {"type": "boolean"}
323 }
324 },
325 "trait2": {
326 "state": {
327 "property2": {"type": "string"}
328 }
329 }
330 })";
331 auto json = CreateDictionaryValue(kTraits);
332 ASSERT_TRUE(manager.LoadTraits(*json, nullptr));
333
334 const base::DictionaryValue* trait = manager.FindTraitDefinition("trait1");
335 ASSERT_NE(nullptr, trait);
336 const char kExpected1[] = R"({
337 "commands": {
338 "command1": {
339 "minimalRole": "user",
340 "parameters": {"height": {"type": "integer"}}
341 }
342 },
343 "state": {
344 "property1": {"type": "boolean"}
345 }
346 })";
347 EXPECT_JSON_EQ(kExpected1, *trait);
348
349 trait = manager.FindTraitDefinition("trait2");
350 ASSERT_NE(nullptr, trait);
351 const char kExpected2[] = R"({
352 "state": {
353 "property2": {"type": "string"}
354 }
355 })";
356 EXPECT_JSON_EQ(kExpected2, *trait);
357
358 EXPECT_EQ(nullptr, manager.FindTraitDefinition("trait3"));
359}
360
361TEST(ComponentManager, FindCommandDefinition) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800362 ComponentManagerImpl manager;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800363 const char kTraits[] = R"({
364 "trait1": {
365 "commands": {
366 "command1": {
367 "minimalRole": "user",
368 "parameters": {"height": {"type": "integer"}}
369 }
370 }
371 },
372 "trait2": {
373 "commands": {
374 "command1": {
375 "minimalRole": "manager"
376 },
377 "command2": {
378 "minimalRole": "owner"
379 }
380 }
381 }
382 })";
383 auto json = CreateDictionaryValue(kTraits);
384 ASSERT_TRUE(manager.LoadTraits(*json, nullptr));
385
386 const auto* cmd_def = manager.FindCommandDefinition("trait1.command1");
387 ASSERT_NE(nullptr, cmd_def);
388 const char kExpected1[] = R"({
389 "minimalRole": "user",
390 "parameters": {"height": {"type": "integer"}}
391 })";
392 EXPECT_JSON_EQ(kExpected1, *cmd_def);
393
394 cmd_def = manager.FindCommandDefinition("trait2.command1");
395 ASSERT_NE(nullptr, cmd_def);
396 const char kExpected2[] = R"({
397 "minimalRole": "manager"
398 })";
399 EXPECT_JSON_EQ(kExpected2, *cmd_def);
400
401 cmd_def = manager.FindCommandDefinition("trait2.command2");
402 ASSERT_NE(nullptr, cmd_def);
403 const char kExpected3[] = R"({
404 "minimalRole": "owner"
405 })";
406 EXPECT_JSON_EQ(kExpected3, *cmd_def);
407
408 EXPECT_EQ(nullptr, manager.FindTraitDefinition("trait1.command2"));
409 EXPECT_EQ(nullptr, manager.FindTraitDefinition("trait3.command1"));
410 EXPECT_EQ(nullptr, manager.FindTraitDefinition("trait"));
411 EXPECT_EQ(nullptr, manager.FindTraitDefinition("trait1.command1.parameters"));
412}
413
414TEST(ComponentManager, GetMinimalRole) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800415 ComponentManagerImpl manager;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800416 const char kTraits[] = R"({
417 "trait1": {
418 "commands": {
419 "command1": { "minimalRole": "user" },
420 "command2": { "minimalRole": "viewer" }
421 }
422 },
423 "trait2": {
424 "commands": {
425 "command1": { "minimalRole": "manager" },
426 "command2": { "minimalRole": "owner" }
427 }
428 }
429 })";
430 auto json = CreateDictionaryValue(kTraits);
431 ASSERT_TRUE(manager.LoadTraits(*json, nullptr));
432
433 UserRole role;
434 ASSERT_TRUE(manager.GetMinimalRole("trait1.command1", &role, nullptr));
435 EXPECT_EQ(UserRole::kUser, role);
436
437 ASSERT_TRUE(manager.GetMinimalRole("trait1.command2", &role, nullptr));
438 EXPECT_EQ(UserRole::kViewer, role);
439
440 ASSERT_TRUE(manager.GetMinimalRole("trait2.command1", &role, nullptr));
441 EXPECT_EQ(UserRole::kManager, role);
442
443 ASSERT_TRUE(manager.GetMinimalRole("trait2.command2", &role, nullptr));
444 EXPECT_EQ(UserRole::kOwner, role);
445
446 EXPECT_FALSE(manager.GetMinimalRole("trait1.command3", &role, nullptr));
447}
448
449TEST(ComponentManager, AddComponent) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800450 ComponentManagerImpl manager;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800451 const char kTraits[] = R"({"trait1": {}, "trait2": {}, "trait3": {}})";
452 auto json = CreateDictionaryValue(kTraits);
453 ASSERT_TRUE(manager.LoadTraits(*json, nullptr));
454 EXPECT_TRUE(manager.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
455 EXPECT_TRUE(manager.AddComponent("", "comp2", {"trait3"}, nullptr));
456 const char kExpected[] = R"({
457 "comp1": {
458 "traits": ["trait1", "trait2"]
459 },
460 "comp2": {
461 "traits": ["trait3"]
462 }
463 })";
464 EXPECT_JSON_EQ(kExpected, manager.GetComponents());
465
466 // 'trait4' is undefined, so can't add a component referring to it.
467 EXPECT_FALSE(manager.AddComponent("", "comp3", {"trait4"}, nullptr));
468}
469
470TEST(ComponentManager, AddSubComponent) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800471 ComponentManagerImpl manager;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800472 EXPECT_TRUE(manager.AddComponent("", "comp1", {}, nullptr));
473 EXPECT_TRUE(manager.AddComponent("comp1", "comp2", {}, nullptr));
474 EXPECT_TRUE(manager.AddComponent("comp1", "comp3", {}, nullptr));
475 EXPECT_TRUE(manager.AddComponent("comp1.comp2", "comp4", {}, nullptr));
476 const char kExpected[] = R"({
477 "comp1": {
478 "traits": [],
479 "components": {
480 "comp2": {
481 "traits": [],
482 "components": {
483 "comp4": {
484 "traits": []
485 }
486 }
487 },
488 "comp3": {
489 "traits": []
490 }
491 }
492 }
493 })";
494 EXPECT_JSON_EQ(kExpected, manager.GetComponents());
495}
496
497TEST(ComponentManager, AddComponentArrayItem) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800498 ComponentManagerImpl manager;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800499 const char kTraits[] = R"({"foo": {}, "bar": {}})";
500 auto json = CreateDictionaryValue(kTraits);
501 ASSERT_TRUE(manager.LoadTraits(*json, nullptr));
502
503 EXPECT_TRUE(manager.AddComponent("", "comp1", {}, nullptr));
504 EXPECT_TRUE(manager.AddComponentArrayItem("comp1", "comp2", {"foo"},
505 nullptr));
506 EXPECT_TRUE(manager.AddComponentArrayItem("comp1", "comp2", {"bar"},
507 nullptr));
508 EXPECT_TRUE(manager.AddComponent("comp1.comp2[1]", "comp3", {}, nullptr));
509 EXPECT_TRUE(manager.AddComponent("comp1.comp2[1].comp3", "comp4", {},
510 nullptr));
511 const char kExpected[] = R"({
512 "comp1": {
513 "traits": [],
514 "components": {
515 "comp2": [
516 {
517 "traits": ["foo"]
518 },
519 {
520 "traits": ["bar"],
521 "components": {
522 "comp3": {
523 "traits": [],
524 "components": {
525 "comp4": {
526 "traits": []
527 }
528 }
529 }
530 }
531 }
532 ]
533 }
534 }
535 })";
536 EXPECT_JSON_EQ(kExpected, manager.GetComponents());
537}
538
539TEST(ComponentManager, AddComponentExist) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800540 ComponentManagerImpl manager;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800541 EXPECT_TRUE(manager.AddComponent("", "comp1", {}, nullptr));
542 EXPECT_FALSE(manager.AddComponent("", "comp1", {}, nullptr));
543 EXPECT_TRUE(manager.AddComponent("comp1", "comp2", {}, nullptr));
544 EXPECT_FALSE(manager.AddComponent("comp1", "comp2", {}, nullptr));
545}
546
547TEST(ComponentManager, AddComponentDoesNotExist) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800548 ComponentManagerImpl manager;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800549 EXPECT_FALSE(manager.AddComponent("comp1", "comp2", {}, nullptr));
550}
551
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800552TEST(ComponentManager, AddComponentTreeChangedCallback) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800553 ComponentManagerImpl manager;
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800554 int count = 0;
555 int count2 = 0;
556 manager.AddComponentTreeChangedCallback(base::Bind([&count]() { count++; }));
557 manager.AddComponentTreeChangedCallback(
558 base::Bind([&count2]() { count2++; }));
559 EXPECT_EQ(1, count);
560 EXPECT_EQ(1, count2);
561 EXPECT_TRUE(manager.AddComponent("", "comp1", {}, nullptr));
562 EXPECT_EQ(2, count);
563 EXPECT_TRUE(manager.AddComponent("comp1", "comp2", {}, nullptr));
564 EXPECT_EQ(3, count);
565 EXPECT_TRUE(manager.AddComponent("comp1.comp2", "comp4", {}, nullptr));
566 EXPECT_EQ(4, count);
567 EXPECT_TRUE(manager.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
568 EXPECT_EQ(5, count);
569 EXPECT_TRUE(manager.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
570 EXPECT_EQ(6, count);
571 // Make sure both callbacks were called the same number of times.
572 EXPECT_EQ(count2, count);
573}
574
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800575TEST(ComponentManager, FindComponent) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800576 ComponentManagerImpl manager;
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800577 CreateTestComponentTree(&manager);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800578
579 const base::DictionaryValue* comp = manager.FindComponent("comp1", nullptr);
580 ASSERT_NE(nullptr, comp);
581 EXPECT_TRUE(HasTrait(*comp, "t1"));
582
583 comp = manager.FindComponent("comp1.comp2[0]", nullptr);
584 ASSERT_NE(nullptr, comp);
585 EXPECT_TRUE(HasTrait(*comp, "t2"));
586
587 comp = manager.FindComponent("comp1.comp2[1]", nullptr);
588 ASSERT_NE(nullptr, comp);
589 EXPECT_TRUE(HasTrait(*comp, "t3"));
590
591 comp = manager.FindComponent("comp1.comp2[1].comp3", nullptr);
592 ASSERT_NE(nullptr, comp);
593 EXPECT_TRUE(HasTrait(*comp, "t4"));
594
595 comp = manager.FindComponent("comp1.comp2[1].comp3.comp4", nullptr);
596 ASSERT_NE(nullptr, comp);
597 EXPECT_TRUE(HasTrait(*comp, "t5"));
598
599 // Some whitespaces don't hurt.
600 comp = manager.FindComponent(" comp1 . comp2 [ \t 1 ] . comp3.comp4 ",
601 nullptr);
602 EXPECT_NE(nullptr, comp);
603
604 // Now check some failure cases.
605 ErrorPtr error;
606 EXPECT_EQ(nullptr, manager.FindComponent("", &error));
607 EXPECT_NE(nullptr, error.get());
608 // 'comp2' doesn't exist:
609 EXPECT_EQ(nullptr, manager.FindComponent("comp2", nullptr));
610 // 'comp1.comp2' is an array, not a component:
611 EXPECT_EQ(nullptr, manager.FindComponent("comp1.comp2", nullptr));
612 // 'comp1.comp2[3]' doesn't exist:
613 EXPECT_EQ(nullptr, manager.FindComponent("comp1.comp2[3]", nullptr));
614 // Empty component names:
615 EXPECT_EQ(nullptr, manager.FindComponent(".comp2[1]", nullptr));
616 EXPECT_EQ(nullptr, manager.FindComponent("comp1.[1]", nullptr));
617 // Invalid array indices:
618 EXPECT_EQ(nullptr, manager.FindComponent("comp1.comp2[s]", nullptr));
619 EXPECT_EQ(nullptr, manager.FindComponent("comp1.comp2[-2]", nullptr));
620 EXPECT_EQ(nullptr, manager.FindComponent("comp1.comp2[1e1]", nullptr));
621 EXPECT_EQ(nullptr, manager.FindComponent("comp1.comp2[1", nullptr));
622}
623
624TEST(ComponentManager, AddCommand) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800625 ComponentManagerImpl manager;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800626 const char kTraits[] = R"({
627 "trait1": {
628 "commands": {
629 "command1": { "minimalRole": "user" },
630 "command2": { "minimalRole": "viewer" }
631 }
632 },
633 "trait2": {
634 "commands": {
635 "command1": { "minimalRole": "manager" },
636 "command2": { "minimalRole": "owner" }
637 }
638 }
639 })";
640 auto traits = CreateDictionaryValue(kTraits);
641 ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
642 ASSERT_TRUE(manager.AddComponent("", "comp1", {"trait1"}, nullptr));
643 ASSERT_TRUE(manager.AddComponent("", "comp2", {"trait2"}, nullptr));
644
645 std::string id;
646 const char kCommand1[] = R"({
647 "name": "trait1.command1",
Alex Vakulenkob736c982015-12-05 14:09:27 -0800648 "id": "1234-12345",
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800649 "component": "comp1",
650 "parameters": {}
651 })";
652 auto command1 = CreateDictionaryValue(kCommand1);
Alex Vakulenkob736c982015-12-05 14:09:27 -0800653 EXPECT_TRUE(manager.AddCommand(*command1, Command::Origin::kLocal,
654 UserRole::kUser, &id, nullptr));
655 EXPECT_EQ("1234-12345", id);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800656 // Not enough access rights
Alex Vakulenkob736c982015-12-05 14:09:27 -0800657 EXPECT_FALSE(manager.AddCommand(*command1, Command::Origin::kLocal,
658 UserRole::kViewer, &id, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800659
660 const char kCommand2[] = R"({
661 "name": "trait1.command3",
662 "component": "comp1",
663 "parameters": {}
664 })";
665 auto command2 = CreateDictionaryValue(kCommand2);
666 // trait1.command3 doesn't exist
Alex Vakulenkob736c982015-12-05 14:09:27 -0800667 EXPECT_FALSE(manager.AddCommand(*command2, Command::Origin::kLocal,
668 UserRole::kOwner, &id, nullptr));
669 EXPECT_TRUE(id.empty());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800670
671 const char kCommand3[] = R"({
672 "name": "trait2.command1",
673 "component": "comp1",
674 "parameters": {}
675 })";
676 auto command3 = CreateDictionaryValue(kCommand3);
677 // Component comp1 doesn't have trait2.
Alex Vakulenkob736c982015-12-05 14:09:27 -0800678 EXPECT_FALSE(manager.AddCommand(*command3, Command::Origin::kLocal,
679 UserRole::kOwner, &id, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800680
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800681 // No component specified, find the suitable component
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800682 const char kCommand4[] = R"({
683 "name": "trait1.command1",
684 "parameters": {}
685 })";
686 auto command4 = CreateDictionaryValue(kCommand4);
Alex Vakulenkob736c982015-12-05 14:09:27 -0800687 EXPECT_TRUE(manager.AddCommand(*command4, Command::Origin::kLocal,
688 UserRole::kOwner, &id, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800689 auto cmd = manager.FindCommand(id);
690 ASSERT_NE(nullptr, cmd);
691 EXPECT_EQ("comp1", cmd->GetComponent());
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800692
693 const char kCommand5[] = R"({
694 "name": "trait2.command1",
695 "parameters": {}
696 })";
697 auto command5 = CreateDictionaryValue(kCommand5);
Alex Vakulenkob736c982015-12-05 14:09:27 -0800698 EXPECT_TRUE(manager.AddCommand(*command5, Command::Origin::kLocal,
699 UserRole::kOwner, &id, nullptr));
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800700 cmd = manager.FindCommand(id);
701 ASSERT_NE(nullptr, cmd);
702 EXPECT_EQ("comp2", cmd->GetComponent());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800703}
704
705TEST(ComponentManager, AddCommandHandler) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800706 ComponentManagerImpl manager;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800707 const char kTraits[] = R"({
708 "trait1": {
709 "commands": {
710 "command1": { "minimalRole": "user" }
711 }
712 },
713 "trait2": {
714 "commands": {
715 "command2": { "minimalRole": "user" }
716 }
717 }
718 })";
719 auto traits = CreateDictionaryValue(kTraits);
720 ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
721 ASSERT_TRUE(manager.AddComponent("", "comp1", {"trait1"}, nullptr));
722 ASSERT_TRUE(manager.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
723
724 std::string last_tags;
725 auto handler = [&last_tags](int tag, const std::weak_ptr<Command>& command) {
726 if (!last_tags.empty())
727 last_tags += ',';
728 last_tags += std::to_string(tag);
729 };
730
731 manager.AddCommandHandler("comp1", "trait1.command1", base::Bind(handler, 1));
732 manager.AddCommandHandler("comp2", "trait1.command1", base::Bind(handler, 2));
733 manager.AddCommandHandler("comp2", "trait2.command2", base::Bind(handler, 3));
734 EXPECT_TRUE(last_tags.empty());
735
736 const char kCommand1[] = R"({
737 "name": "trait1.command1",
738 "component": "comp1"
739 })";
740 auto command1 = CreateDictionaryValue(kCommand1);
Alex Vakulenkob736c982015-12-05 14:09:27 -0800741 EXPECT_TRUE(manager.AddCommand(*command1, Command::Origin::kCloud,
742 UserRole::kUser, nullptr, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800743 EXPECT_EQ("1", last_tags);
744 last_tags.clear();
745
746 const char kCommand2[] = R"({
747 "name": "trait1.command1",
748 "component": "comp2"
749 })";
750 auto command2 = CreateDictionaryValue(kCommand2);
Alex Vakulenkob736c982015-12-05 14:09:27 -0800751 EXPECT_TRUE(manager.AddCommand(*command2, Command::Origin::kCloud,
752 UserRole::kUser, nullptr, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800753 EXPECT_EQ("2", last_tags);
754 last_tags.clear();
755
756 const char kCommand3[] = R"({
757 "name": "trait2.command2",
758 "component": "comp2",
759 "parameters": {}
760 })";
761 auto command3 = CreateDictionaryValue(kCommand3);
Alex Vakulenkob736c982015-12-05 14:09:27 -0800762 EXPECT_TRUE(manager.AddCommand(*command3, Command::Origin::kLocal,
763 UserRole::kUser, nullptr, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800764 EXPECT_EQ("3", last_tags);
765 last_tags.clear();
766}
767
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800768TEST(ComponentManager, SetStateProperties) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800769 ComponentManagerImpl manager;
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800770 CreateTestComponentTree(&manager);
771
772 const char kState1[] = R"({"t1": {"p1": 0, "p2": "foo"}})";
773 auto state1 = CreateDictionaryValue(kState1);
774 ASSERT_TRUE(manager.SetStateProperties("comp1", *state1, nullptr));
775 const char kExpected1[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800776 "comp1": {
777 "traits": [ "t1" ],
778 "state": {"t1": {"p1": 0, "p2": "foo"}},
779 "components": {
780 "comp2": [
781 {
782 "traits": [ "t2" ]
783 },
784 {
785 "traits": [ "t3" ],
786 "components": {
787 "comp3": {
788 "traits": [ "t4" ],
789 "components": {
790 "comp4": {
791 "traits": [ "t5", "t6" ]
792 }
793 }
794 }
795 }
796 }
797 ]
798 }
799 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800800 })";
801 EXPECT_JSON_EQ(kExpected1, manager.GetComponents());
802
803 const char kState2[] = R"({"t1": {"p1": {"bar": "baz"}}})";
804 auto state2 = CreateDictionaryValue(kState2);
805 ASSERT_TRUE(manager.SetStateProperties("comp1", *state2, nullptr));
806
807 const char kExpected2[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800808 "comp1": {
809 "traits": [ "t1" ],
810 "state": {"t1": {"p1": {"bar": "baz"}, "p2": "foo"}},
811 "components": {
812 "comp2": [
813 {
814 "traits": [ "t2" ]
815 },
816 {
817 "traits": [ "t3" ],
818 "components": {
819 "comp3": {
820 "traits": [ "t4" ],
821 "components": {
822 "comp4": {
823 "traits": [ "t5", "t6" ]
824 }
825 }
826 }
827 }
828 }
829 ]
830 }
831 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800832 })";
833 EXPECT_JSON_EQ(kExpected2, manager.GetComponents());
834
835 const char kState3[] = R"({"t5": {"p1": 1}})";
836 auto state3 = CreateDictionaryValue(kState3);
837 ASSERT_TRUE(manager.SetStateProperties("comp1.comp2[1].comp3.comp4", *state3,
838 nullptr));
839
840 const char kExpected3[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800841 "comp1": {
842 "traits": [ "t1" ],
843 "state": {"t1": {"p1": {"bar": "baz"}, "p2": "foo"}},
844 "components": {
845 "comp2": [
846 {
847 "traits": [ "t2" ]
848 },
849 {
850 "traits": [ "t3" ],
851 "components": {
852 "comp3": {
853 "traits": [ "t4" ],
854 "components": {
855 "comp4": {
856 "traits": [ "t5", "t6" ],
857 "state": { "t5": { "p1": 1 } }
858 }
859 }
860 }
861 }
862 }
863 ]
864 }
865 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800866 })";
867 EXPECT_JSON_EQ(kExpected3, manager.GetComponents());
868}
869
870TEST(ComponentManager, SetStatePropertiesFromJson) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800871 ComponentManagerImpl manager;
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800872 CreateTestComponentTree(&manager);
873
874 ASSERT_TRUE(manager.SetStatePropertiesFromJson(
875 "comp1.comp2[1].comp3.comp4", R"({"t5": {"p1": 3}, "t6": {"p2": 5}})",
876 nullptr));
877
878 const char kExpected[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800879 "comp1": {
880 "traits": [ "t1" ],
881 "components": {
882 "comp2": [
883 {
884 "traits": [ "t2" ]
885 },
886 {
887 "traits": [ "t3" ],
888 "components": {
889 "comp3": {
890 "traits": [ "t4" ],
891 "components": {
892 "comp4": {
893 "traits": [ "t5", "t6" ],
894 "state": {
895 "t5": { "p1": 3 },
896 "t6": { "p2": 5 }
897 }
898 }
899 }
900 }
901 }
902 }
903 ]
904 }
905 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800906 })";
907 EXPECT_JSON_EQ(kExpected, manager.GetComponents());
908}
909
910TEST(ComponentManager, SetGetStateProperty) {
Alex Vakulenkoba981152015-12-05 13:58:22 -0800911 ComponentManagerImpl manager;
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800912 const char kTraits[] = R"({
913 "trait1": {
914 "state": {
915 "prop1": { "type": "string" },
916 "prop2": { "type": "integer" }
917 }
918 },
919 "trait2": {
920 "state": {
921 "prop3": { "type": "string" },
922 "prop4": { "type": "string" }
923 }
924 }
925 })";
926 auto traits = CreateDictionaryValue(kTraits);
927 ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
928 ASSERT_TRUE(manager.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
929
930 base::StringValue p1("foo");
931 ASSERT_TRUE(manager.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
932
933 const char kExpected1[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800934 "comp1": {
935 "traits": [ "trait1", "trait2" ],
936 "state": {
937 "trait1": { "prop1": "foo" }
938 }
939 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800940 })";
941 EXPECT_JSON_EQ(kExpected1, manager.GetComponents());
942
943 base::FundamentalValue p2(2);
944 ASSERT_TRUE(manager.SetStateProperty("comp1", "trait2.prop3", p2, nullptr));
945
946 const char kExpected2[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800947 "comp1": {
948 "traits": [ "trait1", "trait2" ],
949 "state": {
950 "trait1": { "prop1": "foo" },
951 "trait2": { "prop3": 2 }
952 }
953 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800954 })";
955 EXPECT_JSON_EQ(kExpected2, manager.GetComponents());
956 // Just the package name without property:
957 EXPECT_FALSE(manager.SetStateProperty("comp1", "trait2", p2, nullptr));
958
959 const base::Value* value = manager.GetStateProperty("comp1", "trait1.prop1",
960 nullptr);
961 ASSERT_NE(nullptr, value);
962 EXPECT_TRUE(p1.Equals(value));
963 value = manager.GetStateProperty("comp1", "trait2.prop3", nullptr);
964 ASSERT_NE(nullptr, value);
965 EXPECT_TRUE(p2.Equals(value));
966
967 // Non-existing property:
968 EXPECT_EQ(nullptr, manager.GetStateProperty("comp1", "trait2.p", nullptr));
969 // Non-existing component
970 EXPECT_EQ(nullptr, manager.GetStateProperty("comp2", "trait.prop", nullptr));
971 // Just the package name without property:
972 EXPECT_EQ(nullptr, manager.GetStateProperty("comp1", "trait2", nullptr));
973}
974
975TEST(ComponentManager, AddStateChangedCallback) {
976 SimpleTestClock clock;
Alex Vakulenkoba981152015-12-05 13:58:22 -0800977 ComponentManagerImpl manager{&clock};
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800978 const char kTraits[] = R"({
979 "trait1": {
980 "state": {
981 "prop1": { "type": "string" },
982 "prop2": { "type": "string" }
983 }
984 }
985 })";
986 auto traits = CreateDictionaryValue(kTraits);
987 ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
988 ASSERT_TRUE(manager.AddComponent("", "comp1", {"trait1"}, nullptr));
989
990 int count = 0;
991 int count2 = 0;
992 manager.AddStateChangedCallback(base::Bind([&count]() { count++; }));
993 manager.AddStateChangedCallback(base::Bind([&count2]() { count2++; }));
994 EXPECT_EQ(1, count);
995 EXPECT_EQ(1, count2);
996 EXPECT_EQ(0, manager.GetLastStateChangeId());
997
998 base::StringValue p1("foo");
999 ASSERT_TRUE(manager.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
1000 EXPECT_EQ(2, count);
1001 EXPECT_EQ(2, count2);
1002 EXPECT_EQ(1, manager.GetLastStateChangeId());
1003
1004 ASSERT_TRUE(manager.SetStateProperty("comp1", "trait1.prop2", p1, nullptr));
1005 EXPECT_EQ(3, count);
1006 EXPECT_EQ(3, count2);
1007 EXPECT_EQ(2, manager.GetLastStateChangeId());
1008
1009 // Fail - no component.
1010 ASSERT_FALSE(manager.SetStateProperty("comp2", "trait1.prop2", p1, nullptr));
1011 EXPECT_EQ(3, count);
1012 EXPECT_EQ(3, count2);
1013 EXPECT_EQ(2, manager.GetLastStateChangeId());
1014}
1015
1016TEST(ComponentManager, ComponentStateUpdates) {
1017 SimpleTestClock clock;
Alex Vakulenkoba981152015-12-05 13:58:22 -08001018 ComponentManagerImpl manager{&clock};
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001019 const char kTraits[] = R"({
1020 "trait1": {
1021 "state": {
1022 "prop1": { "type": "string" },
1023 "prop2": { "type": "string" }
1024 }
1025 },
1026 "trait2": {
1027 "state": {
1028 "prop3": { "type": "string" },
1029 "prop4": { "type": "string" }
1030 }
1031 }
1032 })";
1033 auto traits = CreateDictionaryValue(kTraits);
1034 ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
1035 ASSERT_TRUE(manager.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
1036 ASSERT_TRUE(manager.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
1037
1038 std::vector<ComponentManager::UpdateID> updates1;
1039 auto callback1 = [&updates1](ComponentManager::UpdateID id) {
1040 updates1.push_back(id);
1041 };
1042 // State change queue is empty, callback should be called immediately.
1043 auto token1 = manager.AddServerStateUpdatedCallback(base::Bind(callback1));
1044 ASSERT_EQ(1u, updates1.size());
1045 EXPECT_EQ(manager.GetLastStateChangeId(), updates1.front());
1046 updates1.clear();
1047
1048 base::StringValue foo("foo");
1049 base::Time time1 = base::Time::Now();
1050 clock.SetNow(time1);
1051 // These three updates should be grouped into two separate state change queue
1052 // items, since they all happen at the same time, but for two different
1053 // components.
1054 ASSERT_TRUE(manager.SetStateProperty("comp1", "trait1.prop1", foo, nullptr));
1055 ASSERT_TRUE(manager.SetStateProperty("comp2", "trait2.prop3", foo, nullptr));
1056 ASSERT_TRUE(manager.SetStateProperty("comp1", "trait1.prop2", foo, nullptr));
1057
1058 std::vector<ComponentManager::UpdateID> updates2;
1059 auto callback2 = [&updates2](ComponentManager::UpdateID id) {
1060 updates2.push_back(id);
1061 };
1062 // State change queue is not empty, so callback will be called later.
1063 auto token2 = manager.AddServerStateUpdatedCallback(base::Bind(callback2));
1064 EXPECT_TRUE(updates2.empty());
1065
1066 base::StringValue bar("bar");
1067 base::Time time2 = time1 + base::TimeDelta::FromSeconds(1);
1068 clock.SetNow(time2);
1069 // Two more update events (as above) but at |time2|.
1070 ASSERT_TRUE(manager.SetStateProperty("comp1", "trait1.prop1", bar, nullptr));
1071 ASSERT_TRUE(manager.SetStateProperty("comp2", "trait2.prop3", bar, nullptr));
1072 ASSERT_TRUE(manager.SetStateProperty("comp1", "trait1.prop2", bar, nullptr));
1073
1074 auto snapshot = manager.GetAndClearRecordedStateChanges();
1075 EXPECT_EQ(manager.GetLastStateChangeId(), snapshot.update_id);
1076 ASSERT_EQ(4u, snapshot.state_changes.size());
1077
1078 EXPECT_EQ("comp1", snapshot.state_changes[0].component);
1079 EXPECT_EQ(time1, snapshot.state_changes[0].timestamp);
1080 EXPECT_JSON_EQ(R"({"trait1":{"prop1":"foo","prop2":"foo"}})",
1081 *snapshot.state_changes[0].changed_properties);
1082
1083 EXPECT_EQ("comp2", snapshot.state_changes[1].component);
1084 EXPECT_EQ(time1, snapshot.state_changes[1].timestamp);
1085 EXPECT_JSON_EQ(R"({"trait2":{"prop3":"foo"}})",
1086 *snapshot.state_changes[1].changed_properties);
1087
1088 EXPECT_EQ("comp1", snapshot.state_changes[2].component);
1089 EXPECT_EQ(time2, snapshot.state_changes[2].timestamp);
1090 EXPECT_JSON_EQ(R"({"trait1":{"prop1":"bar","prop2":"bar"}})",
1091 *snapshot.state_changes[2].changed_properties);
1092
1093 EXPECT_EQ("comp2", snapshot.state_changes[3].component);
1094 EXPECT_EQ(time2, snapshot.state_changes[3].timestamp);
1095 EXPECT_JSON_EQ(R"({"trait2":{"prop3":"bar"}})",
1096 *snapshot.state_changes[3].changed_properties);
1097
1098 // Make sure previous GetAndClearRecordedStateChanges() clears the queue.
1099 auto snapshot2 = manager.GetAndClearRecordedStateChanges();
1100 EXPECT_EQ(manager.GetLastStateChangeId(), snapshot2.update_id);
1101 EXPECT_TRUE(snapshot2.state_changes.empty());
1102
1103 // Now indicate that we have update the changes on the server.
1104 manager.NotifyStateUpdatedOnServer(snapshot.update_id);
1105 ASSERT_EQ(1u, updates1.size());
1106 EXPECT_EQ(snapshot.update_id, updates1.front());
1107 ASSERT_EQ(1u, updates2.size());
1108 EXPECT_EQ(snapshot.update_id, updates2.front());
1109}
1110
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001111TEST(ComponentManager, FindComponentWithTrait) {
Alex Vakulenkoba981152015-12-05 13:58:22 -08001112 ComponentManagerImpl manager;
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001113 const char kTraits[] = R"({
1114 "trait1": {},
1115 "trait2": {},
1116 "trait3": {}
1117 })";
1118 auto traits = CreateDictionaryValue(kTraits);
1119 ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
1120 ASSERT_TRUE(manager.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
1121 ASSERT_TRUE(manager.AddComponent("", "comp2", {"trait3"}, nullptr));
1122
1123 EXPECT_EQ("comp1", manager.FindComponentWithTrait("trait1"));
1124 EXPECT_EQ("comp1", manager.FindComponentWithTrait("trait2"));
1125 EXPECT_EQ("comp2", manager.FindComponentWithTrait("trait3"));
1126 EXPECT_EQ("", manager.FindComponentWithTrait("trait4"));
1127}
1128
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001129TEST(ComponentManager, AddLegacyCommandAndStateDefinitions) {
1130 ComponentManagerImpl manager;
1131 const char kCommandDefs1[] = R"({
1132 "package1": {
1133 "command1": {
1134 "minimalRole": "user",
1135 "parameters": {"height": {"type": "integer"}}
1136 },
1137 "command2": {
1138 "minimalRole": "owner",
1139 "parameters": {}
1140 }
1141 },
1142 "package2": {
1143 "command1": { "minimalRole": "user" },
1144 "command2": { "minimalRole": "owner" }
1145 }
1146 })";
1147 auto json = CreateDictionaryValue(kCommandDefs1);
1148 EXPECT_TRUE(manager.AddLegacyCommandDefinitions(*json, nullptr));
1149 const char kExpected1[] = R"({
1150 "package1": {
1151 "commands": {
1152 "command1": {
1153 "minimalRole": "user",
1154 "parameters": {"height": {"type": "integer"}}
1155 },
1156 "command2": {
1157 "minimalRole": "owner",
1158 "parameters": {}
1159 }
1160 }
1161 },
1162 "package2": {
1163 "commands": {
1164 "command1": { "minimalRole": "user" },
1165 "command2": { "minimalRole": "owner" }
1166 }
1167 }
1168 })";
1169 EXPECT_JSON_EQ(kExpected1, manager.GetTraits());
1170 const char kExpectedComponents1[] = R"({
1171 "__weave__": { "traits": ["package1", "package2"] }
1172 })";
1173 EXPECT_JSON_EQ(kExpectedComponents1, manager.GetComponents());
1174
1175 const char kCommandDefs2[] = R"({
1176 "package2": {
1177 "command3": { "minimalRole": "user" }
1178 },
1179 "package3": {
1180 "command1": { "minimalRole": "user" },
1181 "command2": { "minimalRole": "owner" }
1182 }
1183 })";
1184 json = CreateDictionaryValue(kCommandDefs2);
1185 EXPECT_TRUE(manager.AddLegacyCommandDefinitions(*json, nullptr));
1186 const char kExpected2[] = R"({
1187 "package1": {
1188 "commands": {
1189 "command1": {
1190 "minimalRole": "user",
1191 "parameters": {"height": {"type": "integer"}}
1192 },
1193 "command2": {
1194 "minimalRole": "owner",
1195 "parameters": {}
1196 }
1197 }
1198 },
1199 "package2": {
1200 "commands": {
1201 "command1": { "minimalRole": "user" },
1202 "command2": { "minimalRole": "owner" },
1203 "command3": { "minimalRole": "user" }
1204 }
1205 },
1206 "package3": {
1207 "commands": {
1208 "command1": { "minimalRole": "user" },
1209 "command2": { "minimalRole": "owner" }
1210 }
1211 }
1212 })";
1213 EXPECT_JSON_EQ(kExpected2, manager.GetTraits());
1214 const char kExpectedComponents2[] = R"({
1215 "__weave__": { "traits": ["package1", "package2", "package3"] }
1216 })";
1217 EXPECT_JSON_EQ(kExpectedComponents2, manager.GetComponents());
1218
1219 // Redefining existing commands.
1220 EXPECT_FALSE(manager.AddLegacyCommandDefinitions(*json, nullptr));
1221
1222 const char kStateDefs1[] = R"({
1223 "package1": {
1224 "prop1": { "type": "string" },
1225 "prop2": { "type": "string" }
1226 },
1227 "package4": {
1228 "prop3": { "type": "string" },
1229 "prop4": { "type": "string" }
1230 }
1231 })";
1232 json = CreateDictionaryValue(kStateDefs1);
1233 EXPECT_TRUE(manager.AddLegacyStateDefinitions(*json, nullptr));
1234 const char kExpectedComponents3[] = R"({
1235 "__weave__": { "traits": ["package1", "package2", "package3", "package4"] }
1236 })";
1237 EXPECT_JSON_EQ(kExpectedComponents3, manager.GetComponents());
1238
1239 const char kExpected3[] = R"({
1240 "package1": {
1241 "commands": {
1242 "command1": {
1243 "minimalRole": "user",
1244 "parameters": {"height": {"type": "integer"}}
1245 },
1246 "command2": {
1247 "minimalRole": "owner",
1248 "parameters": {}
1249 }
1250 },
1251 "state": {
1252 "prop1": { "type": "string" },
1253 "prop2": { "type": "string" }
1254 }
1255 },
1256 "package2": {
1257 "commands": {
1258 "command1": { "minimalRole": "user" },
1259 "command2": { "minimalRole": "owner" },
1260 "command3": { "minimalRole": "user" }
1261 }
1262 },
1263 "package3": {
1264 "commands": {
1265 "command1": { "minimalRole": "user" },
1266 "command2": { "minimalRole": "owner" }
1267 }
1268 },
1269 "package4": {
1270 "state": {
1271 "prop3": { "type": "string" },
1272 "prop4": { "type": "string" }
1273 }
1274 }
1275 })";
1276 EXPECT_JSON_EQ(kExpected3, manager.GetTraits());
1277 const char kExpectedComponents4[] = R"({
1278 "__weave__": { "traits": ["package1", "package2", "package3", "package4"] }
1279 })";
1280 EXPECT_JSON_EQ(kExpectedComponents4, manager.GetComponents());
1281
1282 // Redefining existing commands.
1283 EXPECT_FALSE(manager.AddLegacyStateDefinitions(*json, nullptr));
1284
1285 const char kExpected4[] = R"({
1286 "package1": {
1287 "command1": {
1288 "minimalRole": "user",
1289 "parameters": {"height": {"type": "integer"}}
1290 },
1291 "command2": {
1292 "minimalRole": "owner",
1293 "parameters": {}
1294 }
1295 },
1296 "package2": {
1297 "command1": { "minimalRole": "user" },
1298 "command2": { "minimalRole": "owner" },
1299 "command3": { "minimalRole": "user" }
1300 },
1301 "package3": {
1302 "command1": { "minimalRole": "user" },
1303 "command2": { "minimalRole": "owner" }
1304 }
1305 })";
1306 EXPECT_JSON_EQ(kExpected4, manager.GetLegacyCommandDefinitions());
1307}
1308
1309TEST(ComponentManager, GetLegacyState) {
1310 ComponentManagerImpl manager;
1311 const char kTraits[] = R"({
1312 "trait1": {
1313 "state": {
1314 "prop1": { "type": "string" },
1315 "prop2": { "type": "string" }
1316 }
1317 },
1318 "trait2": {
1319 "state": {
1320 "prop3": { "type": "string" },
1321 "prop4": { "type": "string" }
1322 }
1323 }
1324 })";
1325 auto traits = CreateDictionaryValue(kTraits);
1326 ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
1327 ASSERT_TRUE(manager.AddComponent("", "comp1", {"trait1"}, nullptr));
1328 ASSERT_TRUE(manager.AddComponent("", "comp2", {"trait2"}, nullptr));
1329
1330 ASSERT_TRUE(manager.SetStatePropertiesFromJson(
1331 "comp1", R"({"trait1": {"prop1": "foo", "prop2": "bar"}})", nullptr));
1332 ASSERT_TRUE(manager.SetStatePropertiesFromJson(
1333 "comp2", R"({"trait2": {"prop3": "baz", "prop4": "quux"}})", nullptr));
1334
1335 const char kExpected[] = R"({
1336 "trait1": {
1337 "prop1": "foo",
1338 "prop2": "bar"
1339 },
1340 "trait2": {
1341 "prop3": "baz",
1342 "prop4": "quux"
1343 }
1344 })";
1345 EXPECT_JSON_EQ(kExpected, manager.GetLegacyState());
1346}
1347
Alex Vakulenkoba981152015-12-05 13:58:22 -08001348TEST(ComponentManager, TestMockComponentManager) {
1349 // Check that all the virtual methods are mocked out.
1350 MockComponentManager mock;
1351}
1352
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -08001353} // namespace weave