blob: 6b660b16915cb7e5968c0c06b966db8b50c05ba6 [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
Vitaly Bukaece713e2015-12-09 10:59:33 -0800522TEST_F(ComponentManagerTest, AddComponentExist) {
523 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
524 EXPECT_FALSE(manager_.AddComponent("", "comp1", {}, nullptr));
525 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
526 EXPECT_FALSE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800527}
528
Vitaly Bukaece713e2015-12-09 10:59:33 -0800529TEST_F(ComponentManagerTest, AddComponentDoesNotExist) {
530 EXPECT_FALSE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800531}
532
Vitaly Bukaece713e2015-12-09 10:59:33 -0800533TEST_F(ComponentManagerTest, AddComponentTreeChangedCallback) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800534 int count = 0;
535 int count2 = 0;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800536 manager_.AddComponentTreeChangedCallback(base::Bind([&count]() { count++; }));
537 manager_.AddComponentTreeChangedCallback(
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800538 base::Bind([&count2]() { count2++; }));
539 EXPECT_EQ(1, count);
540 EXPECT_EQ(1, count2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800541 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800542 EXPECT_EQ(2, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800543 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800544 EXPECT_EQ(3, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800545 EXPECT_TRUE(manager_.AddComponent("comp1.comp2", "comp4", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800546 EXPECT_EQ(4, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800547 EXPECT_TRUE(manager_.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800548 EXPECT_EQ(5, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800549 EXPECT_TRUE(manager_.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800550 EXPECT_EQ(6, count);
551 // Make sure both callbacks were called the same number of times.
552 EXPECT_EQ(count2, count);
553}
554
Vitaly Bukaece713e2015-12-09 10:59:33 -0800555TEST_F(ComponentManagerTest, FindComponent) {
556 CreateTestComponentTree(&manager_);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800557
Vitaly Bukaece713e2015-12-09 10:59:33 -0800558 const base::DictionaryValue* comp = manager_.FindComponent("comp1", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800559 ASSERT_NE(nullptr, comp);
560 EXPECT_TRUE(HasTrait(*comp, "t1"));
561
Vitaly Bukaece713e2015-12-09 10:59:33 -0800562 comp = manager_.FindComponent("comp1.comp2[0]", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800563 ASSERT_NE(nullptr, comp);
564 EXPECT_TRUE(HasTrait(*comp, "t2"));
565
Vitaly Bukaece713e2015-12-09 10:59:33 -0800566 comp = manager_.FindComponent("comp1.comp2[1]", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800567 ASSERT_NE(nullptr, comp);
568 EXPECT_TRUE(HasTrait(*comp, "t3"));
569
Vitaly Bukaece713e2015-12-09 10:59:33 -0800570 comp = manager_.FindComponent("comp1.comp2[1].comp3", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800571 ASSERT_NE(nullptr, comp);
572 EXPECT_TRUE(HasTrait(*comp, "t4"));
573
Vitaly Bukaece713e2015-12-09 10:59:33 -0800574 comp = manager_.FindComponent("comp1.comp2[1].comp3.comp4", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800575 ASSERT_NE(nullptr, comp);
576 EXPECT_TRUE(HasTrait(*comp, "t5"));
577
578 // Some whitespaces don't hurt.
Vitaly Bukaece713e2015-12-09 10:59:33 -0800579 comp = manager_.FindComponent(" comp1 . comp2 [ \t 1 ] . comp3.comp4 ",
580 nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800581 EXPECT_NE(nullptr, comp);
582
583 // Now check some failure cases.
584 ErrorPtr error;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800585 EXPECT_EQ(nullptr, manager_.FindComponent("", &error));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800586 EXPECT_NE(nullptr, error.get());
587 // 'comp2' doesn't exist:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800588 EXPECT_EQ(nullptr, manager_.FindComponent("comp2", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800589 // 'comp1.comp2' is an array, not a component:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800590 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800591 // 'comp1.comp2[3]' doesn't exist:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800592 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[3]", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800593 // Empty component names:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800594 EXPECT_EQ(nullptr, manager_.FindComponent(".comp2[1]", nullptr));
595 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.[1]", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800596 // Invalid array indices:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800597 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[s]", nullptr));
598 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[-2]", nullptr));
599 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[1e1]", nullptr));
600 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[1", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800601}
602
Vitaly Bukaece713e2015-12-09 10:59:33 -0800603TEST_F(ComponentManagerTest, ParseCommandInstance) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800604 const char kTraits[] = R"({
605 "trait1": {
606 "commands": {
607 "command1": { "minimalRole": "user" },
608 "command2": { "minimalRole": "viewer" }
609 }
610 },
611 "trait2": {
612 "commands": {
613 "command1": { "minimalRole": "manager" },
614 "command2": { "minimalRole": "owner" }
615 }
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800616 },
617 "trait3": {
618 "commands": {
619 "command1": { "minimalRole": "manager" },
620 "command2": { "minimalRole": "owner" }
621 }
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800622 }
623 })";
624 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800625 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
626 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
627 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait2"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800628
629 std::string id;
630 const char kCommand1[] = R"({
631 "name": "trait1.command1",
Alex Vakulenkob736c982015-12-05 14:09:27 -0800632 "id": "1234-12345",
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800633 "component": "comp1",
634 "parameters": {}
635 })";
636 auto command1 = CreateDictionaryValue(kCommand1);
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800637 EXPECT_NE(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800638 manager_.ParseCommandInstance(*command1, Command::Origin::kLocal,
639 UserRole::kUser, &id, nullptr)
640 .get());
Alex Vakulenkob736c982015-12-05 14:09:27 -0800641 EXPECT_EQ("1234-12345", id);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800642 // Not enough access rights
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800643 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800644 manager_.ParseCommandInstance(*command1, Command::Origin::kLocal,
645 UserRole::kViewer, &id, nullptr)
646 .get());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800647
648 const char kCommand2[] = R"({
649 "name": "trait1.command3",
650 "component": "comp1",
651 "parameters": {}
652 })";
653 auto command2 = CreateDictionaryValue(kCommand2);
654 // trait1.command3 doesn't exist
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800655 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800656 manager_.ParseCommandInstance(*command2, Command::Origin::kLocal,
657 UserRole::kOwner, &id, nullptr)
658 .get());
Alex Vakulenkob736c982015-12-05 14:09:27 -0800659 EXPECT_TRUE(id.empty());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800660
661 const char kCommand3[] = R"({
662 "name": "trait2.command1",
663 "component": "comp1",
664 "parameters": {}
665 })";
666 auto command3 = CreateDictionaryValue(kCommand3);
667 // Component comp1 doesn't have trait2.
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800668 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800669 manager_.ParseCommandInstance(*command3, Command::Origin::kLocal,
670 UserRole::kOwner, &id, nullptr)
671 .get());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800672
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800673 // No component specified, find the suitable component
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800674 const char kCommand4[] = R"({
675 "name": "trait1.command1",
676 "parameters": {}
677 })";
678 auto command4 = CreateDictionaryValue(kCommand4);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800679 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800680 *command4, Command::Origin::kLocal, UserRole::kOwner, &id, nullptr);
681 EXPECT_NE(nullptr, command_instance.get());
682 EXPECT_EQ("comp1", command_instance->GetComponent());
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800683
684 const char kCommand5[] = R"({
685 "name": "trait2.command1",
686 "parameters": {}
687 })";
688 auto command5 = CreateDictionaryValue(kCommand5);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800689 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800690 *command5, Command::Origin::kLocal, UserRole::kOwner, &id, nullptr);
691 EXPECT_NE(nullptr, command_instance.get());
692 EXPECT_EQ("comp2", command_instance->GetComponent());
693
694 // Cannot route the command, no component with 'trait3'.
695 const char kCommand6[] = R"({
696 "name": "trait3.command1",
697 "parameters": {}
698 })";
699 auto command6 = CreateDictionaryValue(kCommand6);
700 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800701 manager_.ParseCommandInstance(*command6, Command::Origin::kLocal,
702 UserRole::kOwner, &id, nullptr)
703 .get());
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800704}
705
Vitaly Bukaece713e2015-12-09 10:59:33 -0800706TEST_F(ComponentManagerTest, AddCommand) {
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800707 const char kTraits[] = R"({
708 "trait1": {
709 "commands": {
710 "command1": { "minimalRole": "user" }
711 }
712 }
713 })";
714 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800715 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
716 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800717
718 std::string id;
719 const char kCommand[] = R"({
720 "name": "trait1.command1",
721 "id": "1234-12345",
722 "component": "comp1",
723 "parameters": {}
724 })";
725 auto command = CreateDictionaryValue(kCommand);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800726 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800727 *command, Command::Origin::kLocal, UserRole::kUser, &id, nullptr);
728 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800729 manager_.AddCommand(std::move(command_instance));
730 const auto* queued_command = manager_.FindCommand(id);
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800731 ASSERT_NE(nullptr, queued_command);
732 EXPECT_EQ("trait1.command1", queued_command->GetName());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800733}
734
Vitaly Bukaece713e2015-12-09 10:59:33 -0800735TEST_F(ComponentManagerTest, AddCommandHandler) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800736 const char kTraits[] = R"({
737 "trait1": {
738 "commands": {
739 "command1": { "minimalRole": "user" }
740 }
741 },
742 "trait2": {
743 "commands": {
744 "command2": { "minimalRole": "user" }
745 }
746 }
747 })";
748 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800749 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
750 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
751 ASSERT_TRUE(
752 manager_.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800753
754 std::string last_tags;
755 auto handler = [&last_tags](int tag, const std::weak_ptr<Command>& command) {
756 if (!last_tags.empty())
757 last_tags += ',';
758 last_tags += std::to_string(tag);
759 };
760
Vitaly Bukaece713e2015-12-09 10:59:33 -0800761 manager_.AddCommandHandler("comp1", "trait1.command1",
762 base::Bind(handler, 1));
763 manager_.AddCommandHandler("comp2", "trait1.command1",
764 base::Bind(handler, 2));
765 manager_.AddCommandHandler("comp2", "trait2.command2",
766 base::Bind(handler, 3));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800767 EXPECT_TRUE(last_tags.empty());
768
769 const char kCommand1[] = R"({
770 "name": "trait1.command1",
771 "component": "comp1"
772 })";
773 auto command1 = CreateDictionaryValue(kCommand1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800774 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800775 *command1, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
776 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800777 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800778 EXPECT_EQ("1", last_tags);
779 last_tags.clear();
780
781 const char kCommand2[] = R"({
782 "name": "trait1.command1",
783 "component": "comp2"
784 })";
785 auto command2 = CreateDictionaryValue(kCommand2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800786 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800787 *command2, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
788 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800789 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800790 EXPECT_EQ("2", last_tags);
791 last_tags.clear();
792
793 const char kCommand3[] = R"({
794 "name": "trait2.command2",
795 "component": "comp2",
796 "parameters": {}
797 })";
798 auto command3 = CreateDictionaryValue(kCommand3);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800799 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800800 *command3, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
801 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800802 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800803 EXPECT_EQ("3", last_tags);
804 last_tags.clear();
805}
806
Vitaly Bukaece713e2015-12-09 10:59:33 -0800807TEST_F(ComponentManagerTest, AddDefaultCommandHandler) {
Alex Vakulenko20334332015-12-08 13:19:49 -0800808 const char kTraits[] = R"({
809 "trait1": {
810 "commands": {
811 "command1": { "minimalRole": "user" }
812 }
813 },
814 "trait2": {
815 "commands": {
816 "command2": { "minimalRole": "user" }
817 }
818 }
819 })";
820 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800821 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
822 ASSERT_TRUE(manager_.AddComponent("", "comp", {"trait1", "trait2"}, nullptr));
Alex Vakulenko20334332015-12-08 13:19:49 -0800823
824 int count = 0;
825 auto handler = [&count](int tag, const std::weak_ptr<Command>& command) {
826 count++;
827 };
828
Vitaly Bukaece713e2015-12-09 10:59:33 -0800829 manager_.AddCommandHandler("", "", base::Bind(handler, 1));
Alex Vakulenko20334332015-12-08 13:19:49 -0800830 EXPECT_EQ(0, count);
831
832 const char kCommand1[] = R"({
833 "name": "trait1.command1",
834 "component": "comp"
835 })";
836 auto command1 = CreateDictionaryValue(kCommand1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800837 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenko20334332015-12-08 13:19:49 -0800838 *command1, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
839 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800840 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko20334332015-12-08 13:19:49 -0800841 EXPECT_EQ(1, count);
842
843 const char kCommand2[] = R"({
844 "name": "trait2.command2",
845 "component": "comp"
846 })";
847 auto command2 = CreateDictionaryValue(kCommand2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800848 command_instance = manager_.ParseCommandInstance(
Alex Vakulenko20334332015-12-08 13:19:49 -0800849 *command2, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
850 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800851 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko20334332015-12-08 13:19:49 -0800852 EXPECT_EQ(2, count);
853}
854
Vitaly Bukaece713e2015-12-09 10:59:33 -0800855TEST_F(ComponentManagerTest, SetStateProperties) {
856 CreateTestComponentTree(&manager_);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800857
858 const char kState1[] = R"({"t1": {"p1": 0, "p2": "foo"}})";
859 auto state1 = CreateDictionaryValue(kState1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800860 ASSERT_TRUE(manager_.SetStateProperties("comp1", *state1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800861 const char kExpected1[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800862 "comp1": {
863 "traits": [ "t1" ],
864 "state": {"t1": {"p1": 0, "p2": "foo"}},
865 "components": {
866 "comp2": [
867 {
868 "traits": [ "t2" ]
869 },
870 {
871 "traits": [ "t3" ],
872 "components": {
873 "comp3": {
874 "traits": [ "t4" ],
875 "components": {
876 "comp4": {
877 "traits": [ "t5", "t6" ]
878 }
879 }
880 }
881 }
882 }
883 ]
884 }
885 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800886 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800887 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800888
889 const char kState2[] = R"({"t1": {"p1": {"bar": "baz"}}})";
890 auto state2 = CreateDictionaryValue(kState2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800891 ASSERT_TRUE(manager_.SetStateProperties("comp1", *state2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800892
893 const char kExpected2[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800894 "comp1": {
895 "traits": [ "t1" ],
896 "state": {"t1": {"p1": {"bar": "baz"}, "p2": "foo"}},
897 "components": {
898 "comp2": [
899 {
900 "traits": [ "t2" ]
901 },
902 {
903 "traits": [ "t3" ],
904 "components": {
905 "comp3": {
906 "traits": [ "t4" ],
907 "components": {
908 "comp4": {
909 "traits": [ "t5", "t6" ]
910 }
911 }
912 }
913 }
914 }
915 ]
916 }
917 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800918 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800919 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800920
921 const char kState3[] = R"({"t5": {"p1": 1}})";
922 auto state3 = CreateDictionaryValue(kState3);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800923 ASSERT_TRUE(manager_.SetStateProperties("comp1.comp2[1].comp3.comp4", *state3,
924 nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800925
926 const char kExpected3[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800927 "comp1": {
928 "traits": [ "t1" ],
929 "state": {"t1": {"p1": {"bar": "baz"}, "p2": "foo"}},
930 "components": {
931 "comp2": [
932 {
933 "traits": [ "t2" ]
934 },
935 {
936 "traits": [ "t3" ],
937 "components": {
938 "comp3": {
939 "traits": [ "t4" ],
940 "components": {
941 "comp4": {
942 "traits": [ "t5", "t6" ],
943 "state": { "t5": { "p1": 1 } }
944 }
945 }
946 }
947 }
948 }
949 ]
950 }
951 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800952 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800953 EXPECT_JSON_EQ(kExpected3, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800954}
955
Vitaly Bukaece713e2015-12-09 10:59:33 -0800956TEST_F(ComponentManagerTest, SetStatePropertiesFromJson) {
957 CreateTestComponentTree(&manager_);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800958
Vitaly Bukaece713e2015-12-09 10:59:33 -0800959 ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
Vitaly Buka34668e72015-12-15 14:46:47 -0800960 "comp1.comp2[1].comp3.comp4",
961 R"({"t5": {"p1": 3}, "t6": {"p2": 5}})", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800962
963 const char kExpected[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800964 "comp1": {
965 "traits": [ "t1" ],
966 "components": {
967 "comp2": [
968 {
969 "traits": [ "t2" ]
970 },
971 {
972 "traits": [ "t3" ],
973 "components": {
974 "comp3": {
975 "traits": [ "t4" ],
976 "components": {
977 "comp4": {
978 "traits": [ "t5", "t6" ],
979 "state": {
980 "t5": { "p1": 3 },
981 "t6": { "p2": 5 }
982 }
983 }
984 }
985 }
986 }
987 }
988 ]
989 }
990 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800991 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800992 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800993}
994
Vitaly Bukaece713e2015-12-09 10:59:33 -0800995TEST_F(ComponentManagerTest, SetGetStateProperty) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800996 const char kTraits[] = R"({
997 "trait1": {
998 "state": {
999 "prop1": { "type": "string" },
1000 "prop2": { "type": "integer" }
1001 }
1002 },
1003 "trait2": {
1004 "state": {
1005 "prop3": { "type": "string" },
1006 "prop4": { "type": "string" }
1007 }
1008 }
1009 })";
1010 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001011 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1012 ASSERT_TRUE(
1013 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001014
1015 base::StringValue p1("foo");
Vitaly Bukaece713e2015-12-09 10:59:33 -08001016 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001017
1018 const char kExpected1[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001019 "comp1": {
1020 "traits": [ "trait1", "trait2" ],
1021 "state": {
1022 "trait1": { "prop1": "foo" }
1023 }
1024 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001025 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001026 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001027
1028 base::FundamentalValue p2(2);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001029 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait2.prop3", p2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001030
1031 const char kExpected2[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001032 "comp1": {
1033 "traits": [ "trait1", "trait2" ],
1034 "state": {
1035 "trait1": { "prop1": "foo" },
1036 "trait2": { "prop3": 2 }
1037 }
1038 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001039 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001040 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001041 // Just the package name without property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001042 EXPECT_FALSE(manager_.SetStateProperty("comp1", "trait2", p2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001043
Vitaly Bukaece713e2015-12-09 10:59:33 -08001044 const base::Value* value =
1045 manager_.GetStateProperty("comp1", "trait1.prop1", nullptr);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001046 ASSERT_NE(nullptr, value);
1047 EXPECT_TRUE(p1.Equals(value));
Vitaly Bukaece713e2015-12-09 10:59:33 -08001048 value = manager_.GetStateProperty("comp1", "trait2.prop3", nullptr);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001049 ASSERT_NE(nullptr, value);
1050 EXPECT_TRUE(p2.Equals(value));
1051
1052 // Non-existing property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001053 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp1", "trait2.p", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001054 // Non-existing component
Vitaly Bukaece713e2015-12-09 10:59:33 -08001055 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp2", "trait.prop", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001056 // Just the package name without property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001057 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp1", "trait2", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001058}
1059
Vitaly Bukaece713e2015-12-09 10:59:33 -08001060TEST_F(ComponentManagerTest, AddStateChangedCallback) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001061 const char kTraits[] = R"({
1062 "trait1": {
1063 "state": {
1064 "prop1": { "type": "string" },
1065 "prop2": { "type": "string" }
1066 }
1067 }
1068 })";
1069 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001070 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1071 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001072
1073 int count = 0;
1074 int count2 = 0;
Vitaly Bukaece713e2015-12-09 10:59:33 -08001075 manager_.AddStateChangedCallback(base::Bind([&count]() { count++; }));
1076 manager_.AddStateChangedCallback(base::Bind([&count2]() { count2++; }));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001077 EXPECT_EQ(1, count);
1078 EXPECT_EQ(1, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001079 EXPECT_EQ(0u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001080
1081 base::StringValue p1("foo");
Vitaly Bukaece713e2015-12-09 10:59:33 -08001082 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001083 EXPECT_EQ(2, count);
1084 EXPECT_EQ(2, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001085 EXPECT_EQ(1u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001086
Vitaly Bukaece713e2015-12-09 10:59:33 -08001087 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001088 EXPECT_EQ(3, count);
1089 EXPECT_EQ(3, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001090 EXPECT_EQ(2u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001091
1092 // Fail - no component.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001093 ASSERT_FALSE(manager_.SetStateProperty("comp2", "trait1.prop2", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001094 EXPECT_EQ(3, count);
1095 EXPECT_EQ(3, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001096 EXPECT_EQ(2u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001097}
1098
Vitaly Bukaece713e2015-12-09 10:59:33 -08001099TEST_F(ComponentManagerTest, ComponentStateUpdates) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001100 const char kTraits[] = R"({
1101 "trait1": {
1102 "state": {
1103 "prop1": { "type": "string" },
1104 "prop2": { "type": "string" }
1105 }
1106 },
1107 "trait2": {
1108 "state": {
1109 "prop3": { "type": "string" },
1110 "prop4": { "type": "string" }
1111 }
1112 }
1113 })";
1114 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001115 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1116 ASSERT_TRUE(
1117 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
1118 ASSERT_TRUE(
1119 manager_.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001120
1121 std::vector<ComponentManager::UpdateID> updates1;
1122 auto callback1 = [&updates1](ComponentManager::UpdateID id) {
1123 updates1.push_back(id);
1124 };
1125 // State change queue is empty, callback should be called immediately.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001126 auto token1 = manager_.AddServerStateUpdatedCallback(base::Bind(callback1));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001127 ASSERT_EQ(1u, updates1.size());
Vitaly Bukaece713e2015-12-09 10:59:33 -08001128 EXPECT_EQ(manager_.GetLastStateChangeId(), updates1.front());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001129 updates1.clear();
1130
1131 base::StringValue foo("foo");
1132 base::Time time1 = base::Time::Now();
Vitaly Bukaece713e2015-12-09 10:59:33 -08001133 EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(time1));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001134 // These three updates should be grouped into two separate state change queue
1135 // items, since they all happen at the same time, but for two different
1136 // components.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001137 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", foo, nullptr));
1138 ASSERT_TRUE(manager_.SetStateProperty("comp2", "trait2.prop3", foo, nullptr));
1139 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", foo, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001140
1141 std::vector<ComponentManager::UpdateID> updates2;
1142 auto callback2 = [&updates2](ComponentManager::UpdateID id) {
1143 updates2.push_back(id);
1144 };
1145 // State change queue is not empty, so callback will be called later.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001146 auto token2 = manager_.AddServerStateUpdatedCallback(base::Bind(callback2));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001147 EXPECT_TRUE(updates2.empty());
1148
1149 base::StringValue bar("bar");
1150 base::Time time2 = time1 + base::TimeDelta::FromSeconds(1);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001151 EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(time2));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001152 // Two more update events (as above) but at |time2|.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001153 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", bar, nullptr));
1154 ASSERT_TRUE(manager_.SetStateProperty("comp2", "trait2.prop3", bar, nullptr));
1155 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", bar, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001156
Vitaly Bukaece713e2015-12-09 10:59:33 -08001157 auto snapshot = manager_.GetAndClearRecordedStateChanges();
1158 EXPECT_EQ(manager_.GetLastStateChangeId(), snapshot.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001159 ASSERT_EQ(4u, snapshot.state_changes.size());
1160
1161 EXPECT_EQ("comp1", snapshot.state_changes[0].component);
1162 EXPECT_EQ(time1, snapshot.state_changes[0].timestamp);
1163 EXPECT_JSON_EQ(R"({"trait1":{"prop1":"foo","prop2":"foo"}})",
1164 *snapshot.state_changes[0].changed_properties);
1165
1166 EXPECT_EQ("comp2", snapshot.state_changes[1].component);
1167 EXPECT_EQ(time1, snapshot.state_changes[1].timestamp);
1168 EXPECT_JSON_EQ(R"({"trait2":{"prop3":"foo"}})",
1169 *snapshot.state_changes[1].changed_properties);
1170
1171 EXPECT_EQ("comp1", snapshot.state_changes[2].component);
1172 EXPECT_EQ(time2, snapshot.state_changes[2].timestamp);
1173 EXPECT_JSON_EQ(R"({"trait1":{"prop1":"bar","prop2":"bar"}})",
1174 *snapshot.state_changes[2].changed_properties);
1175
1176 EXPECT_EQ("comp2", snapshot.state_changes[3].component);
1177 EXPECT_EQ(time2, snapshot.state_changes[3].timestamp);
1178 EXPECT_JSON_EQ(R"({"trait2":{"prop3":"bar"}})",
1179 *snapshot.state_changes[3].changed_properties);
1180
1181 // Make sure previous GetAndClearRecordedStateChanges() clears the queue.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001182 auto snapshot2 = manager_.GetAndClearRecordedStateChanges();
1183 EXPECT_EQ(manager_.GetLastStateChangeId(), snapshot2.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001184 EXPECT_TRUE(snapshot2.state_changes.empty());
1185
1186 // Now indicate that we have update the changes on the server.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001187 manager_.NotifyStateUpdatedOnServer(snapshot.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001188 ASSERT_EQ(1u, updates1.size());
1189 EXPECT_EQ(snapshot.update_id, updates1.front());
1190 ASSERT_EQ(1u, updates2.size());
1191 EXPECT_EQ(snapshot.update_id, updates2.front());
1192}
1193
Vitaly Bukaece713e2015-12-09 10:59:33 -08001194TEST_F(ComponentManagerTest, FindComponentWithTrait) {
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001195 const char kTraits[] = R"({
1196 "trait1": {},
1197 "trait2": {},
1198 "trait3": {}
1199 })";
1200 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001201 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1202 ASSERT_TRUE(
1203 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
1204 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait3"}, nullptr));
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001205
Vitaly Bukaece713e2015-12-09 10:59:33 -08001206 EXPECT_EQ("comp1", manager_.FindComponentWithTrait("trait1"));
1207 EXPECT_EQ("comp1", manager_.FindComponentWithTrait("trait2"));
1208 EXPECT_EQ("comp2", manager_.FindComponentWithTrait("trait3"));
1209 EXPECT_EQ("", manager_.FindComponentWithTrait("trait4"));
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001210}
1211
Vitaly Bukaece713e2015-12-09 10:59:33 -08001212TEST_F(ComponentManagerTest, AddLegacyCommandAndStateDefinitions) {
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001213 const char kCommandDefs1[] = R"({
1214 "package1": {
1215 "command1": {
1216 "minimalRole": "user",
1217 "parameters": {"height": {"type": "integer"}}
1218 },
1219 "command2": {
1220 "minimalRole": "owner",
1221 "parameters": {}
1222 }
1223 },
1224 "package2": {
1225 "command1": { "minimalRole": "user" },
1226 "command2": { "minimalRole": "owner" }
1227 }
1228 })";
1229 auto json = CreateDictionaryValue(kCommandDefs1);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001230 EXPECT_TRUE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001231 const char kExpected1[] = R"({
1232 "package1": {
1233 "commands": {
1234 "command1": {
1235 "minimalRole": "user",
1236 "parameters": {"height": {"type": "integer"}}
1237 },
1238 "command2": {
1239 "minimalRole": "owner",
1240 "parameters": {}
1241 }
1242 }
1243 },
1244 "package2": {
1245 "commands": {
1246 "command1": { "minimalRole": "user" },
1247 "command2": { "minimalRole": "owner" }
1248 }
1249 }
1250 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001251 EXPECT_JSON_EQ(kExpected1, manager_.GetTraits());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001252 const char kExpectedComponents1[] = R"({
1253 "__weave__": { "traits": ["package1", "package2"] }
1254 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001255 EXPECT_JSON_EQ(kExpectedComponents1, manager_.GetComponents());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001256
1257 const char kCommandDefs2[] = R"({
1258 "package2": {
1259 "command3": { "minimalRole": "user" }
1260 },
1261 "package3": {
1262 "command1": { "minimalRole": "user" },
1263 "command2": { "minimalRole": "owner" }
1264 }
1265 })";
1266 json = CreateDictionaryValue(kCommandDefs2);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001267 EXPECT_TRUE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001268 const char kExpected2[] = R"({
1269 "package1": {
1270 "commands": {
1271 "command1": {
1272 "minimalRole": "user",
1273 "parameters": {"height": {"type": "integer"}}
1274 },
1275 "command2": {
1276 "minimalRole": "owner",
1277 "parameters": {}
1278 }
1279 }
1280 },
1281 "package2": {
1282 "commands": {
1283 "command1": { "minimalRole": "user" },
1284 "command2": { "minimalRole": "owner" },
1285 "command3": { "minimalRole": "user" }
1286 }
1287 },
1288 "package3": {
1289 "commands": {
1290 "command1": { "minimalRole": "user" },
1291 "command2": { "minimalRole": "owner" }
1292 }
1293 }
1294 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001295 EXPECT_JSON_EQ(kExpected2, manager_.GetTraits());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001296 const char kExpectedComponents2[] = R"({
1297 "__weave__": { "traits": ["package1", "package2", "package3"] }
1298 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001299 EXPECT_JSON_EQ(kExpectedComponents2, manager_.GetComponents());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001300
1301 // Redefining existing commands.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001302 EXPECT_FALSE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001303
1304 const char kStateDefs1[] = R"({
1305 "package1": {
1306 "prop1": { "type": "string" },
1307 "prop2": { "type": "string" }
1308 },
1309 "package4": {
1310 "prop3": { "type": "string" },
1311 "prop4": { "type": "string" }
1312 }
1313 })";
1314 json = CreateDictionaryValue(kStateDefs1);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001315 EXPECT_TRUE(manager_.AddLegacyStateDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001316 const char kExpectedComponents3[] = R"({
1317 "__weave__": { "traits": ["package1", "package2", "package3", "package4"] }
1318 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001319 EXPECT_JSON_EQ(kExpectedComponents3, manager_.GetComponents());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001320
1321 const char kExpected3[] = R"({
1322 "package1": {
1323 "commands": {
1324 "command1": {
1325 "minimalRole": "user",
1326 "parameters": {"height": {"type": "integer"}}
1327 },
1328 "command2": {
1329 "minimalRole": "owner",
1330 "parameters": {}
1331 }
1332 },
1333 "state": {
1334 "prop1": { "type": "string" },
1335 "prop2": { "type": "string" }
1336 }
1337 },
1338 "package2": {
1339 "commands": {
1340 "command1": { "minimalRole": "user" },
1341 "command2": { "minimalRole": "owner" },
1342 "command3": { "minimalRole": "user" }
1343 }
1344 },
1345 "package3": {
1346 "commands": {
1347 "command1": { "minimalRole": "user" },
1348 "command2": { "minimalRole": "owner" }
1349 }
1350 },
1351 "package4": {
1352 "state": {
1353 "prop3": { "type": "string" },
1354 "prop4": { "type": "string" }
1355 }
1356 }
1357 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001358 EXPECT_JSON_EQ(kExpected3, manager_.GetTraits());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001359 const char kExpectedComponents4[] = R"({
1360 "__weave__": { "traits": ["package1", "package2", "package3", "package4"] }
1361 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001362 EXPECT_JSON_EQ(kExpectedComponents4, manager_.GetComponents());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001363
1364 // Redefining existing commands.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001365 EXPECT_FALSE(manager_.AddLegacyStateDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001366
1367 const char kExpected4[] = R"({
1368 "package1": {
1369 "command1": {
1370 "minimalRole": "user",
1371 "parameters": {"height": {"type": "integer"}}
1372 },
1373 "command2": {
1374 "minimalRole": "owner",
1375 "parameters": {}
1376 }
1377 },
1378 "package2": {
1379 "command1": { "minimalRole": "user" },
1380 "command2": { "minimalRole": "owner" },
1381 "command3": { "minimalRole": "user" }
1382 },
1383 "package3": {
1384 "command1": { "minimalRole": "user" },
1385 "command2": { "minimalRole": "owner" }
1386 }
1387 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001388 EXPECT_JSON_EQ(kExpected4, manager_.GetLegacyCommandDefinitions());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001389}
1390
Vitaly Bukaece713e2015-12-09 10:59:33 -08001391TEST_F(ComponentManagerTest, GetLegacyState) {
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001392 const char kTraits[] = R"({
1393 "trait1": {
1394 "state": {
1395 "prop1": { "type": "string" },
1396 "prop2": { "type": "string" }
1397 }
1398 },
1399 "trait2": {
1400 "state": {
1401 "prop3": { "type": "string" },
1402 "prop4": { "type": "string" }
1403 }
1404 }
1405 })";
1406 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001407 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1408 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
1409 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait2"}, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001410
Vitaly Bukaece713e2015-12-09 10:59:33 -08001411 ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001412 "comp1", R"({"trait1": {"prop1": "foo", "prop2": "bar"}})", nullptr));
Vitaly Bukaece713e2015-12-09 10:59:33 -08001413 ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001414 "comp2", R"({"trait2": {"prop3": "baz", "prop4": "quux"}})", nullptr));
1415
1416 const char kExpected[] = R"({
1417 "trait1": {
1418 "prop1": "foo",
1419 "prop2": "bar"
1420 },
1421 "trait2": {
1422 "prop3": "baz",
1423 "prop4": "quux"
1424 }
1425 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001426 EXPECT_JSON_EQ(kExpected, manager_.GetLegacyState());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001427}
1428
Vitaly Bukaece713e2015-12-09 10:59:33 -08001429TEST_F(ComponentManagerTest, TestMockComponentManager) {
Alex Vakulenkoba981152015-12-05 13:58:22 -08001430 // Check that all the virtual methods are mocked out.
1431 MockComponentManager mock;
1432}
1433
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -08001434} // namespace weave