blob: 519b80a3b17846cda0d8a5c11947f7fc57d91422 [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"
Vitaly Bukaece713e2015-12-09 10:59:33 -080015#include "src/test/mock_clock.h"
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080016
17namespace weave {
18
19using test::CreateDictionaryValue;
Vitaly Bukaece713e2015-12-09 10:59:33 -080020using testing::Return;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080021
22namespace {
23
24bool HasTrait(const base::DictionaryValue& comp, const std::string& trait) {
25 const base::ListValue* list = nullptr;
26 if (!comp.GetList("traits", &list))
27 return false;
28 for (const base::Value* item : *list) {
29 std::string value;
30 if (item->GetAsString(&value) && value == trait)
31 return true;
32 }
33 return false;
34}
35
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080036// Creates sample trait/component trees:
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -080037// {
38// "traits": {
39// "t1": {},
40// "t2": {},
41// "t3": {},
42// "t4": {},
43// "t5": {},
44// "t6": {},
45// },
46// "components": {
47// "comp1": {
48// "traits": [ "t1" ],
49// "components": {
50// "comp2": [
51// { "traits": [ "t2" ] },
52// {
53// "traits": [ "t3" ],
54// "components": {
55// "comp3": {
56// "traits": [ "t4" ],
57// "components": {
58// "comp4": {
59// "traits": [ "t5", "t6" ]
60// }
61// }
62// }
63// }
64// }
65// ],
66// }
67// }
68// }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080069// }
Vitaly Bukaece713e2015-12-09 10:59:33 -080070class ComponentManagerTest : public ::testing::Test {
71 protected:
72 void CreateTestComponentTree(ComponentManager* manager) {
73 const char kTraits[] =
74 R"({"t1":{},"t2":{},"t3":{},"t4":{},"t5":{},"t6":{}})";
75 auto json = CreateDictionaryValue(kTraits);
76 ASSERT_TRUE(manager->LoadTraits(*json, nullptr));
77 EXPECT_TRUE(manager->AddComponent("", "comp1", {"t1"}, nullptr));
78 EXPECT_TRUE(
79 manager->AddComponentArrayItem("comp1", "comp2", {"t2"}, nullptr));
80 EXPECT_TRUE(
81 manager->AddComponentArrayItem("comp1", "comp2", {"t3"}, nullptr));
82 EXPECT_TRUE(
83 manager->AddComponent("comp1.comp2[1]", "comp3", {"t4"}, nullptr));
84 EXPECT_TRUE(manager->AddComponent("comp1.comp2[1].comp3", "comp4",
85 {"t5", "t6"}, nullptr));
86 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080087
Vitaly Bukaece713e2015-12-09 10:59:33 -080088 test::MockClock clock_;
89 ComponentManagerImpl manager_{&clock_};
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080090};
91
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080092} // anonymous namespace
93
Vitaly Bukaece713e2015-12-09 10:59:33 -080094TEST_F(ComponentManagerTest, Empty) {
95 EXPECT_TRUE(manager_.GetTraits().empty());
96 EXPECT_TRUE(manager_.GetComponents().empty());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080097}
98
Vitaly Bukaece713e2015-12-09 10:59:33 -080099TEST_F(ComponentManagerTest, LoadTraits) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800100 const char kTraits[] = R"({
101 "trait1": {
102 "commands": {
103 "command1": {
104 "minimalRole": "user",
105 "parameters": {"height": {"type": "integer"}}
106 }
107 },
108 "state": {
109 "property1": {"type": "boolean"}
110 }
111 },
112 "trait2": {
113 "state": {
114 "property2": {"type": "string"}
115 }
116 }
117 })";
118 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800119 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
120 EXPECT_JSON_EQ(kTraits, manager_.GetTraits());
121 EXPECT_TRUE(manager_.GetComponents().empty());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800122}
123
Vitaly Bukaece713e2015-12-09 10:59:33 -0800124TEST_F(ComponentManagerTest, LoadTraitsDuplicateIdentical) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800125 const char kTraits1[] = R"({
126 "trait1": {
127 "commands": {
128 "command1": {
129 "minimalRole": "user",
130 "parameters": {"height": {"type": "integer"}}
131 }
132 },
133 "state": {
134 "property1": {"type": "boolean"}
135 }
136 },
137 "trait2": {
138 "state": {
139 "property2": {"type": "string"}
140 }
141 }
142 })";
143 auto json = CreateDictionaryValue(kTraits1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800144 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800145 const char kTraits2[] = R"({
146 "trait1": {
147 "commands": {
148 "command1": {
149 "minimalRole": "user",
150 "parameters": {"height": {"type": "integer"}}
151 }
152 },
153 "state": {
154 "property1": {"type": "boolean"}
155 }
156 },
157 "trait3": {
158 "state": {
159 "property3": {"type": "string"}
160 }
161 }
162 })";
163 json = CreateDictionaryValue(kTraits2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800164 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800165 const char kExpected[] = R"({
166 "trait1": {
167 "commands": {
168 "command1": {
169 "minimalRole": "user",
170 "parameters": {"height": {"type": "integer"}}
171 }
172 },
173 "state": {
174 "property1": {"type": "boolean"}
175 }
176 },
177 "trait2": {
178 "state": {
179 "property2": {"type": "string"}
180 }
181 },
182 "trait3": {
183 "state": {
184 "property3": {"type": "string"}
185 }
186 }
187 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800188 EXPECT_JSON_EQ(kExpected, manager_.GetTraits());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800189}
190
Vitaly Bukaece713e2015-12-09 10:59:33 -0800191TEST_F(ComponentManagerTest, LoadTraitsDuplicateOverride) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800192 const char kTraits1[] = R"({
193 "trait1": {
194 "commands": {
195 "command1": {
196 "minimalRole": "user",
197 "parameters": {"height": {"type": "integer"}}
198 }
199 },
200 "state": {
201 "property1": {"type": "boolean"}
202 }
203 },
204 "trait2": {
205 "state": {
206 "property2": {"type": "string"}
207 }
208 }
209 })";
210 auto json = CreateDictionaryValue(kTraits1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800211 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800212 const char kTraits2[] = R"({
213 "trait1": {
214 "commands": {
215 "command1": {
216 "minimalRole": "user",
217 "parameters": {"height": {"type": "string"}}
218 }
219 },
220 "state": {
221 "property1": {"type": "boolean"}
222 }
223 },
224 "trait3": {
225 "state": {
226 "property3": {"type": "string"}
227 }
228 }
229 })";
230 json = CreateDictionaryValue(kTraits2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800231 EXPECT_FALSE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800232}
233
Vitaly Bukaece713e2015-12-09 10:59:33 -0800234TEST_F(ComponentManagerTest, AddTraitDefChangedCallback) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800235 int count = 0;
236 int count2 = 0;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800237 manager_.AddTraitDefChangedCallback(base::Bind([&count]() { count++; }));
238 manager_.AddTraitDefChangedCallback(base::Bind([&count2]() { count2++; }));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800239 EXPECT_EQ(1, count);
240 EXPECT_EQ(1, count2);
241 // New definitions.
242 const char kTraits1[] = R"({
243 "trait1": {
244 "state": {
245 "property1": {"type": "boolean"}
246 }
247 },
248 "trait2": {
249 "state": {
250 "property2": {"type": "string"}
251 }
252 }
253 })";
254 auto json = CreateDictionaryValue(kTraits1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800255 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800256 EXPECT_EQ(2, count);
257 // Duplicate definition, shouldn't call the callback.
258 const char kTraits2[] = R"({
259 "trait1": {
260 "state": {
261 "property1": {"type": "boolean"}
262 }
263 }
264 })";
265 json = CreateDictionaryValue(kTraits2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800266 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800267 EXPECT_EQ(2, count);
268 // New definition, should call the callback now.
269 const char kTraits3[] = R"({
270 "trait3": {
271 "state": {
272 "property3": {"type": "string"}
273 }
274 }
275 })";
276 json = CreateDictionaryValue(kTraits3);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800277 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800278 EXPECT_EQ(3, count);
279 // Wrong definition, shouldn't call the callback.
280 const char kTraits4[] = R"({
281 "trait4": "foo"
282 })";
283 json = CreateDictionaryValue(kTraits4);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800284 EXPECT_FALSE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800285 EXPECT_EQ(3, count);
286 // Make sure both callbacks were called the same number of times.
287 EXPECT_EQ(count2, count);
288}
289
Vitaly Bukaece713e2015-12-09 10:59:33 -0800290TEST_F(ComponentManagerTest, LoadTraitsNotAnObject) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800291 const char kTraits1[] = R"({"trait1": 0})";
292 auto json = CreateDictionaryValue(kTraits1);
293 ErrorPtr error;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800294 EXPECT_FALSE(manager_.LoadTraits(*json, &error));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800295 EXPECT_EQ(errors::commands::kTypeMismatch, error->GetCode());
296}
297
Vitaly Bukaece713e2015-12-09 10:59:33 -0800298TEST_F(ComponentManagerTest, FindTraitDefinition) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800299 const char kTraits[] = R"({
300 "trait1": {
301 "commands": {
302 "command1": {
303 "minimalRole": "user",
304 "parameters": {"height": {"type": "integer"}}
305 }
306 },
307 "state": {
308 "property1": {"type": "boolean"}
309 }
310 },
311 "trait2": {
312 "state": {
313 "property2": {"type": "string"}
314 }
315 }
316 })";
317 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800318 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800319
Vitaly Bukaece713e2015-12-09 10:59:33 -0800320 const base::DictionaryValue* trait = manager_.FindTraitDefinition("trait1");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800321 ASSERT_NE(nullptr, trait);
322 const char kExpected1[] = R"({
323 "commands": {
324 "command1": {
325 "minimalRole": "user",
326 "parameters": {"height": {"type": "integer"}}
327 }
328 },
329 "state": {
330 "property1": {"type": "boolean"}
331 }
332 })";
333 EXPECT_JSON_EQ(kExpected1, *trait);
334
Vitaly Bukaece713e2015-12-09 10:59:33 -0800335 trait = manager_.FindTraitDefinition("trait2");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800336 ASSERT_NE(nullptr, trait);
337 const char kExpected2[] = R"({
338 "state": {
339 "property2": {"type": "string"}
340 }
341 })";
342 EXPECT_JSON_EQ(kExpected2, *trait);
343
Vitaly Bukaece713e2015-12-09 10:59:33 -0800344 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait3"));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800345}
346
Vitaly Bukaece713e2015-12-09 10:59:33 -0800347TEST_F(ComponentManagerTest, FindCommandDefinition) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800348 const char kTraits[] = R"({
349 "trait1": {
350 "commands": {
351 "command1": {
352 "minimalRole": "user",
353 "parameters": {"height": {"type": "integer"}}
354 }
355 }
356 },
357 "trait2": {
358 "commands": {
359 "command1": {
360 "minimalRole": "manager"
361 },
362 "command2": {
363 "minimalRole": "owner"
364 }
365 }
366 }
367 })";
368 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800369 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800370
Vitaly Bukaece713e2015-12-09 10:59:33 -0800371 const auto* cmd_def = manager_.FindCommandDefinition("trait1.command1");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800372 ASSERT_NE(nullptr, cmd_def);
373 const char kExpected1[] = R"({
374 "minimalRole": "user",
375 "parameters": {"height": {"type": "integer"}}
376 })";
377 EXPECT_JSON_EQ(kExpected1, *cmd_def);
378
Vitaly Bukaece713e2015-12-09 10:59:33 -0800379 cmd_def = manager_.FindCommandDefinition("trait2.command1");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800380 ASSERT_NE(nullptr, cmd_def);
381 const char kExpected2[] = R"({
382 "minimalRole": "manager"
383 })";
384 EXPECT_JSON_EQ(kExpected2, *cmd_def);
385
Vitaly Bukaece713e2015-12-09 10:59:33 -0800386 cmd_def = manager_.FindCommandDefinition("trait2.command2");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800387 ASSERT_NE(nullptr, cmd_def);
388 const char kExpected3[] = R"({
389 "minimalRole": "owner"
390 })";
391 EXPECT_JSON_EQ(kExpected3, *cmd_def);
392
Vitaly Bukaece713e2015-12-09 10:59:33 -0800393 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait1.command2"));
394 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait3.command1"));
395 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait"));
396 EXPECT_EQ(nullptr,
397 manager_.FindTraitDefinition("trait1.command1.parameters"));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800398}
399
Vitaly Bukaece713e2015-12-09 10:59:33 -0800400TEST_F(ComponentManagerTest, GetMinimalRole) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800401 const char kTraits[] = R"({
402 "trait1": {
403 "commands": {
404 "command1": { "minimalRole": "user" },
405 "command2": { "minimalRole": "viewer" }
406 }
407 },
408 "trait2": {
409 "commands": {
410 "command1": { "minimalRole": "manager" },
411 "command2": { "minimalRole": "owner" }
412 }
413 }
414 })";
415 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800416 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800417
418 UserRole role;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800419 ASSERT_TRUE(manager_.GetMinimalRole("trait1.command1", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800420 EXPECT_EQ(UserRole::kUser, role);
421
Vitaly Bukaece713e2015-12-09 10:59:33 -0800422 ASSERT_TRUE(manager_.GetMinimalRole("trait1.command2", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800423 EXPECT_EQ(UserRole::kViewer, role);
424
Vitaly Bukaece713e2015-12-09 10:59:33 -0800425 ASSERT_TRUE(manager_.GetMinimalRole("trait2.command1", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800426 EXPECT_EQ(UserRole::kManager, role);
427
Vitaly Bukaece713e2015-12-09 10:59:33 -0800428 ASSERT_TRUE(manager_.GetMinimalRole("trait2.command2", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800429 EXPECT_EQ(UserRole::kOwner, role);
430
Vitaly Bukaece713e2015-12-09 10:59:33 -0800431 EXPECT_FALSE(manager_.GetMinimalRole("trait1.command3", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800432}
433
Vitaly Bukaece713e2015-12-09 10:59:33 -0800434TEST_F(ComponentManagerTest, AddComponent) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800435 const char kTraits[] = R"({"trait1": {}, "trait2": {}, "trait3": {}})";
436 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800437 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
438 EXPECT_TRUE(
439 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
440 EXPECT_TRUE(manager_.AddComponent("", "comp2", {"trait3"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800441 const char kExpected[] = R"({
442 "comp1": {
443 "traits": ["trait1", "trait2"]
444 },
445 "comp2": {
446 "traits": ["trait3"]
447 }
448 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800449 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800450
451 // 'trait4' is undefined, so can't add a component referring to it.
Vitaly Bukaece713e2015-12-09 10:59:33 -0800452 EXPECT_FALSE(manager_.AddComponent("", "comp3", {"trait4"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800453}
454
Vitaly Bukaece713e2015-12-09 10:59:33 -0800455TEST_F(ComponentManagerTest, AddSubComponent) {
456 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
457 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
458 EXPECT_TRUE(manager_.AddComponent("comp1", "comp3", {}, nullptr));
459 EXPECT_TRUE(manager_.AddComponent("comp1.comp2", "comp4", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800460 const char kExpected[] = R"({
461 "comp1": {
462 "traits": [],
463 "components": {
464 "comp2": {
465 "traits": [],
466 "components": {
467 "comp4": {
468 "traits": []
469 }
470 }
471 },
472 "comp3": {
473 "traits": []
474 }
475 }
476 }
477 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800478 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800479}
480
Vitaly Bukaece713e2015-12-09 10:59:33 -0800481TEST_F(ComponentManagerTest, AddComponentArrayItem) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800482 const char kTraits[] = R"({"foo": {}, "bar": {}})";
483 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800484 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800485
Vitaly Bukaece713e2015-12-09 10:59:33 -0800486 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
487 EXPECT_TRUE(
488 manager_.AddComponentArrayItem("comp1", "comp2", {"foo"}, nullptr));
489 EXPECT_TRUE(
490 manager_.AddComponentArrayItem("comp1", "comp2", {"bar"}, nullptr));
491 EXPECT_TRUE(manager_.AddComponent("comp1.comp2[1]", "comp3", {}, nullptr));
492 EXPECT_TRUE(
493 manager_.AddComponent("comp1.comp2[1].comp3", "comp4", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800494 const char kExpected[] = R"({
495 "comp1": {
496 "traits": [],
497 "components": {
498 "comp2": [
499 {
500 "traits": ["foo"]
501 },
502 {
503 "traits": ["bar"],
504 "components": {
505 "comp3": {
506 "traits": [],
507 "components": {
508 "comp4": {
509 "traits": []
510 }
511 }
512 }
513 }
514 }
515 ]
516 }
517 }
518 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800519 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800520}
521
Alex Vakulenkoce850b52016-01-04 09:27:50 -0800522TEST_F(ComponentManagerTest, RemoveComponent) {
523 CreateTestComponentTree(&manager_);
524 EXPECT_TRUE(manager_.RemoveComponent("comp1.comp2[1].comp3", "comp4",
525 nullptr));
526 const char kExpected1[] = R"({
527 "comp1": {
528 "traits": [ "t1" ],
529 "components": {
530 "comp2": [
531 {
532 "traits": [ "t2" ]
533 },
534 {
535 "traits": [ "t3" ],
536 "components": {
537 "comp3": {
538 "traits": [ "t4" ],
539 "components": {}
540 }
541 }
542 }
543 ]
544 }
545 }
546 })";
547 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
548 EXPECT_TRUE(manager_.RemoveComponentArrayItem("comp1", "comp2", 1, nullptr));
549 const char kExpected2[] = R"({
550 "comp1": {
551 "traits": [ "t1" ],
552 "components": {
553 "comp2": [
554 {
555 "traits": [ "t2" ]
556 }
557 ]
558 }
559 }
560 })";
561 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
562}
563
Vitaly Bukaece713e2015-12-09 10:59:33 -0800564TEST_F(ComponentManagerTest, AddComponentExist) {
565 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
566 EXPECT_FALSE(manager_.AddComponent("", "comp1", {}, nullptr));
567 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
568 EXPECT_FALSE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800569}
570
Vitaly Bukaece713e2015-12-09 10:59:33 -0800571TEST_F(ComponentManagerTest, AddComponentDoesNotExist) {
572 EXPECT_FALSE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800573}
574
Vitaly Bukaece713e2015-12-09 10:59:33 -0800575TEST_F(ComponentManagerTest, AddComponentTreeChangedCallback) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800576 int count = 0;
577 int count2 = 0;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800578 manager_.AddComponentTreeChangedCallback(base::Bind([&count]() { count++; }));
579 manager_.AddComponentTreeChangedCallback(
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800580 base::Bind([&count2]() { count2++; }));
581 EXPECT_EQ(1, count);
582 EXPECT_EQ(1, count2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800583 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800584 EXPECT_EQ(2, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800585 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800586 EXPECT_EQ(3, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800587 EXPECT_TRUE(manager_.AddComponent("comp1.comp2", "comp4", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800588 EXPECT_EQ(4, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800589 EXPECT_TRUE(manager_.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800590 EXPECT_EQ(5, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800591 EXPECT_TRUE(manager_.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800592 EXPECT_EQ(6, count);
Alex Vakulenkoce850b52016-01-04 09:27:50 -0800593 EXPECT_TRUE(manager_.RemoveComponentArrayItem("comp1", "comp3", 1, nullptr));
594 EXPECT_EQ(7, count);
595 EXPECT_TRUE(manager_.RemoveComponent("", "comp1", nullptr));
596 EXPECT_EQ(8, count);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800597 // Make sure both callbacks were called the same number of times.
598 EXPECT_EQ(count2, count);
599}
600
Vitaly Bukaece713e2015-12-09 10:59:33 -0800601TEST_F(ComponentManagerTest, FindComponent) {
602 CreateTestComponentTree(&manager_);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800603
Vitaly Bukaece713e2015-12-09 10:59:33 -0800604 const base::DictionaryValue* comp = manager_.FindComponent("comp1", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800605 ASSERT_NE(nullptr, comp);
606 EXPECT_TRUE(HasTrait(*comp, "t1"));
607
Vitaly Bukaece713e2015-12-09 10:59:33 -0800608 comp = manager_.FindComponent("comp1.comp2[0]", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800609 ASSERT_NE(nullptr, comp);
610 EXPECT_TRUE(HasTrait(*comp, "t2"));
611
Vitaly Bukaece713e2015-12-09 10:59:33 -0800612 comp = manager_.FindComponent("comp1.comp2[1]", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800613 ASSERT_NE(nullptr, comp);
614 EXPECT_TRUE(HasTrait(*comp, "t3"));
615
Vitaly Bukaece713e2015-12-09 10:59:33 -0800616 comp = manager_.FindComponent("comp1.comp2[1].comp3", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800617 ASSERT_NE(nullptr, comp);
618 EXPECT_TRUE(HasTrait(*comp, "t4"));
619
Vitaly Bukaece713e2015-12-09 10:59:33 -0800620 comp = manager_.FindComponent("comp1.comp2[1].comp3.comp4", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800621 ASSERT_NE(nullptr, comp);
622 EXPECT_TRUE(HasTrait(*comp, "t5"));
623
624 // Some whitespaces don't hurt.
Vitaly Bukaece713e2015-12-09 10:59:33 -0800625 comp = manager_.FindComponent(" comp1 . comp2 [ \t 1 ] . comp3.comp4 ",
626 nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800627 EXPECT_NE(nullptr, comp);
628
629 // Now check some failure cases.
630 ErrorPtr error;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800631 EXPECT_EQ(nullptr, manager_.FindComponent("", &error));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800632 EXPECT_NE(nullptr, error.get());
633 // 'comp2' doesn't exist:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800634 EXPECT_EQ(nullptr, manager_.FindComponent("comp2", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800635 // 'comp1.comp2' is an array, not a component:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800636 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800637 // 'comp1.comp2[3]' doesn't exist:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800638 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[3]", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800639 // Empty component names:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800640 EXPECT_EQ(nullptr, manager_.FindComponent(".comp2[1]", nullptr));
641 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.[1]", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800642 // Invalid array indices:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800643 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[s]", nullptr));
644 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[-2]", nullptr));
645 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[1e1]", nullptr));
646 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[1", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800647}
648
Vitaly Bukaece713e2015-12-09 10:59:33 -0800649TEST_F(ComponentManagerTest, ParseCommandInstance) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800650 const char kTraits[] = R"({
651 "trait1": {
652 "commands": {
653 "command1": { "minimalRole": "user" },
654 "command2": { "minimalRole": "viewer" }
655 }
656 },
657 "trait2": {
658 "commands": {
659 "command1": { "minimalRole": "manager" },
660 "command2": { "minimalRole": "owner" }
661 }
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800662 },
663 "trait3": {
664 "commands": {
665 "command1": { "minimalRole": "manager" },
666 "command2": { "minimalRole": "owner" }
667 }
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800668 }
669 })";
670 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800671 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
672 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
673 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait2"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800674
675 std::string id;
676 const char kCommand1[] = R"({
677 "name": "trait1.command1",
Alex Vakulenkob736c982015-12-05 14:09:27 -0800678 "id": "1234-12345",
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800679 "component": "comp1",
680 "parameters": {}
681 })";
682 auto command1 = CreateDictionaryValue(kCommand1);
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800683 EXPECT_NE(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800684 manager_.ParseCommandInstance(*command1, Command::Origin::kLocal,
685 UserRole::kUser, &id, nullptr)
686 .get());
Alex Vakulenkob736c982015-12-05 14:09:27 -0800687 EXPECT_EQ("1234-12345", id);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800688 // Not enough access rights
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800689 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800690 manager_.ParseCommandInstance(*command1, Command::Origin::kLocal,
691 UserRole::kViewer, &id, nullptr)
692 .get());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800693
694 const char kCommand2[] = R"({
695 "name": "trait1.command3",
696 "component": "comp1",
697 "parameters": {}
698 })";
699 auto command2 = CreateDictionaryValue(kCommand2);
700 // trait1.command3 doesn't exist
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800701 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800702 manager_.ParseCommandInstance(*command2, Command::Origin::kLocal,
703 UserRole::kOwner, &id, nullptr)
704 .get());
Alex Vakulenkob736c982015-12-05 14:09:27 -0800705 EXPECT_TRUE(id.empty());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800706
707 const char kCommand3[] = R"({
708 "name": "trait2.command1",
709 "component": "comp1",
710 "parameters": {}
711 })";
712 auto command3 = CreateDictionaryValue(kCommand3);
713 // Component comp1 doesn't have trait2.
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800714 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800715 manager_.ParseCommandInstance(*command3, Command::Origin::kLocal,
716 UserRole::kOwner, &id, nullptr)
717 .get());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800718
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800719 // No component specified, find the suitable component
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800720 const char kCommand4[] = R"({
721 "name": "trait1.command1",
722 "parameters": {}
723 })";
724 auto command4 = CreateDictionaryValue(kCommand4);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800725 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800726 *command4, Command::Origin::kLocal, UserRole::kOwner, &id, nullptr);
727 EXPECT_NE(nullptr, command_instance.get());
728 EXPECT_EQ("comp1", command_instance->GetComponent());
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800729
730 const char kCommand5[] = R"({
731 "name": "trait2.command1",
732 "parameters": {}
733 })";
734 auto command5 = CreateDictionaryValue(kCommand5);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800735 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800736 *command5, Command::Origin::kLocal, UserRole::kOwner, &id, nullptr);
737 EXPECT_NE(nullptr, command_instance.get());
738 EXPECT_EQ("comp2", command_instance->GetComponent());
739
740 // Cannot route the command, no component with 'trait3'.
741 const char kCommand6[] = R"({
742 "name": "trait3.command1",
743 "parameters": {}
744 })";
745 auto command6 = CreateDictionaryValue(kCommand6);
746 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800747 manager_.ParseCommandInstance(*command6, Command::Origin::kLocal,
748 UserRole::kOwner, &id, nullptr)
749 .get());
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800750}
751
Vitaly Bukaece713e2015-12-09 10:59:33 -0800752TEST_F(ComponentManagerTest, AddCommand) {
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800753 const char kTraits[] = R"({
754 "trait1": {
755 "commands": {
756 "command1": { "minimalRole": "user" }
757 }
758 }
759 })";
760 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800761 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
762 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800763
764 std::string id;
765 const char kCommand[] = R"({
766 "name": "trait1.command1",
767 "id": "1234-12345",
768 "component": "comp1",
769 "parameters": {}
770 })";
771 auto command = CreateDictionaryValue(kCommand);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800772 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800773 *command, Command::Origin::kLocal, UserRole::kUser, &id, nullptr);
774 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800775 manager_.AddCommand(std::move(command_instance));
776 const auto* queued_command = manager_.FindCommand(id);
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800777 ASSERT_NE(nullptr, queued_command);
778 EXPECT_EQ("trait1.command1", queued_command->GetName());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800779}
780
Vitaly Bukaece713e2015-12-09 10:59:33 -0800781TEST_F(ComponentManagerTest, AddCommandHandler) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800782 const char kTraits[] = R"({
783 "trait1": {
784 "commands": {
785 "command1": { "minimalRole": "user" }
786 }
787 },
788 "trait2": {
789 "commands": {
790 "command2": { "minimalRole": "user" }
791 }
792 }
793 })";
794 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800795 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
796 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
797 ASSERT_TRUE(
798 manager_.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800799
800 std::string last_tags;
801 auto handler = [&last_tags](int tag, const std::weak_ptr<Command>& command) {
802 if (!last_tags.empty())
803 last_tags += ',';
804 last_tags += std::to_string(tag);
805 };
806
Vitaly Bukaece713e2015-12-09 10:59:33 -0800807 manager_.AddCommandHandler("comp1", "trait1.command1",
808 base::Bind(handler, 1));
809 manager_.AddCommandHandler("comp2", "trait1.command1",
810 base::Bind(handler, 2));
811 manager_.AddCommandHandler("comp2", "trait2.command2",
812 base::Bind(handler, 3));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800813 EXPECT_TRUE(last_tags.empty());
814
815 const char kCommand1[] = R"({
816 "name": "trait1.command1",
817 "component": "comp1"
818 })";
819 auto command1 = CreateDictionaryValue(kCommand1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800820 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800821 *command1, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
822 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800823 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800824 EXPECT_EQ("1", last_tags);
825 last_tags.clear();
826
827 const char kCommand2[] = R"({
828 "name": "trait1.command1",
829 "component": "comp2"
830 })";
831 auto command2 = CreateDictionaryValue(kCommand2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800832 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800833 *command2, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
834 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800835 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800836 EXPECT_EQ("2", last_tags);
837 last_tags.clear();
838
839 const char kCommand3[] = R"({
840 "name": "trait2.command2",
841 "component": "comp2",
842 "parameters": {}
843 })";
844 auto command3 = CreateDictionaryValue(kCommand3);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800845 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800846 *command3, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
847 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800848 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800849 EXPECT_EQ("3", last_tags);
850 last_tags.clear();
851}
852
Vitaly Bukaece713e2015-12-09 10:59:33 -0800853TEST_F(ComponentManagerTest, AddDefaultCommandHandler) {
Alex Vakulenko20334332015-12-08 13:19:49 -0800854 const char kTraits[] = R"({
855 "trait1": {
856 "commands": {
857 "command1": { "minimalRole": "user" }
858 }
859 },
860 "trait2": {
861 "commands": {
862 "command2": { "minimalRole": "user" }
863 }
864 }
865 })";
866 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800867 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
868 ASSERT_TRUE(manager_.AddComponent("", "comp", {"trait1", "trait2"}, nullptr));
Alex Vakulenko20334332015-12-08 13:19:49 -0800869
870 int count = 0;
871 auto handler = [&count](int tag, const std::weak_ptr<Command>& command) {
872 count++;
873 };
874
Vitaly Bukaece713e2015-12-09 10:59:33 -0800875 manager_.AddCommandHandler("", "", base::Bind(handler, 1));
Alex Vakulenko20334332015-12-08 13:19:49 -0800876 EXPECT_EQ(0, count);
877
878 const char kCommand1[] = R"({
879 "name": "trait1.command1",
880 "component": "comp"
881 })";
882 auto command1 = CreateDictionaryValue(kCommand1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800883 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenko20334332015-12-08 13:19:49 -0800884 *command1, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
885 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800886 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko20334332015-12-08 13:19:49 -0800887 EXPECT_EQ(1, count);
888
889 const char kCommand2[] = R"({
890 "name": "trait2.command2",
891 "component": "comp"
892 })";
893 auto command2 = CreateDictionaryValue(kCommand2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800894 command_instance = manager_.ParseCommandInstance(
Alex Vakulenko20334332015-12-08 13:19:49 -0800895 *command2, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
896 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800897 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko20334332015-12-08 13:19:49 -0800898 EXPECT_EQ(2, count);
899}
900
Vitaly Bukaece713e2015-12-09 10:59:33 -0800901TEST_F(ComponentManagerTest, SetStateProperties) {
902 CreateTestComponentTree(&manager_);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800903
904 const char kState1[] = R"({"t1": {"p1": 0, "p2": "foo"}})";
905 auto state1 = CreateDictionaryValue(kState1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800906 ASSERT_TRUE(manager_.SetStateProperties("comp1", *state1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800907 const char kExpected1[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800908 "comp1": {
909 "traits": [ "t1" ],
910 "state": {"t1": {"p1": 0, "p2": "foo"}},
911 "components": {
912 "comp2": [
913 {
914 "traits": [ "t2" ]
915 },
916 {
917 "traits": [ "t3" ],
918 "components": {
919 "comp3": {
920 "traits": [ "t4" ],
921 "components": {
922 "comp4": {
923 "traits": [ "t5", "t6" ]
924 }
925 }
926 }
927 }
928 }
929 ]
930 }
931 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800932 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800933 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800934
935 const char kState2[] = R"({"t1": {"p1": {"bar": "baz"}}})";
936 auto state2 = CreateDictionaryValue(kState2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800937 ASSERT_TRUE(manager_.SetStateProperties("comp1", *state2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800938
939 const char kExpected2[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800940 "comp1": {
941 "traits": [ "t1" ],
942 "state": {"t1": {"p1": {"bar": "baz"}, "p2": "foo"}},
943 "components": {
944 "comp2": [
945 {
946 "traits": [ "t2" ]
947 },
948 {
949 "traits": [ "t3" ],
950 "components": {
951 "comp3": {
952 "traits": [ "t4" ],
953 "components": {
954 "comp4": {
955 "traits": [ "t5", "t6" ]
956 }
957 }
958 }
959 }
960 }
961 ]
962 }
963 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800964 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800965 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800966
967 const char kState3[] = R"({"t5": {"p1": 1}})";
968 auto state3 = CreateDictionaryValue(kState3);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800969 ASSERT_TRUE(manager_.SetStateProperties("comp1.comp2[1].comp3.comp4", *state3,
970 nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800971
972 const char kExpected3[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800973 "comp1": {
974 "traits": [ "t1" ],
975 "state": {"t1": {"p1": {"bar": "baz"}, "p2": "foo"}},
976 "components": {
977 "comp2": [
978 {
979 "traits": [ "t2" ]
980 },
981 {
982 "traits": [ "t3" ],
983 "components": {
984 "comp3": {
985 "traits": [ "t4" ],
986 "components": {
987 "comp4": {
988 "traits": [ "t5", "t6" ],
989 "state": { "t5": { "p1": 1 } }
990 }
991 }
992 }
993 }
994 }
995 ]
996 }
997 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800998 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800999 EXPECT_JSON_EQ(kExpected3, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001000}
1001
Vitaly Bukaece713e2015-12-09 10:59:33 -08001002TEST_F(ComponentManagerTest, SetStatePropertiesFromJson) {
1003 CreateTestComponentTree(&manager_);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001004
Vitaly Bukaece713e2015-12-09 10:59:33 -08001005 ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
Vitaly Buka34668e72015-12-15 14:46:47 -08001006 "comp1.comp2[1].comp3.comp4",
1007 R"({"t5": {"p1": 3}, "t6": {"p2": 5}})", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001008
1009 const char kExpected[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001010 "comp1": {
1011 "traits": [ "t1" ],
1012 "components": {
1013 "comp2": [
1014 {
1015 "traits": [ "t2" ]
1016 },
1017 {
1018 "traits": [ "t3" ],
1019 "components": {
1020 "comp3": {
1021 "traits": [ "t4" ],
1022 "components": {
1023 "comp4": {
1024 "traits": [ "t5", "t6" ],
1025 "state": {
1026 "t5": { "p1": 3 },
1027 "t6": { "p2": 5 }
1028 }
1029 }
1030 }
1031 }
1032 }
1033 }
1034 ]
1035 }
1036 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001037 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001038 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001039}
1040
Vitaly Bukaece713e2015-12-09 10:59:33 -08001041TEST_F(ComponentManagerTest, SetGetStateProperty) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001042 const char kTraits[] = R"({
1043 "trait1": {
1044 "state": {
1045 "prop1": { "type": "string" },
1046 "prop2": { "type": "integer" }
1047 }
1048 },
1049 "trait2": {
1050 "state": {
1051 "prop3": { "type": "string" },
1052 "prop4": { "type": "string" }
1053 }
1054 }
1055 })";
1056 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001057 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1058 ASSERT_TRUE(
1059 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001060
1061 base::StringValue p1("foo");
Vitaly Bukaece713e2015-12-09 10:59:33 -08001062 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001063
1064 const char kExpected1[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001065 "comp1": {
1066 "traits": [ "trait1", "trait2" ],
1067 "state": {
1068 "trait1": { "prop1": "foo" }
1069 }
1070 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001071 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001072 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001073
1074 base::FundamentalValue p2(2);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001075 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait2.prop3", p2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001076
1077 const char kExpected2[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001078 "comp1": {
1079 "traits": [ "trait1", "trait2" ],
1080 "state": {
1081 "trait1": { "prop1": "foo" },
1082 "trait2": { "prop3": 2 }
1083 }
1084 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001085 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001086 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001087 // Just the package name without property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001088 EXPECT_FALSE(manager_.SetStateProperty("comp1", "trait2", p2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001089
Vitaly Bukaece713e2015-12-09 10:59:33 -08001090 const base::Value* value =
1091 manager_.GetStateProperty("comp1", "trait1.prop1", nullptr);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001092 ASSERT_NE(nullptr, value);
1093 EXPECT_TRUE(p1.Equals(value));
Vitaly Bukaece713e2015-12-09 10:59:33 -08001094 value = manager_.GetStateProperty("comp1", "trait2.prop3", nullptr);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001095 ASSERT_NE(nullptr, value);
1096 EXPECT_TRUE(p2.Equals(value));
1097
1098 // Non-existing property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001099 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp1", "trait2.p", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001100 // Non-existing component
Vitaly Bukaece713e2015-12-09 10:59:33 -08001101 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp2", "trait.prop", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001102 // Just the package name without property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001103 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp1", "trait2", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001104}
1105
Vitaly Bukaece713e2015-12-09 10:59:33 -08001106TEST_F(ComponentManagerTest, AddStateChangedCallback) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001107 const char kTraits[] = R"({
1108 "trait1": {
1109 "state": {
1110 "prop1": { "type": "string" },
1111 "prop2": { "type": "string" }
1112 }
1113 }
1114 })";
1115 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001116 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1117 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001118
1119 int count = 0;
1120 int count2 = 0;
Vitaly Bukaece713e2015-12-09 10:59:33 -08001121 manager_.AddStateChangedCallback(base::Bind([&count]() { count++; }));
1122 manager_.AddStateChangedCallback(base::Bind([&count2]() { count2++; }));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001123 EXPECT_EQ(1, count);
1124 EXPECT_EQ(1, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001125 EXPECT_EQ(0u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001126
1127 base::StringValue p1("foo");
Vitaly Bukaece713e2015-12-09 10:59:33 -08001128 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001129 EXPECT_EQ(2, count);
1130 EXPECT_EQ(2, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001131 EXPECT_EQ(1u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001132
Vitaly Bukaece713e2015-12-09 10:59:33 -08001133 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001134 EXPECT_EQ(3, count);
1135 EXPECT_EQ(3, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001136 EXPECT_EQ(2u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001137
1138 // Fail - no component.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001139 ASSERT_FALSE(manager_.SetStateProperty("comp2", "trait1.prop2", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001140 EXPECT_EQ(3, count);
1141 EXPECT_EQ(3, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001142 EXPECT_EQ(2u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001143}
1144
Vitaly Bukaece713e2015-12-09 10:59:33 -08001145TEST_F(ComponentManagerTest, ComponentStateUpdates) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001146 const char kTraits[] = R"({
1147 "trait1": {
1148 "state": {
1149 "prop1": { "type": "string" },
1150 "prop2": { "type": "string" }
1151 }
1152 },
1153 "trait2": {
1154 "state": {
1155 "prop3": { "type": "string" },
1156 "prop4": { "type": "string" }
1157 }
1158 }
1159 })";
1160 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001161 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1162 ASSERT_TRUE(
1163 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
1164 ASSERT_TRUE(
1165 manager_.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001166
1167 std::vector<ComponentManager::UpdateID> updates1;
1168 auto callback1 = [&updates1](ComponentManager::UpdateID id) {
1169 updates1.push_back(id);
1170 };
1171 // State change queue is empty, callback should be called immediately.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001172 auto token1 = manager_.AddServerStateUpdatedCallback(base::Bind(callback1));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001173 ASSERT_EQ(1u, updates1.size());
Vitaly Bukaece713e2015-12-09 10:59:33 -08001174 EXPECT_EQ(manager_.GetLastStateChangeId(), updates1.front());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001175 updates1.clear();
1176
1177 base::StringValue foo("foo");
1178 base::Time time1 = base::Time::Now();
Vitaly Bukaece713e2015-12-09 10:59:33 -08001179 EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(time1));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001180 // These three updates should be grouped into two separate state change queue
1181 // items, since they all happen at the same time, but for two different
1182 // components.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001183 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", foo, nullptr));
1184 ASSERT_TRUE(manager_.SetStateProperty("comp2", "trait2.prop3", foo, nullptr));
1185 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", foo, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001186
1187 std::vector<ComponentManager::UpdateID> updates2;
1188 auto callback2 = [&updates2](ComponentManager::UpdateID id) {
1189 updates2.push_back(id);
1190 };
1191 // State change queue is not empty, so callback will be called later.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001192 auto token2 = manager_.AddServerStateUpdatedCallback(base::Bind(callback2));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001193 EXPECT_TRUE(updates2.empty());
1194
1195 base::StringValue bar("bar");
1196 base::Time time2 = time1 + base::TimeDelta::FromSeconds(1);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001197 EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(time2));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001198 // Two more update events (as above) but at |time2|.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001199 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", bar, nullptr));
1200 ASSERT_TRUE(manager_.SetStateProperty("comp2", "trait2.prop3", bar, nullptr));
1201 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", bar, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001202
Vitaly Bukaece713e2015-12-09 10:59:33 -08001203 auto snapshot = manager_.GetAndClearRecordedStateChanges();
1204 EXPECT_EQ(manager_.GetLastStateChangeId(), snapshot.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001205 ASSERT_EQ(4u, snapshot.state_changes.size());
1206
1207 EXPECT_EQ("comp1", snapshot.state_changes[0].component);
1208 EXPECT_EQ(time1, snapshot.state_changes[0].timestamp);
1209 EXPECT_JSON_EQ(R"({"trait1":{"prop1":"foo","prop2":"foo"}})",
1210 *snapshot.state_changes[0].changed_properties);
1211
1212 EXPECT_EQ("comp2", snapshot.state_changes[1].component);
1213 EXPECT_EQ(time1, snapshot.state_changes[1].timestamp);
1214 EXPECT_JSON_EQ(R"({"trait2":{"prop3":"foo"}})",
1215 *snapshot.state_changes[1].changed_properties);
1216
1217 EXPECT_EQ("comp1", snapshot.state_changes[2].component);
1218 EXPECT_EQ(time2, snapshot.state_changes[2].timestamp);
1219 EXPECT_JSON_EQ(R"({"trait1":{"prop1":"bar","prop2":"bar"}})",
1220 *snapshot.state_changes[2].changed_properties);
1221
1222 EXPECT_EQ("comp2", snapshot.state_changes[3].component);
1223 EXPECT_EQ(time2, snapshot.state_changes[3].timestamp);
1224 EXPECT_JSON_EQ(R"({"trait2":{"prop3":"bar"}})",
1225 *snapshot.state_changes[3].changed_properties);
1226
1227 // Make sure previous GetAndClearRecordedStateChanges() clears the queue.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001228 auto snapshot2 = manager_.GetAndClearRecordedStateChanges();
1229 EXPECT_EQ(manager_.GetLastStateChangeId(), snapshot2.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001230 EXPECT_TRUE(snapshot2.state_changes.empty());
1231
1232 // Now indicate that we have update the changes on the server.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001233 manager_.NotifyStateUpdatedOnServer(snapshot.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001234 ASSERT_EQ(1u, updates1.size());
1235 EXPECT_EQ(snapshot.update_id, updates1.front());
1236 ASSERT_EQ(1u, updates2.size());
1237 EXPECT_EQ(snapshot.update_id, updates2.front());
1238}
1239
Vitaly Bukaece713e2015-12-09 10:59:33 -08001240TEST_F(ComponentManagerTest, FindComponentWithTrait) {
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001241 const char kTraits[] = R"({
1242 "trait1": {},
1243 "trait2": {},
1244 "trait3": {}
1245 })";
1246 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001247 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1248 ASSERT_TRUE(
1249 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
1250 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait3"}, nullptr));
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001251
Vitaly Bukaece713e2015-12-09 10:59:33 -08001252 EXPECT_EQ("comp1", manager_.FindComponentWithTrait("trait1"));
1253 EXPECT_EQ("comp1", manager_.FindComponentWithTrait("trait2"));
1254 EXPECT_EQ("comp2", manager_.FindComponentWithTrait("trait3"));
1255 EXPECT_EQ("", manager_.FindComponentWithTrait("trait4"));
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001256}
1257
Vitaly Bukaece713e2015-12-09 10:59:33 -08001258TEST_F(ComponentManagerTest, AddLegacyCommandAndStateDefinitions) {
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001259 const char kCommandDefs1[] = R"({
1260 "package1": {
1261 "command1": {
1262 "minimalRole": "user",
1263 "parameters": {"height": {"type": "integer"}}
1264 },
1265 "command2": {
1266 "minimalRole": "owner",
1267 "parameters": {}
1268 }
1269 },
1270 "package2": {
1271 "command1": { "minimalRole": "user" },
1272 "command2": { "minimalRole": "owner" }
1273 }
1274 })";
1275 auto json = CreateDictionaryValue(kCommandDefs1);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001276 EXPECT_TRUE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001277 const char kExpected1[] = R"({
1278 "package1": {
1279 "commands": {
1280 "command1": {
1281 "minimalRole": "user",
1282 "parameters": {"height": {"type": "integer"}}
1283 },
1284 "command2": {
1285 "minimalRole": "owner",
1286 "parameters": {}
1287 }
1288 }
1289 },
1290 "package2": {
1291 "commands": {
1292 "command1": { "minimalRole": "user" },
1293 "command2": { "minimalRole": "owner" }
1294 }
1295 }
1296 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001297 EXPECT_JSON_EQ(kExpected1, manager_.GetTraits());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001298 const char kExpectedComponents1[] = R"({
1299 "__weave__": { "traits": ["package1", "package2"] }
1300 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001301 EXPECT_JSON_EQ(kExpectedComponents1, manager_.GetComponents());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001302
1303 const char kCommandDefs2[] = R"({
1304 "package2": {
1305 "command3": { "minimalRole": "user" }
1306 },
1307 "package3": {
1308 "command1": { "minimalRole": "user" },
1309 "command2": { "minimalRole": "owner" }
1310 }
1311 })";
1312 json = CreateDictionaryValue(kCommandDefs2);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001313 EXPECT_TRUE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001314 const char kExpected2[] = R"({
1315 "package1": {
1316 "commands": {
1317 "command1": {
1318 "minimalRole": "user",
1319 "parameters": {"height": {"type": "integer"}}
1320 },
1321 "command2": {
1322 "minimalRole": "owner",
1323 "parameters": {}
1324 }
1325 }
1326 },
1327 "package2": {
1328 "commands": {
1329 "command1": { "minimalRole": "user" },
1330 "command2": { "minimalRole": "owner" },
1331 "command3": { "minimalRole": "user" }
1332 }
1333 },
1334 "package3": {
1335 "commands": {
1336 "command1": { "minimalRole": "user" },
1337 "command2": { "minimalRole": "owner" }
1338 }
1339 }
1340 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001341 EXPECT_JSON_EQ(kExpected2, manager_.GetTraits());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001342 const char kExpectedComponents2[] = R"({
1343 "__weave__": { "traits": ["package1", "package2", "package3"] }
1344 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001345 EXPECT_JSON_EQ(kExpectedComponents2, manager_.GetComponents());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001346
1347 // Redefining existing commands.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001348 EXPECT_FALSE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001349
1350 const char kStateDefs1[] = R"({
1351 "package1": {
1352 "prop1": { "type": "string" },
1353 "prop2": { "type": "string" }
1354 },
1355 "package4": {
1356 "prop3": { "type": "string" },
1357 "prop4": { "type": "string" }
1358 }
1359 })";
1360 json = CreateDictionaryValue(kStateDefs1);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001361 EXPECT_TRUE(manager_.AddLegacyStateDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001362 const char kExpectedComponents3[] = R"({
1363 "__weave__": { "traits": ["package1", "package2", "package3", "package4"] }
1364 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001365 EXPECT_JSON_EQ(kExpectedComponents3, manager_.GetComponents());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001366
1367 const char kExpected3[] = R"({
1368 "package1": {
1369 "commands": {
1370 "command1": {
1371 "minimalRole": "user",
1372 "parameters": {"height": {"type": "integer"}}
1373 },
1374 "command2": {
1375 "minimalRole": "owner",
1376 "parameters": {}
1377 }
1378 },
1379 "state": {
1380 "prop1": { "type": "string" },
1381 "prop2": { "type": "string" }
1382 }
1383 },
1384 "package2": {
1385 "commands": {
1386 "command1": { "minimalRole": "user" },
1387 "command2": { "minimalRole": "owner" },
1388 "command3": { "minimalRole": "user" }
1389 }
1390 },
1391 "package3": {
1392 "commands": {
1393 "command1": { "minimalRole": "user" },
1394 "command2": { "minimalRole": "owner" }
1395 }
1396 },
1397 "package4": {
1398 "state": {
1399 "prop3": { "type": "string" },
1400 "prop4": { "type": "string" }
1401 }
1402 }
1403 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001404 EXPECT_JSON_EQ(kExpected3, manager_.GetTraits());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001405 const char kExpectedComponents4[] = R"({
1406 "__weave__": { "traits": ["package1", "package2", "package3", "package4"] }
1407 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001408 EXPECT_JSON_EQ(kExpectedComponents4, manager_.GetComponents());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001409
1410 // Redefining existing commands.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001411 EXPECT_FALSE(manager_.AddLegacyStateDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001412
1413 const char kExpected4[] = R"({
1414 "package1": {
1415 "command1": {
1416 "minimalRole": "user",
1417 "parameters": {"height": {"type": "integer"}}
1418 },
1419 "command2": {
1420 "minimalRole": "owner",
1421 "parameters": {}
1422 }
1423 },
1424 "package2": {
1425 "command1": { "minimalRole": "user" },
1426 "command2": { "minimalRole": "owner" },
1427 "command3": { "minimalRole": "user" }
1428 },
1429 "package3": {
1430 "command1": { "minimalRole": "user" },
1431 "command2": { "minimalRole": "owner" }
1432 }
1433 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001434 EXPECT_JSON_EQ(kExpected4, manager_.GetLegacyCommandDefinitions());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001435}
1436
Vitaly Bukaece713e2015-12-09 10:59:33 -08001437TEST_F(ComponentManagerTest, GetLegacyState) {
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001438 const char kTraits[] = R"({
1439 "trait1": {
1440 "state": {
1441 "prop1": { "type": "string" },
1442 "prop2": { "type": "string" }
1443 }
1444 },
1445 "trait2": {
1446 "state": {
1447 "prop3": { "type": "string" },
1448 "prop4": { "type": "string" }
1449 }
1450 }
1451 })";
1452 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001453 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1454 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
1455 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait2"}, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001456
Vitaly Bukaece713e2015-12-09 10:59:33 -08001457 ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001458 "comp1", R"({"trait1": {"prop1": "foo", "prop2": "bar"}})", nullptr));
Vitaly Bukaece713e2015-12-09 10:59:33 -08001459 ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001460 "comp2", R"({"trait2": {"prop3": "baz", "prop4": "quux"}})", nullptr));
1461
1462 const char kExpected[] = R"({
1463 "trait1": {
1464 "prop1": "foo",
1465 "prop2": "bar"
1466 },
1467 "trait2": {
1468 "prop3": "baz",
1469 "prop4": "quux"
1470 }
1471 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001472 EXPECT_JSON_EQ(kExpected, manager_.GetLegacyState());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001473}
1474
Vitaly Bukaece713e2015-12-09 10:59:33 -08001475TEST_F(ComponentManagerTest, TestMockComponentManager) {
Alex Vakulenkoba981152015-12-05 13:58:22 -08001476 // Check that all the virtual methods are mocked out.
1477 MockComponentManager mock;
1478}
1479
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -08001480} // namespace weave