blob: 63fedacea766da706c40ba3d69ff21acb7dff714 [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;
Vitaly Bukabcd3f6a2016-01-19 17:09:02 -080021using testing::StrictMock;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080022
23namespace {
24
25bool HasTrait(const base::DictionaryValue& comp, const std::string& trait) {
26 const base::ListValue* list = nullptr;
27 if (!comp.GetList("traits", &list))
28 return false;
29 for (const base::Value* item : *list) {
30 std::string value;
31 if (item->GetAsString(&value) && value == trait)
32 return true;
33 }
34 return false;
35}
36
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080037// Creates sample trait/component trees:
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -080038// {
39// "traits": {
40// "t1": {},
41// "t2": {},
42// "t3": {},
43// "t4": {},
44// "t5": {},
45// "t6": {},
46// },
47// "components": {
48// "comp1": {
49// "traits": [ "t1" ],
50// "components": {
51// "comp2": [
52// { "traits": [ "t2" ] },
53// {
54// "traits": [ "t3" ],
55// "components": {
56// "comp3": {
57// "traits": [ "t4" ],
58// "components": {
59// "comp4": {
60// "traits": [ "t5", "t6" ]
61// }
62// }
63// }
64// }
65// }
66// ],
67// }
68// }
69// }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080070// }
Vitaly Bukaece713e2015-12-09 10:59:33 -080071class ComponentManagerTest : public ::testing::Test {
72 protected:
Vitaly Bukabcd3f6a2016-01-19 17:09:02 -080073 void SetUp() override {
74 EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(base::Time::Now()));
75 }
76
Vitaly Bukaece713e2015-12-09 10:59:33 -080077 void CreateTestComponentTree(ComponentManager* manager) {
78 const char kTraits[] =
79 R"({"t1":{},"t2":{},"t3":{},"t4":{},"t5":{},"t6":{}})";
80 auto json = CreateDictionaryValue(kTraits);
81 ASSERT_TRUE(manager->LoadTraits(*json, nullptr));
82 EXPECT_TRUE(manager->AddComponent("", "comp1", {"t1"}, nullptr));
83 EXPECT_TRUE(
84 manager->AddComponentArrayItem("comp1", "comp2", {"t2"}, nullptr));
85 EXPECT_TRUE(
86 manager->AddComponentArrayItem("comp1", "comp2", {"t3"}, nullptr));
87 EXPECT_TRUE(
88 manager->AddComponent("comp1.comp2[1]", "comp3", {"t4"}, nullptr));
89 EXPECT_TRUE(manager->AddComponent("comp1.comp2[1].comp3", "comp4",
90 {"t5", "t6"}, nullptr));
91 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080092
Vitaly Bukabcd3f6a2016-01-19 17:09:02 -080093 StrictMock<test::MockClock> clock_;
Vitaly Bukaece713e2015-12-09 10:59:33 -080094 ComponentManagerImpl manager_{&clock_};
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080095};
96
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080097} // anonymous namespace
98
Vitaly Bukaece713e2015-12-09 10:59:33 -080099TEST_F(ComponentManagerTest, Empty) {
100 EXPECT_TRUE(manager_.GetTraits().empty());
101 EXPECT_TRUE(manager_.GetComponents().empty());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800102}
103
Vitaly Bukaece713e2015-12-09 10:59:33 -0800104TEST_F(ComponentManagerTest, LoadTraits) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800105 const char kTraits[] = R"({
106 "trait1": {
107 "commands": {
108 "command1": {
109 "minimalRole": "user",
110 "parameters": {"height": {"type": "integer"}}
111 }
112 },
113 "state": {
114 "property1": {"type": "boolean"}
115 }
116 },
117 "trait2": {
118 "state": {
119 "property2": {"type": "string"}
120 }
121 }
122 })";
123 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800124 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
125 EXPECT_JSON_EQ(kTraits, manager_.GetTraits());
126 EXPECT_TRUE(manager_.GetComponents().empty());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800127}
128
Vitaly Bukaece713e2015-12-09 10:59:33 -0800129TEST_F(ComponentManagerTest, LoadTraitsDuplicateIdentical) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800130 const char kTraits1[] = R"({
131 "trait1": {
132 "commands": {
133 "command1": {
134 "minimalRole": "user",
135 "parameters": {"height": {"type": "integer"}}
136 }
137 },
138 "state": {
139 "property1": {"type": "boolean"}
140 }
141 },
142 "trait2": {
143 "state": {
144 "property2": {"type": "string"}
145 }
146 }
147 })";
148 auto json = CreateDictionaryValue(kTraits1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800149 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800150 const char kTraits2[] = R"({
151 "trait1": {
152 "commands": {
153 "command1": {
154 "minimalRole": "user",
155 "parameters": {"height": {"type": "integer"}}
156 }
157 },
158 "state": {
159 "property1": {"type": "boolean"}
160 }
161 },
162 "trait3": {
163 "state": {
164 "property3": {"type": "string"}
165 }
166 }
167 })";
168 json = CreateDictionaryValue(kTraits2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800169 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800170 const char kExpected[] = R"({
171 "trait1": {
172 "commands": {
173 "command1": {
174 "minimalRole": "user",
175 "parameters": {"height": {"type": "integer"}}
176 }
177 },
178 "state": {
179 "property1": {"type": "boolean"}
180 }
181 },
182 "trait2": {
183 "state": {
184 "property2": {"type": "string"}
185 }
186 },
187 "trait3": {
188 "state": {
189 "property3": {"type": "string"}
190 }
191 }
192 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800193 EXPECT_JSON_EQ(kExpected, manager_.GetTraits());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800194}
195
Vitaly Bukaece713e2015-12-09 10:59:33 -0800196TEST_F(ComponentManagerTest, LoadTraitsDuplicateOverride) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800197 const char kTraits1[] = R"({
198 "trait1": {
199 "commands": {
200 "command1": {
201 "minimalRole": "user",
202 "parameters": {"height": {"type": "integer"}}
203 }
204 },
205 "state": {
206 "property1": {"type": "boolean"}
207 }
208 },
209 "trait2": {
210 "state": {
211 "property2": {"type": "string"}
212 }
213 }
214 })";
215 auto json = CreateDictionaryValue(kTraits1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800216 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800217 const char kTraits2[] = R"({
218 "trait1": {
219 "commands": {
220 "command1": {
221 "minimalRole": "user",
222 "parameters": {"height": {"type": "string"}}
223 }
224 },
225 "state": {
226 "property1": {"type": "boolean"}
227 }
228 },
229 "trait3": {
230 "state": {
231 "property3": {"type": "string"}
232 }
233 }
234 })";
235 json = CreateDictionaryValue(kTraits2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800236 EXPECT_FALSE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800237}
238
Vitaly Bukaece713e2015-12-09 10:59:33 -0800239TEST_F(ComponentManagerTest, AddTraitDefChangedCallback) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800240 int count = 0;
241 int count2 = 0;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800242 manager_.AddTraitDefChangedCallback(base::Bind([&count]() { count++; }));
243 manager_.AddTraitDefChangedCallback(base::Bind([&count2]() { count2++; }));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800244 EXPECT_EQ(1, count);
245 EXPECT_EQ(1, count2);
246 // New definitions.
247 const char kTraits1[] = R"({
248 "trait1": {
249 "state": {
250 "property1": {"type": "boolean"}
251 }
252 },
253 "trait2": {
254 "state": {
255 "property2": {"type": "string"}
256 }
257 }
258 })";
259 auto json = CreateDictionaryValue(kTraits1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800260 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800261 EXPECT_EQ(2, count);
262 // Duplicate definition, shouldn't call the callback.
263 const char kTraits2[] = R"({
264 "trait1": {
265 "state": {
266 "property1": {"type": "boolean"}
267 }
268 }
269 })";
270 json = CreateDictionaryValue(kTraits2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800271 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800272 EXPECT_EQ(2, count);
273 // New definition, should call the callback now.
274 const char kTraits3[] = R"({
275 "trait3": {
276 "state": {
277 "property3": {"type": "string"}
278 }
279 }
280 })";
281 json = CreateDictionaryValue(kTraits3);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800282 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800283 EXPECT_EQ(3, count);
284 // Wrong definition, shouldn't call the callback.
285 const char kTraits4[] = R"({
286 "trait4": "foo"
287 })";
288 json = CreateDictionaryValue(kTraits4);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800289 EXPECT_FALSE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800290 EXPECT_EQ(3, count);
291 // Make sure both callbacks were called the same number of times.
292 EXPECT_EQ(count2, count);
293}
294
Vitaly Bukaece713e2015-12-09 10:59:33 -0800295TEST_F(ComponentManagerTest, LoadTraitsNotAnObject) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800296 const char kTraits1[] = R"({"trait1": 0})";
297 auto json = CreateDictionaryValue(kTraits1);
298 ErrorPtr error;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800299 EXPECT_FALSE(manager_.LoadTraits(*json, &error));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800300 EXPECT_EQ(errors::commands::kTypeMismatch, error->GetCode());
301}
302
Vitaly Bukaece713e2015-12-09 10:59:33 -0800303TEST_F(ComponentManagerTest, FindTraitDefinition) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800304 const char kTraits[] = R"({
305 "trait1": {
306 "commands": {
307 "command1": {
308 "minimalRole": "user",
309 "parameters": {"height": {"type": "integer"}}
310 }
311 },
312 "state": {
313 "property1": {"type": "boolean"}
314 }
315 },
316 "trait2": {
317 "state": {
318 "property2": {"type": "string"}
319 }
320 }
321 })";
322 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800323 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800324
Vitaly Bukaece713e2015-12-09 10:59:33 -0800325 const base::DictionaryValue* trait = manager_.FindTraitDefinition("trait1");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800326 ASSERT_NE(nullptr, trait);
327 const char kExpected1[] = R"({
328 "commands": {
329 "command1": {
330 "minimalRole": "user",
331 "parameters": {"height": {"type": "integer"}}
332 }
333 },
334 "state": {
335 "property1": {"type": "boolean"}
336 }
337 })";
338 EXPECT_JSON_EQ(kExpected1, *trait);
339
Vitaly Bukaece713e2015-12-09 10:59:33 -0800340 trait = manager_.FindTraitDefinition("trait2");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800341 ASSERT_NE(nullptr, trait);
342 const char kExpected2[] = R"({
343 "state": {
344 "property2": {"type": "string"}
345 }
346 })";
347 EXPECT_JSON_EQ(kExpected2, *trait);
348
Vitaly Bukaece713e2015-12-09 10:59:33 -0800349 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait3"));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800350}
351
Vitaly Bukaece713e2015-12-09 10:59:33 -0800352TEST_F(ComponentManagerTest, FindCommandDefinition) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800353 const char kTraits[] = R"({
354 "trait1": {
355 "commands": {
356 "command1": {
357 "minimalRole": "user",
358 "parameters": {"height": {"type": "integer"}}
359 }
360 }
361 },
362 "trait2": {
363 "commands": {
364 "command1": {
365 "minimalRole": "manager"
366 },
367 "command2": {
368 "minimalRole": "owner"
369 }
370 }
371 }
372 })";
373 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800374 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800375
Vitaly Bukaece713e2015-12-09 10:59:33 -0800376 const auto* cmd_def = manager_.FindCommandDefinition("trait1.command1");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800377 ASSERT_NE(nullptr, cmd_def);
378 const char kExpected1[] = R"({
379 "minimalRole": "user",
380 "parameters": {"height": {"type": "integer"}}
381 })";
382 EXPECT_JSON_EQ(kExpected1, *cmd_def);
383
Vitaly Bukaece713e2015-12-09 10:59:33 -0800384 cmd_def = manager_.FindCommandDefinition("trait2.command1");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800385 ASSERT_NE(nullptr, cmd_def);
386 const char kExpected2[] = R"({
387 "minimalRole": "manager"
388 })";
389 EXPECT_JSON_EQ(kExpected2, *cmd_def);
390
Vitaly Bukaece713e2015-12-09 10:59:33 -0800391 cmd_def = manager_.FindCommandDefinition("trait2.command2");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800392 ASSERT_NE(nullptr, cmd_def);
393 const char kExpected3[] = R"({
394 "minimalRole": "owner"
395 })";
396 EXPECT_JSON_EQ(kExpected3, *cmd_def);
397
Vitaly Bukaece713e2015-12-09 10:59:33 -0800398 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait1.command2"));
399 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait3.command1"));
400 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait"));
401 EXPECT_EQ(nullptr,
402 manager_.FindTraitDefinition("trait1.command1.parameters"));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800403}
404
Vitaly Bukaece713e2015-12-09 10:59:33 -0800405TEST_F(ComponentManagerTest, GetMinimalRole) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800406 const char kTraits[] = R"({
407 "trait1": {
408 "commands": {
409 "command1": { "minimalRole": "user" },
410 "command2": { "minimalRole": "viewer" }
411 }
412 },
413 "trait2": {
414 "commands": {
415 "command1": { "minimalRole": "manager" },
416 "command2": { "minimalRole": "owner" }
417 }
418 }
419 })";
420 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800421 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800422
423 UserRole role;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800424 ASSERT_TRUE(manager_.GetMinimalRole("trait1.command1", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800425 EXPECT_EQ(UserRole::kUser, role);
426
Vitaly Bukaece713e2015-12-09 10:59:33 -0800427 ASSERT_TRUE(manager_.GetMinimalRole("trait1.command2", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800428 EXPECT_EQ(UserRole::kViewer, role);
429
Vitaly Bukaece713e2015-12-09 10:59:33 -0800430 ASSERT_TRUE(manager_.GetMinimalRole("trait2.command1", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800431 EXPECT_EQ(UserRole::kManager, role);
432
Vitaly Bukaece713e2015-12-09 10:59:33 -0800433 ASSERT_TRUE(manager_.GetMinimalRole("trait2.command2", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800434 EXPECT_EQ(UserRole::kOwner, role);
435
Vitaly Bukaece713e2015-12-09 10:59:33 -0800436 EXPECT_FALSE(manager_.GetMinimalRole("trait1.command3", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800437}
438
Vitaly Bukaece713e2015-12-09 10:59:33 -0800439TEST_F(ComponentManagerTest, AddComponent) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800440 const char kTraits[] = R"({"trait1": {}, "trait2": {}, "trait3": {}})";
441 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800442 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
443 EXPECT_TRUE(
444 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
445 EXPECT_TRUE(manager_.AddComponent("", "comp2", {"trait3"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800446 const char kExpected[] = R"({
447 "comp1": {
448 "traits": ["trait1", "trait2"]
449 },
450 "comp2": {
451 "traits": ["trait3"]
452 }
453 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800454 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800455
456 // 'trait4' is undefined, so can't add a component referring to it.
Vitaly Bukaece713e2015-12-09 10:59:33 -0800457 EXPECT_FALSE(manager_.AddComponent("", "comp3", {"trait4"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800458}
459
Vitaly Bukaece713e2015-12-09 10:59:33 -0800460TEST_F(ComponentManagerTest, AddSubComponent) {
461 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
462 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
463 EXPECT_TRUE(manager_.AddComponent("comp1", "comp3", {}, nullptr));
464 EXPECT_TRUE(manager_.AddComponent("comp1.comp2", "comp4", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800465 const char kExpected[] = R"({
466 "comp1": {
467 "traits": [],
468 "components": {
469 "comp2": {
470 "traits": [],
471 "components": {
472 "comp4": {
473 "traits": []
474 }
475 }
476 },
477 "comp3": {
478 "traits": []
479 }
480 }
481 }
482 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800483 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800484}
485
Vitaly Bukaece713e2015-12-09 10:59:33 -0800486TEST_F(ComponentManagerTest, AddComponentArrayItem) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800487 const char kTraits[] = R"({"foo": {}, "bar": {}})";
488 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800489 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800490
Vitaly Bukaece713e2015-12-09 10:59:33 -0800491 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
492 EXPECT_TRUE(
493 manager_.AddComponentArrayItem("comp1", "comp2", {"foo"}, nullptr));
494 EXPECT_TRUE(
495 manager_.AddComponentArrayItem("comp1", "comp2", {"bar"}, nullptr));
496 EXPECT_TRUE(manager_.AddComponent("comp1.comp2[1]", "comp3", {}, nullptr));
497 EXPECT_TRUE(
498 manager_.AddComponent("comp1.comp2[1].comp3", "comp4", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800499 const char kExpected[] = R"({
500 "comp1": {
501 "traits": [],
502 "components": {
503 "comp2": [
504 {
505 "traits": ["foo"]
506 },
507 {
508 "traits": ["bar"],
509 "components": {
510 "comp3": {
511 "traits": [],
512 "components": {
513 "comp4": {
514 "traits": []
515 }
516 }
517 }
518 }
519 }
520 ]
521 }
522 }
523 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800524 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800525}
526
Alex Vakulenkoce850b52016-01-04 09:27:50 -0800527TEST_F(ComponentManagerTest, RemoveComponent) {
528 CreateTestComponentTree(&manager_);
529 EXPECT_TRUE(manager_.RemoveComponent("comp1.comp2[1].comp3", "comp4",
530 nullptr));
531 const char kExpected1[] = R"({
532 "comp1": {
533 "traits": [ "t1" ],
534 "components": {
535 "comp2": [
536 {
537 "traits": [ "t2" ]
538 },
539 {
540 "traits": [ "t3" ],
541 "components": {
542 "comp3": {
543 "traits": [ "t4" ],
544 "components": {}
545 }
546 }
547 }
548 ]
549 }
550 }
551 })";
552 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
553 EXPECT_TRUE(manager_.RemoveComponentArrayItem("comp1", "comp2", 1, nullptr));
554 const char kExpected2[] = R"({
555 "comp1": {
556 "traits": [ "t1" ],
557 "components": {
558 "comp2": [
559 {
560 "traits": [ "t2" ]
561 }
562 ]
563 }
564 }
565 })";
566 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
567}
568
Vitaly Bukaece713e2015-12-09 10:59:33 -0800569TEST_F(ComponentManagerTest, AddComponentExist) {
570 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
571 EXPECT_FALSE(manager_.AddComponent("", "comp1", {}, nullptr));
572 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
573 EXPECT_FALSE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800574}
575
Vitaly Bukaece713e2015-12-09 10:59:33 -0800576TEST_F(ComponentManagerTest, AddComponentDoesNotExist) {
577 EXPECT_FALSE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800578}
579
Vitaly Bukaece713e2015-12-09 10:59:33 -0800580TEST_F(ComponentManagerTest, AddComponentTreeChangedCallback) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800581 int count = 0;
582 int count2 = 0;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800583 manager_.AddComponentTreeChangedCallback(base::Bind([&count]() { count++; }));
584 manager_.AddComponentTreeChangedCallback(
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800585 base::Bind([&count2]() { count2++; }));
586 EXPECT_EQ(1, count);
587 EXPECT_EQ(1, count2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800588 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800589 EXPECT_EQ(2, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800590 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800591 EXPECT_EQ(3, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800592 EXPECT_TRUE(manager_.AddComponent("comp1.comp2", "comp4", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800593 EXPECT_EQ(4, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800594 EXPECT_TRUE(manager_.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800595 EXPECT_EQ(5, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800596 EXPECT_TRUE(manager_.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800597 EXPECT_EQ(6, count);
Alex Vakulenkoce850b52016-01-04 09:27:50 -0800598 EXPECT_TRUE(manager_.RemoveComponentArrayItem("comp1", "comp3", 1, nullptr));
599 EXPECT_EQ(7, count);
600 EXPECT_TRUE(manager_.RemoveComponent("", "comp1", nullptr));
601 EXPECT_EQ(8, count);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800602 // Make sure both callbacks were called the same number of times.
603 EXPECT_EQ(count2, count);
604}
605
Vitaly Bukaece713e2015-12-09 10:59:33 -0800606TEST_F(ComponentManagerTest, FindComponent) {
607 CreateTestComponentTree(&manager_);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800608
Vitaly Bukaece713e2015-12-09 10:59:33 -0800609 const base::DictionaryValue* comp = manager_.FindComponent("comp1", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800610 ASSERT_NE(nullptr, comp);
611 EXPECT_TRUE(HasTrait(*comp, "t1"));
612
Vitaly Bukaece713e2015-12-09 10:59:33 -0800613 comp = manager_.FindComponent("comp1.comp2[0]", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800614 ASSERT_NE(nullptr, comp);
615 EXPECT_TRUE(HasTrait(*comp, "t2"));
616
Vitaly Bukaece713e2015-12-09 10:59:33 -0800617 comp = manager_.FindComponent("comp1.comp2[1]", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800618 ASSERT_NE(nullptr, comp);
619 EXPECT_TRUE(HasTrait(*comp, "t3"));
620
Vitaly Bukaece713e2015-12-09 10:59:33 -0800621 comp = manager_.FindComponent("comp1.comp2[1].comp3", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800622 ASSERT_NE(nullptr, comp);
623 EXPECT_TRUE(HasTrait(*comp, "t4"));
624
Vitaly Bukaece713e2015-12-09 10:59:33 -0800625 comp = manager_.FindComponent("comp1.comp2[1].comp3.comp4", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800626 ASSERT_NE(nullptr, comp);
627 EXPECT_TRUE(HasTrait(*comp, "t5"));
628
629 // Some whitespaces don't hurt.
Vitaly Bukaece713e2015-12-09 10:59:33 -0800630 comp = manager_.FindComponent(" comp1 . comp2 [ \t 1 ] . comp3.comp4 ",
631 nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800632 EXPECT_NE(nullptr, comp);
633
634 // Now check some failure cases.
635 ErrorPtr error;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800636 EXPECT_EQ(nullptr, manager_.FindComponent("", &error));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800637 EXPECT_NE(nullptr, error.get());
638 // 'comp2' doesn't exist:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800639 EXPECT_EQ(nullptr, manager_.FindComponent("comp2", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800640 // 'comp1.comp2' is an array, not a component:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800641 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800642 // 'comp1.comp2[3]' doesn't exist:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800643 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[3]", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800644 // Empty component names:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800645 EXPECT_EQ(nullptr, manager_.FindComponent(".comp2[1]", nullptr));
646 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.[1]", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800647 // Invalid array indices:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800648 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[s]", nullptr));
649 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[-2]", nullptr));
650 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[1e1]", nullptr));
651 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[1", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800652}
653
Vitaly Bukaece713e2015-12-09 10:59:33 -0800654TEST_F(ComponentManagerTest, ParseCommandInstance) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800655 const char kTraits[] = R"({
656 "trait1": {
657 "commands": {
658 "command1": { "minimalRole": "user" },
659 "command2": { "minimalRole": "viewer" }
660 }
661 },
662 "trait2": {
663 "commands": {
664 "command1": { "minimalRole": "manager" },
665 "command2": { "minimalRole": "owner" }
666 }
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800667 },
668 "trait3": {
669 "commands": {
670 "command1": { "minimalRole": "manager" },
671 "command2": { "minimalRole": "owner" }
672 }
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800673 }
674 })";
675 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800676 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
677 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
678 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait2"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800679
680 std::string id;
681 const char kCommand1[] = R"({
682 "name": "trait1.command1",
Alex Vakulenkob736c982015-12-05 14:09:27 -0800683 "id": "1234-12345",
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800684 "component": "comp1",
685 "parameters": {}
686 })";
687 auto command1 = CreateDictionaryValue(kCommand1);
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800688 EXPECT_NE(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800689 manager_.ParseCommandInstance(*command1, Command::Origin::kLocal,
690 UserRole::kUser, &id, nullptr)
691 .get());
Alex Vakulenkob736c982015-12-05 14:09:27 -0800692 EXPECT_EQ("1234-12345", id);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800693 // Not enough access rights
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800694 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800695 manager_.ParseCommandInstance(*command1, Command::Origin::kLocal,
696 UserRole::kViewer, &id, nullptr)
697 .get());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800698
699 const char kCommand2[] = R"({
700 "name": "trait1.command3",
701 "component": "comp1",
702 "parameters": {}
703 })";
704 auto command2 = CreateDictionaryValue(kCommand2);
705 // trait1.command3 doesn't exist
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800706 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800707 manager_.ParseCommandInstance(*command2, Command::Origin::kLocal,
708 UserRole::kOwner, &id, nullptr)
709 .get());
Alex Vakulenkob736c982015-12-05 14:09:27 -0800710 EXPECT_TRUE(id.empty());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800711
712 const char kCommand3[] = R"({
713 "name": "trait2.command1",
714 "component": "comp1",
715 "parameters": {}
716 })";
717 auto command3 = CreateDictionaryValue(kCommand3);
718 // Component comp1 doesn't have trait2.
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800719 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800720 manager_.ParseCommandInstance(*command3, Command::Origin::kLocal,
721 UserRole::kOwner, &id, nullptr)
722 .get());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800723
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800724 // No component specified, find the suitable component
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800725 const char kCommand4[] = R"({
726 "name": "trait1.command1",
727 "parameters": {}
728 })";
729 auto command4 = CreateDictionaryValue(kCommand4);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800730 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800731 *command4, Command::Origin::kLocal, UserRole::kOwner, &id, nullptr);
732 EXPECT_NE(nullptr, command_instance.get());
733 EXPECT_EQ("comp1", command_instance->GetComponent());
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800734
735 const char kCommand5[] = R"({
736 "name": "trait2.command1",
737 "parameters": {}
738 })";
739 auto command5 = CreateDictionaryValue(kCommand5);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800740 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800741 *command5, Command::Origin::kLocal, UserRole::kOwner, &id, nullptr);
742 EXPECT_NE(nullptr, command_instance.get());
743 EXPECT_EQ("comp2", command_instance->GetComponent());
744
745 // Cannot route the command, no component with 'trait3'.
746 const char kCommand6[] = R"({
747 "name": "trait3.command1",
748 "parameters": {}
749 })";
750 auto command6 = CreateDictionaryValue(kCommand6);
751 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800752 manager_.ParseCommandInstance(*command6, Command::Origin::kLocal,
753 UserRole::kOwner, &id, nullptr)
754 .get());
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800755}
756
Vitaly Bukaece713e2015-12-09 10:59:33 -0800757TEST_F(ComponentManagerTest, AddCommand) {
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800758 const char kTraits[] = R"({
759 "trait1": {
760 "commands": {
761 "command1": { "minimalRole": "user" }
762 }
763 }
764 })";
765 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800766 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
767 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800768
769 std::string id;
770 const char kCommand[] = R"({
771 "name": "trait1.command1",
772 "id": "1234-12345",
773 "component": "comp1",
774 "parameters": {}
775 })";
776 auto command = CreateDictionaryValue(kCommand);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800777 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800778 *command, Command::Origin::kLocal, UserRole::kUser, &id, nullptr);
779 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800780 manager_.AddCommand(std::move(command_instance));
781 const auto* queued_command = manager_.FindCommand(id);
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800782 ASSERT_NE(nullptr, queued_command);
783 EXPECT_EQ("trait1.command1", queued_command->GetName());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800784}
785
Vitaly Bukaece713e2015-12-09 10:59:33 -0800786TEST_F(ComponentManagerTest, AddCommandHandler) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800787 const char kTraits[] = R"({
788 "trait1": {
789 "commands": {
790 "command1": { "minimalRole": "user" }
791 }
792 },
793 "trait2": {
794 "commands": {
795 "command2": { "minimalRole": "user" }
796 }
797 }
798 })";
799 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800800 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
801 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
802 ASSERT_TRUE(
803 manager_.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800804
805 std::string last_tags;
806 auto handler = [&last_tags](int tag, const std::weak_ptr<Command>& command) {
807 if (!last_tags.empty())
808 last_tags += ',';
809 last_tags += std::to_string(tag);
810 };
811
Vitaly Bukaece713e2015-12-09 10:59:33 -0800812 manager_.AddCommandHandler("comp1", "trait1.command1",
813 base::Bind(handler, 1));
814 manager_.AddCommandHandler("comp2", "trait1.command1",
815 base::Bind(handler, 2));
816 manager_.AddCommandHandler("comp2", "trait2.command2",
817 base::Bind(handler, 3));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800818 EXPECT_TRUE(last_tags.empty());
819
820 const char kCommand1[] = R"({
821 "name": "trait1.command1",
822 "component": "comp1"
823 })";
824 auto command1 = CreateDictionaryValue(kCommand1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800825 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800826 *command1, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
827 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800828 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800829 EXPECT_EQ("1", last_tags);
830 last_tags.clear();
831
832 const char kCommand2[] = R"({
833 "name": "trait1.command1",
834 "component": "comp2"
835 })";
836 auto command2 = CreateDictionaryValue(kCommand2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800837 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800838 *command2, 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 Vakulenko44c1dbe2015-12-03 15:35:09 -0800841 EXPECT_EQ("2", last_tags);
842 last_tags.clear();
843
844 const char kCommand3[] = R"({
845 "name": "trait2.command2",
846 "component": "comp2",
847 "parameters": {}
848 })";
849 auto command3 = CreateDictionaryValue(kCommand3);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800850 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800851 *command3, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
852 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800853 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800854 EXPECT_EQ("3", last_tags);
855 last_tags.clear();
856}
857
Vitaly Bukaece713e2015-12-09 10:59:33 -0800858TEST_F(ComponentManagerTest, AddDefaultCommandHandler) {
Alex Vakulenko20334332015-12-08 13:19:49 -0800859 const char kTraits[] = R"({
860 "trait1": {
861 "commands": {
862 "command1": { "minimalRole": "user" }
863 }
864 },
865 "trait2": {
866 "commands": {
867 "command2": { "minimalRole": "user" }
868 }
869 }
870 })";
871 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800872 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
873 ASSERT_TRUE(manager_.AddComponent("", "comp", {"trait1", "trait2"}, nullptr));
Alex Vakulenko20334332015-12-08 13:19:49 -0800874
875 int count = 0;
876 auto handler = [&count](int tag, const std::weak_ptr<Command>& command) {
877 count++;
878 };
879
Vitaly Bukaece713e2015-12-09 10:59:33 -0800880 manager_.AddCommandHandler("", "", base::Bind(handler, 1));
Alex Vakulenko20334332015-12-08 13:19:49 -0800881 EXPECT_EQ(0, count);
882
883 const char kCommand1[] = R"({
884 "name": "trait1.command1",
885 "component": "comp"
886 })";
887 auto command1 = CreateDictionaryValue(kCommand1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800888 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenko20334332015-12-08 13:19:49 -0800889 *command1, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
890 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800891 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko20334332015-12-08 13:19:49 -0800892 EXPECT_EQ(1, count);
893
894 const char kCommand2[] = R"({
895 "name": "trait2.command2",
896 "component": "comp"
897 })";
898 auto command2 = CreateDictionaryValue(kCommand2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800899 command_instance = manager_.ParseCommandInstance(
Alex Vakulenko20334332015-12-08 13:19:49 -0800900 *command2, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
901 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800902 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko20334332015-12-08 13:19:49 -0800903 EXPECT_EQ(2, count);
904}
905
Vitaly Bukaece713e2015-12-09 10:59:33 -0800906TEST_F(ComponentManagerTest, SetStateProperties) {
907 CreateTestComponentTree(&manager_);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800908
909 const char kState1[] = R"({"t1": {"p1": 0, "p2": "foo"}})";
910 auto state1 = CreateDictionaryValue(kState1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800911 ASSERT_TRUE(manager_.SetStateProperties("comp1", *state1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800912 const char kExpected1[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800913 "comp1": {
914 "traits": [ "t1" ],
915 "state": {"t1": {"p1": 0, "p2": "foo"}},
916 "components": {
917 "comp2": [
918 {
919 "traits": [ "t2" ]
920 },
921 {
922 "traits": [ "t3" ],
923 "components": {
924 "comp3": {
925 "traits": [ "t4" ],
926 "components": {
927 "comp4": {
928 "traits": [ "t5", "t6" ]
929 }
930 }
931 }
932 }
933 }
934 ]
935 }
936 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800937 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800938 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800939
940 const char kState2[] = R"({"t1": {"p1": {"bar": "baz"}}})";
941 auto state2 = CreateDictionaryValue(kState2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800942 ASSERT_TRUE(manager_.SetStateProperties("comp1", *state2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800943
944 const char kExpected2[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800945 "comp1": {
946 "traits": [ "t1" ],
947 "state": {"t1": {"p1": {"bar": "baz"}, "p2": "foo"}},
948 "components": {
949 "comp2": [
950 {
951 "traits": [ "t2" ]
952 },
953 {
954 "traits": [ "t3" ],
955 "components": {
956 "comp3": {
957 "traits": [ "t4" ],
958 "components": {
959 "comp4": {
960 "traits": [ "t5", "t6" ]
961 }
962 }
963 }
964 }
965 }
966 ]
967 }
968 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800969 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800970 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800971
972 const char kState3[] = R"({"t5": {"p1": 1}})";
973 auto state3 = CreateDictionaryValue(kState3);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800974 ASSERT_TRUE(manager_.SetStateProperties("comp1.comp2[1].comp3.comp4", *state3,
975 nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800976
977 const char kExpected3[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800978 "comp1": {
979 "traits": [ "t1" ],
980 "state": {"t1": {"p1": {"bar": "baz"}, "p2": "foo"}},
981 "components": {
982 "comp2": [
983 {
984 "traits": [ "t2" ]
985 },
986 {
987 "traits": [ "t3" ],
988 "components": {
989 "comp3": {
990 "traits": [ "t4" ],
991 "components": {
992 "comp4": {
993 "traits": [ "t5", "t6" ],
994 "state": { "t5": { "p1": 1 } }
995 }
996 }
997 }
998 }
999 }
1000 ]
1001 }
1002 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001003 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001004 EXPECT_JSON_EQ(kExpected3, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001005}
1006
Vitaly Bukaece713e2015-12-09 10:59:33 -08001007TEST_F(ComponentManagerTest, SetStatePropertiesFromJson) {
1008 CreateTestComponentTree(&manager_);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001009
Vitaly Bukaece713e2015-12-09 10:59:33 -08001010 ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
Vitaly Buka34668e72015-12-15 14:46:47 -08001011 "comp1.comp2[1].comp3.comp4",
1012 R"({"t5": {"p1": 3}, "t6": {"p2": 5}})", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001013
1014 const char kExpected[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001015 "comp1": {
1016 "traits": [ "t1" ],
1017 "components": {
1018 "comp2": [
1019 {
1020 "traits": [ "t2" ]
1021 },
1022 {
1023 "traits": [ "t3" ],
1024 "components": {
1025 "comp3": {
1026 "traits": [ "t4" ],
1027 "components": {
1028 "comp4": {
1029 "traits": [ "t5", "t6" ],
1030 "state": {
1031 "t5": { "p1": 3 },
1032 "t6": { "p2": 5 }
1033 }
1034 }
1035 }
1036 }
1037 }
1038 }
1039 ]
1040 }
1041 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001042 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001043 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001044}
1045
Vitaly Bukaece713e2015-12-09 10:59:33 -08001046TEST_F(ComponentManagerTest, SetGetStateProperty) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001047 const char kTraits[] = R"({
1048 "trait1": {
1049 "state": {
1050 "prop1": { "type": "string" },
1051 "prop2": { "type": "integer" }
1052 }
1053 },
1054 "trait2": {
1055 "state": {
1056 "prop3": { "type": "string" },
1057 "prop4": { "type": "string" }
1058 }
1059 }
1060 })";
1061 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001062 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1063 ASSERT_TRUE(
1064 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001065
1066 base::StringValue p1("foo");
Vitaly Bukaece713e2015-12-09 10:59:33 -08001067 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001068
1069 const char kExpected1[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001070 "comp1": {
1071 "traits": [ "trait1", "trait2" ],
1072 "state": {
1073 "trait1": { "prop1": "foo" }
1074 }
1075 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001076 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001077 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001078
1079 base::FundamentalValue p2(2);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001080 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait2.prop3", p2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001081
1082 const char kExpected2[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001083 "comp1": {
1084 "traits": [ "trait1", "trait2" ],
1085 "state": {
1086 "trait1": { "prop1": "foo" },
1087 "trait2": { "prop3": 2 }
1088 }
1089 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001090 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001091 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001092 // Just the package name without property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001093 EXPECT_FALSE(manager_.SetStateProperty("comp1", "trait2", p2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001094
Vitaly Bukaece713e2015-12-09 10:59:33 -08001095 const base::Value* value =
1096 manager_.GetStateProperty("comp1", "trait1.prop1", nullptr);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001097 ASSERT_NE(nullptr, value);
1098 EXPECT_TRUE(p1.Equals(value));
Vitaly Bukaece713e2015-12-09 10:59:33 -08001099 value = manager_.GetStateProperty("comp1", "trait2.prop3", nullptr);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001100 ASSERT_NE(nullptr, value);
1101 EXPECT_TRUE(p2.Equals(value));
1102
1103 // Non-existing property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001104 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp1", "trait2.p", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001105 // Non-existing component
Vitaly Bukaece713e2015-12-09 10:59:33 -08001106 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp2", "trait.prop", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001107 // Just the package name without property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001108 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp1", "trait2", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001109}
1110
Vitaly Bukaece713e2015-12-09 10:59:33 -08001111TEST_F(ComponentManagerTest, AddStateChangedCallback) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001112 const char kTraits[] = R"({
1113 "trait1": {
1114 "state": {
1115 "prop1": { "type": "string" },
1116 "prop2": { "type": "string" }
1117 }
1118 }
1119 })";
1120 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001121 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1122 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001123
1124 int count = 0;
1125 int count2 = 0;
Vitaly Bukaece713e2015-12-09 10:59:33 -08001126 manager_.AddStateChangedCallback(base::Bind([&count]() { count++; }));
1127 manager_.AddStateChangedCallback(base::Bind([&count2]() { count2++; }));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001128 EXPECT_EQ(1, count);
1129 EXPECT_EQ(1, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001130 EXPECT_EQ(0u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001131
1132 base::StringValue p1("foo");
Vitaly Bukaece713e2015-12-09 10:59:33 -08001133 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001134 EXPECT_EQ(2, count);
1135 EXPECT_EQ(2, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001136 EXPECT_EQ(1u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001137
Vitaly Bukaece713e2015-12-09 10:59:33 -08001138 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001139 EXPECT_EQ(3, count);
1140 EXPECT_EQ(3, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001141 EXPECT_EQ(2u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001142
1143 // Fail - no component.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001144 ASSERT_FALSE(manager_.SetStateProperty("comp2", "trait1.prop2", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001145 EXPECT_EQ(3, count);
1146 EXPECT_EQ(3, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001147 EXPECT_EQ(2u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001148}
1149
Vitaly Bukaece713e2015-12-09 10:59:33 -08001150TEST_F(ComponentManagerTest, ComponentStateUpdates) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001151 const char kTraits[] = R"({
1152 "trait1": {
1153 "state": {
1154 "prop1": { "type": "string" },
1155 "prop2": { "type": "string" }
1156 }
1157 },
1158 "trait2": {
1159 "state": {
1160 "prop3": { "type": "string" },
1161 "prop4": { "type": "string" }
1162 }
1163 }
1164 })";
1165 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001166 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1167 ASSERT_TRUE(
1168 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
1169 ASSERT_TRUE(
1170 manager_.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001171
1172 std::vector<ComponentManager::UpdateID> updates1;
1173 auto callback1 = [&updates1](ComponentManager::UpdateID id) {
1174 updates1.push_back(id);
1175 };
1176 // State change queue is empty, callback should be called immediately.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001177 auto token1 = manager_.AddServerStateUpdatedCallback(base::Bind(callback1));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001178 ASSERT_EQ(1u, updates1.size());
Vitaly Bukaece713e2015-12-09 10:59:33 -08001179 EXPECT_EQ(manager_.GetLastStateChangeId(), updates1.front());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001180 updates1.clear();
1181
1182 base::StringValue foo("foo");
1183 base::Time time1 = base::Time::Now();
Vitaly Bukaece713e2015-12-09 10:59:33 -08001184 EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(time1));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001185 // These three updates should be grouped into two separate state change queue
1186 // items, since they all happen at the same time, but for two different
1187 // components.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001188 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", foo, nullptr));
1189 ASSERT_TRUE(manager_.SetStateProperty("comp2", "trait2.prop3", foo, nullptr));
1190 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", foo, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001191
1192 std::vector<ComponentManager::UpdateID> updates2;
1193 auto callback2 = [&updates2](ComponentManager::UpdateID id) {
1194 updates2.push_back(id);
1195 };
1196 // State change queue is not empty, so callback will be called later.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001197 auto token2 = manager_.AddServerStateUpdatedCallback(base::Bind(callback2));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001198 EXPECT_TRUE(updates2.empty());
1199
1200 base::StringValue bar("bar");
1201 base::Time time2 = time1 + base::TimeDelta::FromSeconds(1);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001202 EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(time2));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001203 // Two more update events (as above) but at |time2|.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001204 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", bar, nullptr));
1205 ASSERT_TRUE(manager_.SetStateProperty("comp2", "trait2.prop3", bar, nullptr));
1206 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", bar, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001207
Vitaly Bukaece713e2015-12-09 10:59:33 -08001208 auto snapshot = manager_.GetAndClearRecordedStateChanges();
1209 EXPECT_EQ(manager_.GetLastStateChangeId(), snapshot.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001210 ASSERT_EQ(4u, snapshot.state_changes.size());
1211
1212 EXPECT_EQ("comp1", snapshot.state_changes[0].component);
1213 EXPECT_EQ(time1, snapshot.state_changes[0].timestamp);
1214 EXPECT_JSON_EQ(R"({"trait1":{"prop1":"foo","prop2":"foo"}})",
1215 *snapshot.state_changes[0].changed_properties);
1216
1217 EXPECT_EQ("comp2", snapshot.state_changes[1].component);
1218 EXPECT_EQ(time1, snapshot.state_changes[1].timestamp);
1219 EXPECT_JSON_EQ(R"({"trait2":{"prop3":"foo"}})",
1220 *snapshot.state_changes[1].changed_properties);
1221
1222 EXPECT_EQ("comp1", snapshot.state_changes[2].component);
1223 EXPECT_EQ(time2, snapshot.state_changes[2].timestamp);
1224 EXPECT_JSON_EQ(R"({"trait1":{"prop1":"bar","prop2":"bar"}})",
1225 *snapshot.state_changes[2].changed_properties);
1226
1227 EXPECT_EQ("comp2", snapshot.state_changes[3].component);
1228 EXPECT_EQ(time2, snapshot.state_changes[3].timestamp);
1229 EXPECT_JSON_EQ(R"({"trait2":{"prop3":"bar"}})",
1230 *snapshot.state_changes[3].changed_properties);
1231
1232 // Make sure previous GetAndClearRecordedStateChanges() clears the queue.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001233 auto snapshot2 = manager_.GetAndClearRecordedStateChanges();
1234 EXPECT_EQ(manager_.GetLastStateChangeId(), snapshot2.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001235 EXPECT_TRUE(snapshot2.state_changes.empty());
1236
1237 // Now indicate that we have update the changes on the server.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001238 manager_.NotifyStateUpdatedOnServer(snapshot.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001239 ASSERT_EQ(1u, updates1.size());
1240 EXPECT_EQ(snapshot.update_id, updates1.front());
1241 ASSERT_EQ(1u, updates2.size());
1242 EXPECT_EQ(snapshot.update_id, updates2.front());
1243}
1244
Vitaly Bukaece713e2015-12-09 10:59:33 -08001245TEST_F(ComponentManagerTest, FindComponentWithTrait) {
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001246 const char kTraits[] = R"({
1247 "trait1": {},
1248 "trait2": {},
1249 "trait3": {}
1250 })";
1251 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001252 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1253 ASSERT_TRUE(
1254 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
1255 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait3"}, nullptr));
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001256
Vitaly Bukaece713e2015-12-09 10:59:33 -08001257 EXPECT_EQ("comp1", manager_.FindComponentWithTrait("trait1"));
1258 EXPECT_EQ("comp1", manager_.FindComponentWithTrait("trait2"));
1259 EXPECT_EQ("comp2", manager_.FindComponentWithTrait("trait3"));
1260 EXPECT_EQ("", manager_.FindComponentWithTrait("trait4"));
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001261}
1262
Vitaly Bukaece713e2015-12-09 10:59:33 -08001263TEST_F(ComponentManagerTest, AddLegacyCommandAndStateDefinitions) {
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001264 const char kCommandDefs1[] = R"({
1265 "package1": {
1266 "command1": {
1267 "minimalRole": "user",
1268 "parameters": {"height": {"type": "integer"}}
1269 },
1270 "command2": {
1271 "minimalRole": "owner",
1272 "parameters": {}
1273 }
1274 },
1275 "package2": {
1276 "command1": { "minimalRole": "user" },
1277 "command2": { "minimalRole": "owner" }
1278 }
1279 })";
1280 auto json = CreateDictionaryValue(kCommandDefs1);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001281 EXPECT_TRUE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001282 const char kExpected1[] = R"({
1283 "package1": {
1284 "commands": {
1285 "command1": {
1286 "minimalRole": "user",
1287 "parameters": {"height": {"type": "integer"}}
1288 },
1289 "command2": {
1290 "minimalRole": "owner",
1291 "parameters": {}
1292 }
1293 }
1294 },
1295 "package2": {
1296 "commands": {
1297 "command1": { "minimalRole": "user" },
1298 "command2": { "minimalRole": "owner" }
1299 }
1300 }
1301 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001302 EXPECT_JSON_EQ(kExpected1, manager_.GetTraits());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001303 const char kExpectedComponents1[] = R"({
1304 "__weave__": { "traits": ["package1", "package2"] }
1305 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001306 EXPECT_JSON_EQ(kExpectedComponents1, manager_.GetComponents());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001307
1308 const char kCommandDefs2[] = R"({
1309 "package2": {
1310 "command3": { "minimalRole": "user" }
1311 },
1312 "package3": {
1313 "command1": { "minimalRole": "user" },
1314 "command2": { "minimalRole": "owner" }
1315 }
1316 })";
1317 json = CreateDictionaryValue(kCommandDefs2);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001318 EXPECT_TRUE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001319 const char kExpected2[] = R"({
1320 "package1": {
1321 "commands": {
1322 "command1": {
1323 "minimalRole": "user",
1324 "parameters": {"height": {"type": "integer"}}
1325 },
1326 "command2": {
1327 "minimalRole": "owner",
1328 "parameters": {}
1329 }
1330 }
1331 },
1332 "package2": {
1333 "commands": {
1334 "command1": { "minimalRole": "user" },
1335 "command2": { "minimalRole": "owner" },
1336 "command3": { "minimalRole": "user" }
1337 }
1338 },
1339 "package3": {
1340 "commands": {
1341 "command1": { "minimalRole": "user" },
1342 "command2": { "minimalRole": "owner" }
1343 }
1344 }
1345 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001346 EXPECT_JSON_EQ(kExpected2, manager_.GetTraits());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001347 const char kExpectedComponents2[] = R"({
1348 "__weave__": { "traits": ["package1", "package2", "package3"] }
1349 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001350 EXPECT_JSON_EQ(kExpectedComponents2, manager_.GetComponents());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001351
1352 // Redefining existing commands.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001353 EXPECT_FALSE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001354
1355 const char kStateDefs1[] = R"({
1356 "package1": {
1357 "prop1": { "type": "string" },
1358 "prop2": { "type": "string" }
1359 },
1360 "package4": {
1361 "prop3": { "type": "string" },
1362 "prop4": { "type": "string" }
1363 }
1364 })";
1365 json = CreateDictionaryValue(kStateDefs1);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001366 EXPECT_TRUE(manager_.AddLegacyStateDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001367 const char kExpectedComponents3[] = R"({
1368 "__weave__": { "traits": ["package1", "package2", "package3", "package4"] }
1369 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001370 EXPECT_JSON_EQ(kExpectedComponents3, manager_.GetComponents());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001371
1372 const char kExpected3[] = R"({
1373 "package1": {
1374 "commands": {
1375 "command1": {
1376 "minimalRole": "user",
1377 "parameters": {"height": {"type": "integer"}}
1378 },
1379 "command2": {
1380 "minimalRole": "owner",
1381 "parameters": {}
1382 }
1383 },
1384 "state": {
1385 "prop1": { "type": "string" },
1386 "prop2": { "type": "string" }
1387 }
1388 },
1389 "package2": {
1390 "commands": {
1391 "command1": { "minimalRole": "user" },
1392 "command2": { "minimalRole": "owner" },
1393 "command3": { "minimalRole": "user" }
1394 }
1395 },
1396 "package3": {
1397 "commands": {
1398 "command1": { "minimalRole": "user" },
1399 "command2": { "minimalRole": "owner" }
1400 }
1401 },
1402 "package4": {
1403 "state": {
1404 "prop3": { "type": "string" },
1405 "prop4": { "type": "string" }
1406 }
1407 }
1408 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001409 EXPECT_JSON_EQ(kExpected3, manager_.GetTraits());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001410 const char kExpectedComponents4[] = R"({
1411 "__weave__": { "traits": ["package1", "package2", "package3", "package4"] }
1412 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001413 EXPECT_JSON_EQ(kExpectedComponents4, manager_.GetComponents());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001414
1415 // Redefining existing commands.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001416 EXPECT_FALSE(manager_.AddLegacyStateDefinitions(*json, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001417
1418 const char kExpected4[] = R"({
1419 "package1": {
1420 "command1": {
1421 "minimalRole": "user",
1422 "parameters": {"height": {"type": "integer"}}
1423 },
1424 "command2": {
1425 "minimalRole": "owner",
1426 "parameters": {}
1427 }
1428 },
1429 "package2": {
1430 "command1": { "minimalRole": "user" },
1431 "command2": { "minimalRole": "owner" },
1432 "command3": { "minimalRole": "user" }
1433 },
1434 "package3": {
1435 "command1": { "minimalRole": "user" },
1436 "command2": { "minimalRole": "owner" }
1437 }
1438 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001439 EXPECT_JSON_EQ(kExpected4, manager_.GetLegacyCommandDefinitions());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001440}
1441
Vitaly Bukaece713e2015-12-09 10:59:33 -08001442TEST_F(ComponentManagerTest, GetLegacyState) {
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001443 const char kTraits[] = R"({
1444 "trait1": {
1445 "state": {
1446 "prop1": { "type": "string" },
1447 "prop2": { "type": "string" }
1448 }
1449 },
1450 "trait2": {
1451 "state": {
1452 "prop3": { "type": "string" },
1453 "prop4": { "type": "string" }
1454 }
1455 }
1456 })";
1457 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001458 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1459 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
1460 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait2"}, nullptr));
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001461
Vitaly Bukaece713e2015-12-09 10:59:33 -08001462 ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001463 "comp1", R"({"trait1": {"prop1": "foo", "prop2": "bar"}})", nullptr));
Vitaly Bukaece713e2015-12-09 10:59:33 -08001464 ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001465 "comp2", R"({"trait2": {"prop3": "baz", "prop4": "quux"}})", nullptr));
1466
1467 const char kExpected[] = R"({
1468 "trait1": {
1469 "prop1": "foo",
1470 "prop2": "bar"
1471 },
1472 "trait2": {
1473 "prop3": "baz",
1474 "prop4": "quux"
1475 }
1476 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001477 EXPECT_JSON_EQ(kExpected, manager_.GetLegacyState());
Alex Vakulenko6b394d12015-12-05 15:52:54 -08001478}
1479
Vitaly Bukaece713e2015-12-09 10:59:33 -08001480TEST_F(ComponentManagerTest, TestMockComponentManager) {
Alex Vakulenkoba981152015-12-05 13:58:22 -08001481 // Check that all the virtual methods are mocked out.
1482 MockComponentManager mock;
1483}
1484
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -08001485} // namespace weave