blob: 180baf083fe94470bc11efd3196f7f8a7dd8e6d2 [file] [log] [blame]
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -08001// Copyright 2015 The Weave Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Alex Vakulenkoba981152015-12-05 13:58:22 -08005#include "src/component_manager_impl.h"
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -08006
7#include <map>
8
9#include <gtest/gtest.h>
Alex Vakulenko98d1fee2016-02-01 12:25:21 -080010#include <weave/provider/test/fake_task_runner.h>
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080011#include <weave/test/unittest_utils.h>
12
13#include "src/bind_lambda.h"
14#include "src/commands/schema_constants.h"
Vitaly Buka012cd982016-02-22 17:18:49 -080015#include "src/test/mock_component_manager.h"
Vitaly Bukaece713e2015-12-09 10:59:33 -080016#include "src/test/mock_clock.h"
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080017
18namespace weave {
19
20using test::CreateDictionaryValue;
Vitaly Bukaece713e2015-12-09 10:59:33 -080021using testing::Return;
Vitaly Bukabcd3f6a2016-01-19 17:09:02 -080022using testing::StrictMock;
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080023
24namespace {
25
26bool HasTrait(const base::DictionaryValue& comp, const std::string& trait) {
27 const base::ListValue* list = nullptr;
28 if (!comp.GetList("traits", &list))
29 return false;
Luis Hector Chavez17f710e2016-07-18 16:08:56 -070030 for (const auto& item : *list) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080031 std::string value;
32 if (item->GetAsString(&value) && value == trait)
33 return true;
34 }
35 return false;
36}
37
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080038// Creates sample trait/component trees:
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -080039// {
40// "traits": {
41// "t1": {},
42// "t2": {},
43// "t3": {},
44// "t4": {},
45// "t5": {},
46// "t6": {},
47// },
48// "components": {
49// "comp1": {
50// "traits": [ "t1" ],
51// "components": {
52// "comp2": [
53// { "traits": [ "t2" ] },
54// {
55// "traits": [ "t3" ],
56// "components": {
57// "comp3": {
58// "traits": [ "t4" ],
59// "components": {
60// "comp4": {
61// "traits": [ "t5", "t6" ]
62// }
63// }
64// }
65// }
66// }
67// ],
68// }
69// }
70// }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080071// }
Vitaly Bukaece713e2015-12-09 10:59:33 -080072class ComponentManagerTest : public ::testing::Test {
73 protected:
Vitaly Bukabcd3f6a2016-01-19 17:09:02 -080074 void SetUp() override {
75 EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(base::Time::Now()));
76 }
77
Vitaly Bukaece713e2015-12-09 10:59:33 -080078 void CreateTestComponentTree(ComponentManager* manager) {
79 const char kTraits[] =
80 R"({"t1":{},"t2":{},"t3":{},"t4":{},"t5":{},"t6":{}})";
81 auto json = CreateDictionaryValue(kTraits);
82 ASSERT_TRUE(manager->LoadTraits(*json, nullptr));
83 EXPECT_TRUE(manager->AddComponent("", "comp1", {"t1"}, nullptr));
84 EXPECT_TRUE(
85 manager->AddComponentArrayItem("comp1", "comp2", {"t2"}, nullptr));
86 EXPECT_TRUE(
87 manager->AddComponentArrayItem("comp1", "comp2", {"t3"}, nullptr));
88 EXPECT_TRUE(
89 manager->AddComponent("comp1.comp2[1]", "comp3", {"t4"}, nullptr));
90 EXPECT_TRUE(manager->AddComponent("comp1.comp2[1].comp3", "comp4",
91 {"t5", "t6"}, nullptr));
92 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080093
Alex Vakulenko98d1fee2016-02-01 12:25:21 -080094 StrictMock<provider::test::FakeTaskRunner> task_runner_;
Vitaly Bukabcd3f6a2016-01-19 17:09:02 -080095 StrictMock<test::MockClock> clock_;
Alex Vakulenko98d1fee2016-02-01 12:25:21 -080096 ComponentManagerImpl manager_{&task_runner_, &clock_};
Alex Vakulenko7b588fc2015-12-04 16:03:59 -080097};
98
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -080099} // anonymous namespace
100
Vitaly Bukaece713e2015-12-09 10:59:33 -0800101TEST_F(ComponentManagerTest, Empty) {
102 EXPECT_TRUE(manager_.GetTraits().empty());
103 EXPECT_TRUE(manager_.GetComponents().empty());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800104}
105
Vitaly Bukaece713e2015-12-09 10:59:33 -0800106TEST_F(ComponentManagerTest, LoadTraits) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800107 const char kTraits[] = R"({
108 "trait1": {
109 "commands": {
110 "command1": {
111 "minimalRole": "user",
112 "parameters": {"height": {"type": "integer"}}
113 }
114 },
115 "state": {
116 "property1": {"type": "boolean"}
117 }
118 },
119 "trait2": {
120 "state": {
121 "property2": {"type": "string"}
122 }
123 }
124 })";
125 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800126 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
127 EXPECT_JSON_EQ(kTraits, manager_.GetTraits());
128 EXPECT_TRUE(manager_.GetComponents().empty());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800129}
130
Vitaly Bukaece713e2015-12-09 10:59:33 -0800131TEST_F(ComponentManagerTest, LoadTraitsDuplicateIdentical) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800132 const char kTraits1[] = R"({
133 "trait1": {
134 "commands": {
135 "command1": {
136 "minimalRole": "user",
137 "parameters": {"height": {"type": "integer"}}
138 }
139 },
140 "state": {
141 "property1": {"type": "boolean"}
142 }
143 },
144 "trait2": {
145 "state": {
146 "property2": {"type": "string"}
147 }
148 }
149 })";
150 auto json = CreateDictionaryValue(kTraits1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800151 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800152 const char kTraits2[] = R"({
153 "trait1": {
154 "commands": {
155 "command1": {
156 "minimalRole": "user",
157 "parameters": {"height": {"type": "integer"}}
158 }
159 },
160 "state": {
161 "property1": {"type": "boolean"}
162 }
163 },
164 "trait3": {
165 "state": {
166 "property3": {"type": "string"}
167 }
168 }
169 })";
170 json = CreateDictionaryValue(kTraits2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800171 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800172 const char kExpected[] = R"({
173 "trait1": {
174 "commands": {
175 "command1": {
176 "minimalRole": "user",
177 "parameters": {"height": {"type": "integer"}}
178 }
179 },
180 "state": {
181 "property1": {"type": "boolean"}
182 }
183 },
184 "trait2": {
185 "state": {
186 "property2": {"type": "string"}
187 }
188 },
189 "trait3": {
190 "state": {
191 "property3": {"type": "string"}
192 }
193 }
194 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800195 EXPECT_JSON_EQ(kExpected, manager_.GetTraits());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800196}
197
Vitaly Bukaece713e2015-12-09 10:59:33 -0800198TEST_F(ComponentManagerTest, LoadTraitsDuplicateOverride) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800199 const char kTraits1[] = R"({
200 "trait1": {
201 "commands": {
202 "command1": {
203 "minimalRole": "user",
204 "parameters": {"height": {"type": "integer"}}
205 }
206 },
207 "state": {
208 "property1": {"type": "boolean"}
209 }
210 },
211 "trait2": {
212 "state": {
213 "property2": {"type": "string"}
214 }
215 }
216 })";
217 auto json = CreateDictionaryValue(kTraits1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800218 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800219 const char kTraits2[] = R"({
220 "trait1": {
221 "commands": {
222 "command1": {
223 "minimalRole": "user",
224 "parameters": {"height": {"type": "string"}}
225 }
226 },
227 "state": {
228 "property1": {"type": "boolean"}
229 }
230 },
231 "trait3": {
232 "state": {
233 "property3": {"type": "string"}
234 }
235 }
236 })";
237 json = CreateDictionaryValue(kTraits2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800238 EXPECT_FALSE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800239}
240
Vitaly Bukaece713e2015-12-09 10:59:33 -0800241TEST_F(ComponentManagerTest, AddTraitDefChangedCallback) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800242 int count = 0;
243 int count2 = 0;
Luis Hector Chavez17f710e2016-07-18 16:08:56 -0700244 auto handler = [](int* count) { (*count)++; };
245 manager_.AddTraitDefChangedCallback(
246 base::Bind(handler, base::Unretained(&count)));
247 manager_.AddTraitDefChangedCallback(
248 base::Bind(handler, base::Unretained(&count2)));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800249 EXPECT_EQ(1, count);
250 EXPECT_EQ(1, count2);
251 // New definitions.
252 const char kTraits1[] = R"({
253 "trait1": {
254 "state": {
255 "property1": {"type": "boolean"}
256 }
257 },
258 "trait2": {
259 "state": {
260 "property2": {"type": "string"}
261 }
262 }
263 })";
264 auto json = CreateDictionaryValue(kTraits1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800265 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800266 EXPECT_EQ(2, count);
267 // Duplicate definition, shouldn't call the callback.
268 const char kTraits2[] = R"({
269 "trait1": {
270 "state": {
271 "property1": {"type": "boolean"}
272 }
273 }
274 })";
275 json = CreateDictionaryValue(kTraits2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800276 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800277 EXPECT_EQ(2, count);
278 // New definition, should call the callback now.
279 const char kTraits3[] = R"({
280 "trait3": {
281 "state": {
282 "property3": {"type": "string"}
283 }
284 }
285 })";
286 json = CreateDictionaryValue(kTraits3);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800287 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800288 EXPECT_EQ(3, count);
289 // Wrong definition, shouldn't call the callback.
290 const char kTraits4[] = R"({
291 "trait4": "foo"
292 })";
293 json = CreateDictionaryValue(kTraits4);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800294 EXPECT_FALSE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800295 EXPECT_EQ(3, count);
296 // Make sure both callbacks were called the same number of times.
297 EXPECT_EQ(count2, count);
298}
299
Vitaly Bukaece713e2015-12-09 10:59:33 -0800300TEST_F(ComponentManagerTest, LoadTraitsNotAnObject) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800301 const char kTraits1[] = R"({"trait1": 0})";
302 auto json = CreateDictionaryValue(kTraits1);
303 ErrorPtr error;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800304 EXPECT_FALSE(manager_.LoadTraits(*json, &error));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800305 EXPECT_EQ(errors::commands::kTypeMismatch, error->GetCode());
306}
307
Vitaly Bukaece713e2015-12-09 10:59:33 -0800308TEST_F(ComponentManagerTest, FindTraitDefinition) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800309 const char kTraits[] = R"({
310 "trait1": {
311 "commands": {
312 "command1": {
313 "minimalRole": "user",
314 "parameters": {"height": {"type": "integer"}}
315 }
316 },
317 "state": {
318 "property1": {"type": "boolean"}
319 }
320 },
321 "trait2": {
322 "state": {
323 "property2": {"type": "string"}
324 }
325 }
326 })";
327 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800328 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800329
Vitaly Bukaece713e2015-12-09 10:59:33 -0800330 const base::DictionaryValue* trait = manager_.FindTraitDefinition("trait1");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800331 ASSERT_NE(nullptr, trait);
332 const char kExpected1[] = R"({
333 "commands": {
334 "command1": {
335 "minimalRole": "user",
336 "parameters": {"height": {"type": "integer"}}
337 }
338 },
339 "state": {
340 "property1": {"type": "boolean"}
341 }
342 })";
343 EXPECT_JSON_EQ(kExpected1, *trait);
344
Vitaly Bukaece713e2015-12-09 10:59:33 -0800345 trait = manager_.FindTraitDefinition("trait2");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800346 ASSERT_NE(nullptr, trait);
347 const char kExpected2[] = R"({
348 "state": {
349 "property2": {"type": "string"}
350 }
351 })";
352 EXPECT_JSON_EQ(kExpected2, *trait);
353
Vitaly Bukaece713e2015-12-09 10:59:33 -0800354 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait3"));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800355}
356
Vitaly Bukaece713e2015-12-09 10:59:33 -0800357TEST_F(ComponentManagerTest, FindCommandDefinition) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800358 const char kTraits[] = R"({
359 "trait1": {
360 "commands": {
361 "command1": {
362 "minimalRole": "user",
363 "parameters": {"height": {"type": "integer"}}
364 }
365 }
366 },
367 "trait2": {
368 "commands": {
369 "command1": {
370 "minimalRole": "manager"
371 },
372 "command2": {
373 "minimalRole": "owner"
374 }
375 }
376 }
377 })";
378 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800379 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800380
Vitaly Bukaece713e2015-12-09 10:59:33 -0800381 const auto* cmd_def = manager_.FindCommandDefinition("trait1.command1");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800382 ASSERT_NE(nullptr, cmd_def);
383 const char kExpected1[] = R"({
384 "minimalRole": "user",
385 "parameters": {"height": {"type": "integer"}}
386 })";
387 EXPECT_JSON_EQ(kExpected1, *cmd_def);
388
Vitaly Bukaece713e2015-12-09 10:59:33 -0800389 cmd_def = manager_.FindCommandDefinition("trait2.command1");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800390 ASSERT_NE(nullptr, cmd_def);
391 const char kExpected2[] = R"({
392 "minimalRole": "manager"
393 })";
394 EXPECT_JSON_EQ(kExpected2, *cmd_def);
395
Vitaly Bukaece713e2015-12-09 10:59:33 -0800396 cmd_def = manager_.FindCommandDefinition("trait2.command2");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800397 ASSERT_NE(nullptr, cmd_def);
398 const char kExpected3[] = R"({
399 "minimalRole": "owner"
400 })";
401 EXPECT_JSON_EQ(kExpected3, *cmd_def);
402
Vitaly Bukaece713e2015-12-09 10:59:33 -0800403 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait1.command2"));
404 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait3.command1"));
405 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait"));
406 EXPECT_EQ(nullptr,
407 manager_.FindTraitDefinition("trait1.command1.parameters"));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800408}
409
Alex Vakulenko0d3062e2016-02-23 16:03:43 -0800410TEST_F(ComponentManagerTest, GetCommandMinimalRole) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800411 const char kTraits[] = R"({
412 "trait1": {
413 "commands": {
414 "command1": { "minimalRole": "user" },
415 "command2": { "minimalRole": "viewer" }
416 }
417 },
418 "trait2": {
419 "commands": {
420 "command1": { "minimalRole": "manager" },
421 "command2": { "minimalRole": "owner" }
422 }
423 }
424 })";
425 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800426 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800427
428 UserRole role;
Vitaly Buka5e94dc82016-03-01 13:03:01 -0800429 ASSERT_TRUE(
430 manager_.GetCommandMinimalRole("trait1.command1", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800431 EXPECT_EQ(UserRole::kUser, role);
432
Vitaly Buka5e94dc82016-03-01 13:03:01 -0800433 ASSERT_TRUE(
434 manager_.GetCommandMinimalRole("trait1.command2", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800435 EXPECT_EQ(UserRole::kViewer, role);
436
Vitaly Buka5e94dc82016-03-01 13:03:01 -0800437 ASSERT_TRUE(
438 manager_.GetCommandMinimalRole("trait2.command1", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800439 EXPECT_EQ(UserRole::kManager, role);
440
Vitaly Buka5e94dc82016-03-01 13:03:01 -0800441 ASSERT_TRUE(
442 manager_.GetCommandMinimalRole("trait2.command2", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800443 EXPECT_EQ(UserRole::kOwner, role);
444
Vitaly Buka5e94dc82016-03-01 13:03:01 -0800445 EXPECT_FALSE(
446 manager_.GetCommandMinimalRole("trait1.command3", &role, nullptr));
Alex Vakulenko0d3062e2016-02-23 16:03:43 -0800447}
448
449TEST_F(ComponentManagerTest, GetStateMinimalRole) {
450 const char kTraits[] = R"({
451 "trait1": {
452 "state": {
453 "property1": {"type": "integer"},
454 "property2": {"type": "boolean", "minimalRole": "viewer"},
455 "property3": {"type": "integer", "minimalRole": "user"}
456 }
457 },
458 "trait2": {
459 "state": {
460 "property1": {"type": "string", "minimalRole": "manager"},
461 "property2": {"type": "integer", "minimalRole": "owner"}
462 }
463 }
464 })";
465 auto json = CreateDictionaryValue(kTraits);
466 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
467
468 UserRole role;
469 ASSERT_TRUE(manager_.GetStateMinimalRole("trait1.property1", &role, nullptr));
470 EXPECT_EQ(UserRole::kUser, role);
471
472 ASSERT_TRUE(manager_.GetStateMinimalRole("trait1.property2", &role, nullptr));
473 EXPECT_EQ(UserRole::kViewer, role);
474
475 ASSERT_TRUE(manager_.GetStateMinimalRole("trait1.property3", &role, nullptr));
476 EXPECT_EQ(UserRole::kUser, role);
477
478 ASSERT_TRUE(manager_.GetStateMinimalRole("trait2.property1", &role, nullptr));
479 EXPECT_EQ(UserRole::kManager, role);
480
481 ASSERT_TRUE(manager_.GetStateMinimalRole("trait2.property2", &role, nullptr));
482 EXPECT_EQ(UserRole::kOwner, role);
483
Vitaly Buka5e94dc82016-03-01 13:03:01 -0800484 ASSERT_FALSE(
485 manager_.GetStateMinimalRole("trait2.property3", &role, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800486}
487
Vitaly Bukaece713e2015-12-09 10:59:33 -0800488TEST_F(ComponentManagerTest, AddComponent) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800489 const char kTraits[] = R"({"trait1": {}, "trait2": {}, "trait3": {}})";
490 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800491 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
492 EXPECT_TRUE(
493 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
494 EXPECT_TRUE(manager_.AddComponent("", "comp2", {"trait3"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800495 const char kExpected[] = R"({
496 "comp1": {
497 "traits": ["trait1", "trait2"]
498 },
499 "comp2": {
500 "traits": ["trait3"]
501 }
502 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800503 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800504
505 // 'trait4' is undefined, so can't add a component referring to it.
Vitaly Bukaece713e2015-12-09 10:59:33 -0800506 EXPECT_FALSE(manager_.AddComponent("", "comp3", {"trait4"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800507}
508
Vitaly Bukaece713e2015-12-09 10:59:33 -0800509TEST_F(ComponentManagerTest, AddSubComponent) {
510 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
511 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
512 EXPECT_TRUE(manager_.AddComponent("comp1", "comp3", {}, nullptr));
513 EXPECT_TRUE(manager_.AddComponent("comp1.comp2", "comp4", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800514 const char kExpected[] = R"({
515 "comp1": {
516 "traits": [],
517 "components": {
518 "comp2": {
519 "traits": [],
520 "components": {
521 "comp4": {
522 "traits": []
523 }
524 }
525 },
526 "comp3": {
527 "traits": []
528 }
529 }
530 }
531 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800532 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800533}
534
Vitaly Bukaece713e2015-12-09 10:59:33 -0800535TEST_F(ComponentManagerTest, AddComponentArrayItem) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800536 const char kTraits[] = R"({"foo": {}, "bar": {}})";
537 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800538 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800539
Vitaly Bukaece713e2015-12-09 10:59:33 -0800540 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
541 EXPECT_TRUE(
542 manager_.AddComponentArrayItem("comp1", "comp2", {"foo"}, nullptr));
543 EXPECT_TRUE(
544 manager_.AddComponentArrayItem("comp1", "comp2", {"bar"}, nullptr));
545 EXPECT_TRUE(manager_.AddComponent("comp1.comp2[1]", "comp3", {}, nullptr));
546 EXPECT_TRUE(
547 manager_.AddComponent("comp1.comp2[1].comp3", "comp4", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800548 const char kExpected[] = R"({
549 "comp1": {
550 "traits": [],
551 "components": {
552 "comp2": [
553 {
554 "traits": ["foo"]
555 },
556 {
557 "traits": ["bar"],
558 "components": {
559 "comp3": {
560 "traits": [],
561 "components": {
562 "comp4": {
563 "traits": []
564 }
565 }
566 }
567 }
568 }
569 ]
570 }
571 }
572 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800573 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800574}
575
Alex Vakulenkoce850b52016-01-04 09:27:50 -0800576TEST_F(ComponentManagerTest, RemoveComponent) {
577 CreateTestComponentTree(&manager_);
Vitaly Buka5e94dc82016-03-01 13:03:01 -0800578 EXPECT_TRUE(
579 manager_.RemoveComponent("comp1.comp2[1].comp3", "comp4", nullptr));
Alex Vakulenkoce850b52016-01-04 09:27:50 -0800580 const char kExpected1[] = R"({
581 "comp1": {
582 "traits": [ "t1" ],
583 "components": {
584 "comp2": [
585 {
586 "traits": [ "t2" ]
587 },
588 {
589 "traits": [ "t3" ],
590 "components": {
591 "comp3": {
592 "traits": [ "t4" ],
593 "components": {}
594 }
595 }
596 }
597 ]
598 }
599 }
600 })";
601 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
602 EXPECT_TRUE(manager_.RemoveComponentArrayItem("comp1", "comp2", 1, nullptr));
603 const char kExpected2[] = R"({
604 "comp1": {
605 "traits": [ "t1" ],
606 "components": {
607 "comp2": [
608 {
609 "traits": [ "t2" ]
610 }
611 ]
612 }
613 }
614 })";
615 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
616}
617
Vitaly Bukaece713e2015-12-09 10:59:33 -0800618TEST_F(ComponentManagerTest, AddComponentExist) {
619 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
620 EXPECT_FALSE(manager_.AddComponent("", "comp1", {}, nullptr));
621 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
622 EXPECT_FALSE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800623}
624
Vitaly Bukaece713e2015-12-09 10:59:33 -0800625TEST_F(ComponentManagerTest, AddComponentDoesNotExist) {
626 EXPECT_FALSE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800627}
628
Vitaly Bukaece713e2015-12-09 10:59:33 -0800629TEST_F(ComponentManagerTest, AddComponentTreeChangedCallback) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800630 int count = 0;
631 int count2 = 0;
Luis Hector Chavez17f710e2016-07-18 16:08:56 -0700632 auto handler = [](int* count) { (*count)++; };
Vitaly Bukaece713e2015-12-09 10:59:33 -0800633 manager_.AddComponentTreeChangedCallback(
Luis Hector Chavez17f710e2016-07-18 16:08:56 -0700634 base::Bind(handler, base::Unretained(&count)));
635 manager_.AddComponentTreeChangedCallback(
636 base::Bind(handler, base::Unretained(&count2)));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800637 EXPECT_EQ(1, count);
638 EXPECT_EQ(1, count2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800639 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800640 EXPECT_EQ(2, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800641 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800642 EXPECT_EQ(3, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800643 EXPECT_TRUE(manager_.AddComponent("comp1.comp2", "comp4", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800644 EXPECT_EQ(4, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800645 EXPECT_TRUE(manager_.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800646 EXPECT_EQ(5, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800647 EXPECT_TRUE(manager_.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800648 EXPECT_EQ(6, count);
Alex Vakulenkoce850b52016-01-04 09:27:50 -0800649 EXPECT_TRUE(manager_.RemoveComponentArrayItem("comp1", "comp3", 1, nullptr));
650 EXPECT_EQ(7, count);
651 EXPECT_TRUE(manager_.RemoveComponent("", "comp1", nullptr));
652 EXPECT_EQ(8, count);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800653 // Make sure both callbacks were called the same number of times.
654 EXPECT_EQ(count2, count);
655}
656
Vitaly Bukaece713e2015-12-09 10:59:33 -0800657TEST_F(ComponentManagerTest, FindComponent) {
658 CreateTestComponentTree(&manager_);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800659
Vitaly Bukaece713e2015-12-09 10:59:33 -0800660 const base::DictionaryValue* comp = manager_.FindComponent("comp1", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800661 ASSERT_NE(nullptr, comp);
662 EXPECT_TRUE(HasTrait(*comp, "t1"));
663
Vitaly Bukaece713e2015-12-09 10:59:33 -0800664 comp = manager_.FindComponent("comp1.comp2[0]", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800665 ASSERT_NE(nullptr, comp);
666 EXPECT_TRUE(HasTrait(*comp, "t2"));
667
Vitaly Bukaece713e2015-12-09 10:59:33 -0800668 comp = manager_.FindComponent("comp1.comp2[1]", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800669 ASSERT_NE(nullptr, comp);
670 EXPECT_TRUE(HasTrait(*comp, "t3"));
671
Vitaly Bukaece713e2015-12-09 10:59:33 -0800672 comp = manager_.FindComponent("comp1.comp2[1].comp3", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800673 ASSERT_NE(nullptr, comp);
674 EXPECT_TRUE(HasTrait(*comp, "t4"));
675
Vitaly Bukaece713e2015-12-09 10:59:33 -0800676 comp = manager_.FindComponent("comp1.comp2[1].comp3.comp4", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800677 ASSERT_NE(nullptr, comp);
678 EXPECT_TRUE(HasTrait(*comp, "t5"));
679
680 // Some whitespaces don't hurt.
Vitaly Bukaece713e2015-12-09 10:59:33 -0800681 comp = manager_.FindComponent(" comp1 . comp2 [ \t 1 ] . comp3.comp4 ",
682 nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800683 EXPECT_NE(nullptr, comp);
684
685 // Now check some failure cases.
686 ErrorPtr error;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800687 EXPECT_EQ(nullptr, manager_.FindComponent("", &error));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800688 EXPECT_NE(nullptr, error.get());
689 // 'comp2' doesn't exist:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800690 EXPECT_EQ(nullptr, manager_.FindComponent("comp2", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800691 // 'comp1.comp2' is an array, not a component:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800692 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800693 // 'comp1.comp2[3]' doesn't exist:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800694 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[3]", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800695 // Empty component names:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800696 EXPECT_EQ(nullptr, manager_.FindComponent(".comp2[1]", nullptr));
697 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.[1]", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800698 // Invalid array indices:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800699 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[s]", nullptr));
700 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[-2]", nullptr));
701 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[1e1]", nullptr));
702 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[1", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800703}
704
Vitaly Bukaece713e2015-12-09 10:59:33 -0800705TEST_F(ComponentManagerTest, ParseCommandInstance) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800706 const char kTraits[] = R"({
707 "trait1": {
708 "commands": {
709 "command1": { "minimalRole": "user" },
710 "command2": { "minimalRole": "viewer" }
711 }
712 },
713 "trait2": {
714 "commands": {
715 "command1": { "minimalRole": "manager" },
716 "command2": { "minimalRole": "owner" }
717 }
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800718 },
719 "trait3": {
720 "commands": {
721 "command1": { "minimalRole": "manager" },
722 "command2": { "minimalRole": "owner" }
723 }
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800724 }
725 })";
726 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800727 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
728 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
729 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait2"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800730
731 std::string id;
732 const char kCommand1[] = R"({
733 "name": "trait1.command1",
Alex Vakulenkob736c982015-12-05 14:09:27 -0800734 "id": "1234-12345",
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800735 "component": "comp1",
736 "parameters": {}
737 })";
738 auto command1 = CreateDictionaryValue(kCommand1);
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800739 EXPECT_NE(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800740 manager_.ParseCommandInstance(*command1, Command::Origin::kLocal,
741 UserRole::kUser, &id, nullptr)
742 .get());
Alex Vakulenkob736c982015-12-05 14:09:27 -0800743 EXPECT_EQ("1234-12345", id);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800744 // Not enough access rights
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800745 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800746 manager_.ParseCommandInstance(*command1, Command::Origin::kLocal,
747 UserRole::kViewer, &id, nullptr)
748 .get());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800749
750 const char kCommand2[] = R"({
751 "name": "trait1.command3",
752 "component": "comp1",
753 "parameters": {}
754 })";
755 auto command2 = CreateDictionaryValue(kCommand2);
756 // trait1.command3 doesn't exist
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800757 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800758 manager_.ParseCommandInstance(*command2, Command::Origin::kLocal,
759 UserRole::kOwner, &id, nullptr)
760 .get());
Alex Vakulenkob736c982015-12-05 14:09:27 -0800761 EXPECT_TRUE(id.empty());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800762
763 const char kCommand3[] = R"({
764 "name": "trait2.command1",
765 "component": "comp1",
766 "parameters": {}
767 })";
768 auto command3 = CreateDictionaryValue(kCommand3);
769 // Component comp1 doesn't have trait2.
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800770 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800771 manager_.ParseCommandInstance(*command3, Command::Origin::kLocal,
772 UserRole::kOwner, &id, nullptr)
773 .get());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800774
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800775 // No component specified, find the suitable component
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800776 const char kCommand4[] = R"({
777 "name": "trait1.command1",
778 "parameters": {}
779 })";
780 auto command4 = CreateDictionaryValue(kCommand4);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800781 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800782 *command4, Command::Origin::kLocal, UserRole::kOwner, &id, nullptr);
783 EXPECT_NE(nullptr, command_instance.get());
784 EXPECT_EQ("comp1", command_instance->GetComponent());
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800785
786 const char kCommand5[] = R"({
787 "name": "trait2.command1",
788 "parameters": {}
789 })";
790 auto command5 = CreateDictionaryValue(kCommand5);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800791 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800792 *command5, Command::Origin::kLocal, UserRole::kOwner, &id, nullptr);
793 EXPECT_NE(nullptr, command_instance.get());
794 EXPECT_EQ("comp2", command_instance->GetComponent());
795
796 // Cannot route the command, no component with 'trait3'.
797 const char kCommand6[] = R"({
798 "name": "trait3.command1",
799 "parameters": {}
800 })";
801 auto command6 = CreateDictionaryValue(kCommand6);
802 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800803 manager_.ParseCommandInstance(*command6, Command::Origin::kLocal,
804 UserRole::kOwner, &id, nullptr)
805 .get());
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800806}
807
Vitaly Bukaece713e2015-12-09 10:59:33 -0800808TEST_F(ComponentManagerTest, AddCommand) {
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800809 const char kTraits[] = R"({
810 "trait1": {
811 "commands": {
812 "command1": { "minimalRole": "user" }
813 }
814 }
815 })";
816 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800817 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
818 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800819
820 std::string id;
821 const char kCommand[] = R"({
822 "name": "trait1.command1",
823 "id": "1234-12345",
824 "component": "comp1",
825 "parameters": {}
826 })";
827 auto command = CreateDictionaryValue(kCommand);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800828 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800829 *command, Command::Origin::kLocal, UserRole::kUser, &id, nullptr);
830 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800831 manager_.AddCommand(std::move(command_instance));
832 const auto* queued_command = manager_.FindCommand(id);
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800833 ASSERT_NE(nullptr, queued_command);
834 EXPECT_EQ("trait1.command1", queued_command->GetName());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800835}
836
Vitaly Bukaece713e2015-12-09 10:59:33 -0800837TEST_F(ComponentManagerTest, AddCommandHandler) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800838 const char kTraits[] = R"({
839 "trait1": {
840 "commands": {
841 "command1": { "minimalRole": "user" }
842 }
843 },
844 "trait2": {
845 "commands": {
846 "command2": { "minimalRole": "user" }
847 }
848 }
849 })";
850 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800851 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
852 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
853 ASSERT_TRUE(
854 manager_.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800855
856 std::string last_tags;
Luis Hector Chavez17f710e2016-07-18 16:08:56 -0700857 auto handler = [](std::string* last_tags, int tag,
858 const std::weak_ptr<Command>& command) {
859 if (!last_tags->empty())
860 *last_tags += ',';
861 *last_tags += std::to_string(tag);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800862 };
863
Luis Hector Chavez17f710e2016-07-18 16:08:56 -0700864 manager_.AddCommandHandler(
865 "comp1", "trait1.command1",
866 base::Bind(handler, base::Unretained(&last_tags), 1));
867 manager_.AddCommandHandler(
868 "comp2", "trait1.command1",
869 base::Bind(handler, base::Unretained(&last_tags), 2));
870 manager_.AddCommandHandler(
871 "comp2", "trait2.command2",
872 base::Bind(handler, base::Unretained(&last_tags), 3));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800873 EXPECT_TRUE(last_tags.empty());
874
875 const char kCommand1[] = R"({
876 "name": "trait1.command1",
877 "component": "comp1"
878 })";
879 auto command1 = CreateDictionaryValue(kCommand1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800880 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800881 *command1, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
882 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800883 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800884 EXPECT_EQ("1", last_tags);
885 last_tags.clear();
886
887 const char kCommand2[] = R"({
888 "name": "trait1.command1",
889 "component": "comp2"
890 })";
891 auto command2 = CreateDictionaryValue(kCommand2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800892 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800893 *command2, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
894 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800895 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800896 EXPECT_EQ("2", last_tags);
897 last_tags.clear();
898
899 const char kCommand3[] = R"({
900 "name": "trait2.command2",
901 "component": "comp2",
902 "parameters": {}
903 })";
904 auto command3 = CreateDictionaryValue(kCommand3);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800905 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800906 *command3, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
907 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800908 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800909 EXPECT_EQ("3", last_tags);
910 last_tags.clear();
911}
912
Vitaly Bukaece713e2015-12-09 10:59:33 -0800913TEST_F(ComponentManagerTest, AddDefaultCommandHandler) {
Alex Vakulenko20334332015-12-08 13:19:49 -0800914 const char kTraits[] = R"({
915 "trait1": {
916 "commands": {
917 "command1": { "minimalRole": "user" }
918 }
919 },
920 "trait2": {
921 "commands": {
922 "command2": { "minimalRole": "user" }
923 }
924 }
925 })";
926 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800927 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
928 ASSERT_TRUE(manager_.AddComponent("", "comp", {"trait1", "trait2"}, nullptr));
Alex Vakulenko20334332015-12-08 13:19:49 -0800929
930 int count = 0;
Luis Hector Chavez17f710e2016-07-18 16:08:56 -0700931 auto handler = [](int* count, int tag,
932 const std::weak_ptr<Command>& command) { (*count)++; };
Alex Vakulenko20334332015-12-08 13:19:49 -0800933
Luis Hector Chavez17f710e2016-07-18 16:08:56 -0700934 manager_.AddCommandHandler("", "",
935 base::Bind(handler, base::Unretained(&count), 1));
Alex Vakulenko20334332015-12-08 13:19:49 -0800936 EXPECT_EQ(0, count);
937
938 const char kCommand1[] = R"({
939 "name": "trait1.command1",
940 "component": "comp"
941 })";
942 auto command1 = CreateDictionaryValue(kCommand1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800943 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenko20334332015-12-08 13:19:49 -0800944 *command1, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
945 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800946 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko20334332015-12-08 13:19:49 -0800947 EXPECT_EQ(1, count);
948
949 const char kCommand2[] = R"({
950 "name": "trait2.command2",
951 "component": "comp"
952 })";
953 auto command2 = CreateDictionaryValue(kCommand2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800954 command_instance = manager_.ParseCommandInstance(
Alex Vakulenko20334332015-12-08 13:19:49 -0800955 *command2, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
956 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800957 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko20334332015-12-08 13:19:49 -0800958 EXPECT_EQ(2, count);
959}
960
Vitaly Bukaece713e2015-12-09 10:59:33 -0800961TEST_F(ComponentManagerTest, SetStateProperties) {
962 CreateTestComponentTree(&manager_);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800963
964 const char kState1[] = R"({"t1": {"p1": 0, "p2": "foo"}})";
965 auto state1 = CreateDictionaryValue(kState1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800966 ASSERT_TRUE(manager_.SetStateProperties("comp1", *state1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800967 const char kExpected1[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800968 "comp1": {
969 "traits": [ "t1" ],
970 "state": {"t1": {"p1": 0, "p2": "foo"}},
971 "components": {
972 "comp2": [
973 {
974 "traits": [ "t2" ]
975 },
976 {
977 "traits": [ "t3" ],
978 "components": {
979 "comp3": {
980 "traits": [ "t4" ],
981 "components": {
982 "comp4": {
983 "traits": [ "t5", "t6" ]
984 }
985 }
986 }
987 }
988 }
989 ]
990 }
991 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800992 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800993 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800994
995 const char kState2[] = R"({"t1": {"p1": {"bar": "baz"}}})";
996 auto state2 = CreateDictionaryValue(kState2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800997 ASSERT_TRUE(manager_.SetStateProperties("comp1", *state2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800998
999 const char kExpected2[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001000 "comp1": {
1001 "traits": [ "t1" ],
1002 "state": {"t1": {"p1": {"bar": "baz"}, "p2": "foo"}},
1003 "components": {
1004 "comp2": [
1005 {
1006 "traits": [ "t2" ]
1007 },
1008 {
1009 "traits": [ "t3" ],
1010 "components": {
1011 "comp3": {
1012 "traits": [ "t4" ],
1013 "components": {
1014 "comp4": {
1015 "traits": [ "t5", "t6" ]
1016 }
1017 }
1018 }
1019 }
1020 }
1021 ]
1022 }
1023 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001024 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001025 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001026
1027 const char kState3[] = R"({"t5": {"p1": 1}})";
1028 auto state3 = CreateDictionaryValue(kState3);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001029 ASSERT_TRUE(manager_.SetStateProperties("comp1.comp2[1].comp3.comp4", *state3,
1030 nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001031
1032 const char kExpected3[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001033 "comp1": {
1034 "traits": [ "t1" ],
1035 "state": {"t1": {"p1": {"bar": "baz"}, "p2": "foo"}},
1036 "components": {
1037 "comp2": [
1038 {
1039 "traits": [ "t2" ]
1040 },
1041 {
1042 "traits": [ "t3" ],
1043 "components": {
1044 "comp3": {
1045 "traits": [ "t4" ],
1046 "components": {
1047 "comp4": {
1048 "traits": [ "t5", "t6" ],
1049 "state": { "t5": { "p1": 1 } }
1050 }
1051 }
1052 }
1053 }
1054 }
1055 ]
1056 }
1057 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001058 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001059 EXPECT_JSON_EQ(kExpected3, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001060}
1061
Vitaly Bukaece713e2015-12-09 10:59:33 -08001062TEST_F(ComponentManagerTest, SetStatePropertiesFromJson) {
1063 CreateTestComponentTree(&manager_);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001064
Vitaly Bukaece713e2015-12-09 10:59:33 -08001065 ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
Vitaly Buka34668e72015-12-15 14:46:47 -08001066 "comp1.comp2[1].comp3.comp4",
1067 R"({"t5": {"p1": 3}, "t6": {"p2": 5}})", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001068
1069 const char kExpected[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001070 "comp1": {
1071 "traits": [ "t1" ],
1072 "components": {
1073 "comp2": [
1074 {
1075 "traits": [ "t2" ]
1076 },
1077 {
1078 "traits": [ "t3" ],
1079 "components": {
1080 "comp3": {
1081 "traits": [ "t4" ],
1082 "components": {
1083 "comp4": {
1084 "traits": [ "t5", "t6" ],
1085 "state": {
1086 "t5": { "p1": 3 },
1087 "t6": { "p2": 5 }
1088 }
1089 }
1090 }
1091 }
1092 }
1093 }
1094 ]
1095 }
1096 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001097 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001098 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001099}
1100
Vitaly Bukaece713e2015-12-09 10:59:33 -08001101TEST_F(ComponentManagerTest, SetGetStateProperty) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001102 const char kTraits[] = R"({
1103 "trait1": {
1104 "state": {
1105 "prop1": { "type": "string" },
1106 "prop2": { "type": "integer" }
1107 }
1108 },
1109 "trait2": {
1110 "state": {
1111 "prop3": { "type": "string" },
1112 "prop4": { "type": "string" }
1113 }
1114 }
1115 })";
1116 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001117 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1118 ASSERT_TRUE(
1119 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001120
1121 base::StringValue p1("foo");
Vitaly Bukaece713e2015-12-09 10:59:33 -08001122 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001123
1124 const char kExpected1[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001125 "comp1": {
1126 "traits": [ "trait1", "trait2" ],
1127 "state": {
1128 "trait1": { "prop1": "foo" }
1129 }
1130 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001131 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001132 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001133
1134 base::FundamentalValue p2(2);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001135 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait2.prop3", p2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001136
1137 const char kExpected2[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001138 "comp1": {
1139 "traits": [ "trait1", "trait2" ],
1140 "state": {
1141 "trait1": { "prop1": "foo" },
1142 "trait2": { "prop3": 2 }
1143 }
1144 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001145 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001146 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001147 // Just the package name without property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001148 EXPECT_FALSE(manager_.SetStateProperty("comp1", "trait2", p2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001149
Vitaly Bukaece713e2015-12-09 10:59:33 -08001150 const base::Value* value =
1151 manager_.GetStateProperty("comp1", "trait1.prop1", nullptr);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001152 ASSERT_NE(nullptr, value);
1153 EXPECT_TRUE(p1.Equals(value));
Vitaly Bukaece713e2015-12-09 10:59:33 -08001154 value = manager_.GetStateProperty("comp1", "trait2.prop3", nullptr);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001155 ASSERT_NE(nullptr, value);
1156 EXPECT_TRUE(p2.Equals(value));
1157
1158 // Non-existing property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001159 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp1", "trait2.p", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001160 // Non-existing component
Vitaly Bukaece713e2015-12-09 10:59:33 -08001161 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp2", "trait.prop", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001162 // Just the package name without property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001163 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp1", "trait2", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001164}
1165
Vitaly Bukaece713e2015-12-09 10:59:33 -08001166TEST_F(ComponentManagerTest, AddStateChangedCallback) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001167 const char kTraits[] = R"({
1168 "trait1": {
1169 "state": {
1170 "prop1": { "type": "string" },
1171 "prop2": { "type": "string" }
1172 }
1173 }
1174 })";
1175 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001176 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1177 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001178
1179 int count = 0;
1180 int count2 = 0;
Luis Hector Chavez17f710e2016-07-18 16:08:56 -07001181 auto handler = [](int* count) { (*count)++; };
1182 manager_.AddStateChangedCallback(
1183 base::Bind(handler, base::Unretained(&count)));
1184 manager_.AddStateChangedCallback(
1185 base::Bind(handler, base::Unretained(&count2)));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001186 EXPECT_EQ(1, count);
1187 EXPECT_EQ(1, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001188 EXPECT_EQ(0u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001189
1190 base::StringValue p1("foo");
Vitaly Bukaece713e2015-12-09 10:59:33 -08001191 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001192 EXPECT_EQ(2, count);
1193 EXPECT_EQ(2, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001194 EXPECT_EQ(1u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001195
Vitaly Bukaece713e2015-12-09 10:59:33 -08001196 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001197 EXPECT_EQ(3, count);
1198 EXPECT_EQ(3, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001199 EXPECT_EQ(2u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001200
1201 // Fail - no component.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001202 ASSERT_FALSE(manager_.SetStateProperty("comp2", "trait1.prop2", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001203 EXPECT_EQ(3, count);
1204 EXPECT_EQ(3, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001205 EXPECT_EQ(2u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001206}
1207
Vitaly Bukaece713e2015-12-09 10:59:33 -08001208TEST_F(ComponentManagerTest, ComponentStateUpdates) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001209 const char kTraits[] = R"({
1210 "trait1": {
1211 "state": {
1212 "prop1": { "type": "string" },
1213 "prop2": { "type": "string" }
1214 }
1215 },
1216 "trait2": {
1217 "state": {
1218 "prop3": { "type": "string" },
1219 "prop4": { "type": "string" }
1220 }
1221 }
1222 })";
1223 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001224 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1225 ASSERT_TRUE(
1226 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
1227 ASSERT_TRUE(
1228 manager_.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001229
1230 std::vector<ComponentManager::UpdateID> updates1;
Luis Hector Chavez17f710e2016-07-18 16:08:56 -07001231 auto callback = [](std::vector<ComponentManager::UpdateID>* updates,
1232 ComponentManager::UpdateID id) {
1233 updates->push_back(id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001234 };
1235 // State change queue is empty, callback should be called immediately.
Luis Hector Chavez17f710e2016-07-18 16:08:56 -07001236 auto token1 = manager_.AddServerStateUpdatedCallback(
1237 base::Bind(callback, base::Unretained(&updates1)));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001238 ASSERT_EQ(1u, updates1.size());
Vitaly Bukaece713e2015-12-09 10:59:33 -08001239 EXPECT_EQ(manager_.GetLastStateChangeId(), updates1.front());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001240 updates1.clear();
1241
1242 base::StringValue foo("foo");
1243 base::Time time1 = base::Time::Now();
Vitaly Bukaece713e2015-12-09 10:59:33 -08001244 EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(time1));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001245 // These three updates should be grouped into two separate state change queue
1246 // items, since they all happen at the same time, but for two different
1247 // components.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001248 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", foo, nullptr));
1249 ASSERT_TRUE(manager_.SetStateProperty("comp2", "trait2.prop3", foo, nullptr));
1250 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", foo, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001251
1252 std::vector<ComponentManager::UpdateID> updates2;
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001253 // State change queue is not empty, so callback will be called later.
Luis Hector Chavez17f710e2016-07-18 16:08:56 -07001254 auto token2 = manager_.AddServerStateUpdatedCallback(
1255 base::Bind(callback, base::Unretained(&updates2)));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001256 EXPECT_TRUE(updates2.empty());
1257
1258 base::StringValue bar("bar");
1259 base::Time time2 = time1 + base::TimeDelta::FromSeconds(1);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001260 EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(time2));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001261 // Two more update events (as above) but at |time2|.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001262 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", bar, nullptr));
1263 ASSERT_TRUE(manager_.SetStateProperty("comp2", "trait2.prop3", bar, nullptr));
1264 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", bar, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001265
Vitaly Bukaece713e2015-12-09 10:59:33 -08001266 auto snapshot = manager_.GetAndClearRecordedStateChanges();
1267 EXPECT_EQ(manager_.GetLastStateChangeId(), snapshot.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001268 ASSERT_EQ(4u, snapshot.state_changes.size());
1269
1270 EXPECT_EQ("comp1", snapshot.state_changes[0].component);
1271 EXPECT_EQ(time1, snapshot.state_changes[0].timestamp);
1272 EXPECT_JSON_EQ(R"({"trait1":{"prop1":"foo","prop2":"foo"}})",
1273 *snapshot.state_changes[0].changed_properties);
1274
1275 EXPECT_EQ("comp2", snapshot.state_changes[1].component);
1276 EXPECT_EQ(time1, snapshot.state_changes[1].timestamp);
1277 EXPECT_JSON_EQ(R"({"trait2":{"prop3":"foo"}})",
1278 *snapshot.state_changes[1].changed_properties);
1279
1280 EXPECT_EQ("comp1", snapshot.state_changes[2].component);
1281 EXPECT_EQ(time2, snapshot.state_changes[2].timestamp);
1282 EXPECT_JSON_EQ(R"({"trait1":{"prop1":"bar","prop2":"bar"}})",
1283 *snapshot.state_changes[2].changed_properties);
1284
1285 EXPECT_EQ("comp2", snapshot.state_changes[3].component);
1286 EXPECT_EQ(time2, snapshot.state_changes[3].timestamp);
1287 EXPECT_JSON_EQ(R"({"trait2":{"prop3":"bar"}})",
1288 *snapshot.state_changes[3].changed_properties);
1289
1290 // Make sure previous GetAndClearRecordedStateChanges() clears the queue.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001291 auto snapshot2 = manager_.GetAndClearRecordedStateChanges();
1292 EXPECT_EQ(manager_.GetLastStateChangeId(), snapshot2.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001293 EXPECT_TRUE(snapshot2.state_changes.empty());
1294
1295 // Now indicate that we have update the changes on the server.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001296 manager_.NotifyStateUpdatedOnServer(snapshot.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001297 ASSERT_EQ(1u, updates1.size());
1298 EXPECT_EQ(snapshot.update_id, updates1.front());
1299 ASSERT_EQ(1u, updates2.size());
1300 EXPECT_EQ(snapshot.update_id, updates2.front());
1301}
1302
Vitaly Bukaece713e2015-12-09 10:59:33 -08001303TEST_F(ComponentManagerTest, FindComponentWithTrait) {
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001304 const char kTraits[] = R"({
1305 "trait1": {},
1306 "trait2": {},
1307 "trait3": {}
1308 })";
1309 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001310 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1311 ASSERT_TRUE(
1312 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
1313 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait3"}, nullptr));
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001314
Vitaly Bukaece713e2015-12-09 10:59:33 -08001315 EXPECT_EQ("comp1", manager_.FindComponentWithTrait("trait1"));
1316 EXPECT_EQ("comp1", manager_.FindComponentWithTrait("trait2"));
1317 EXPECT_EQ("comp2", manager_.FindComponentWithTrait("trait3"));
1318 EXPECT_EQ("", manager_.FindComponentWithTrait("trait4"));
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001319}
1320
Vitaly Bukaece713e2015-12-09 10:59:33 -08001321TEST_F(ComponentManagerTest, TestMockComponentManager) {
Alex Vakulenkoba981152015-12-05 13:58:22 -08001322 // Check that all the virtual methods are mocked out.
Vitaly Buka012cd982016-02-22 17:18:49 -08001323 test::MockComponentManager mock;
Alex Vakulenkoba981152015-12-05 13:58:22 -08001324}
1325
Alex Vakulenko0d3062e2016-02-23 16:03:43 -08001326TEST_F(ComponentManagerTest, GetComponentsForUserRole) {
1327 const char kTraits[] = R"({
1328 "trait1": {
1329 "state": {
1330 "prop1": { "type": "string", "minimalRole": "viewer" },
1331 "prop2": { "type": "string", "minimalRole": "user" }
1332 }
1333 },
1334 "trait2": {
1335 "state": {
1336 "prop3": { "type": "string", "minimalRole": "manager" },
1337 "prop4": { "type": "string", "minimalRole": "owner" }
1338 }
1339 },
1340 "trait3": {
1341 "state": {
1342 "prop5": { "type": "string" }
1343 }
1344 }
1345 })";
1346 auto json = CreateDictionaryValue(kTraits);
1347 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Vitaly Buka5e94dc82016-03-01 13:03:01 -08001348 ASSERT_TRUE(
1349 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
Alex Vakulenko0d3062e2016-02-23 16:03:43 -08001350 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait2"}, nullptr));
Vitaly Buka5e94dc82016-03-01 13:03:01 -08001351 ASSERT_TRUE(
1352 manager_.AddComponentArrayItem("comp2", "comp3", {"trait3"}, nullptr));
Alex Vakulenko0d3062e2016-02-23 16:03:43 -08001353 ASSERT_TRUE(manager_.AddComponent("comp2", "comp4", {"trait3"}, nullptr));
1354
1355 const char kComp1Properties[] = R"({
1356 "trait1": { "prop1": "foo", "prop2": "bar" },
1357 "trait2": { "prop3": "baz", "prop4": "quux" }
1358 })";
Vitaly Buka5e94dc82016-03-01 13:03:01 -08001359 ASSERT_TRUE(
1360 manager_.SetStatePropertiesFromJson("comp1", kComp1Properties, nullptr));
Alex Vakulenko0d3062e2016-02-23 16:03:43 -08001361
1362 const char kComp2Properties[] = R"({
1363 "trait2": { "prop3": "foo", "prop4": "bar" }
1364 })";
Vitaly Buka5e94dc82016-03-01 13:03:01 -08001365 ASSERT_TRUE(
1366 manager_.SetStatePropertiesFromJson("comp2", kComp2Properties, nullptr));
Alex Vakulenko0d3062e2016-02-23 16:03:43 -08001367
1368 const char kComp3Properties[] = R"({
1369 "trait3": { "prop5": "foo" }
1370 })";
1371 ASSERT_TRUE(manager_.SetStatePropertiesFromJson("comp2.comp3[0]",
1372 kComp3Properties, nullptr));
1373
1374 const char kComp4Properties[] = R"({
1375 "trait3": { "prop5": "bar" }
1376 })";
1377 ASSERT_TRUE(manager_.SetStatePropertiesFromJson("comp2.comp4",
1378 kComp4Properties, nullptr));
1379
1380 const char kExpected1[] = R"({
1381 "comp1": {
1382 "traits": [ "trait1", "trait2" ],
1383 "state": {
1384 "trait1": {
1385 "prop1": "foo",
1386 "prop2": "bar"
1387 },
1388 "trait2": {
1389 "prop3": "baz",
1390 "prop4": "quux"
1391 }
1392 }
1393 },
1394 "comp2": {
1395 "traits": [ "trait2" ],
1396 "state": {
1397 "trait2": {
1398 "prop3": "foo",
1399 "prop4": "bar"
1400 }
1401 },
1402 "components": {
1403 "comp3": [
1404 {
1405 "traits": [ "trait3" ],
1406 "state": {
1407 "trait3": {
1408 "prop5": "foo"
1409 }
1410 }
1411 }
1412 ],
1413 "comp4": {
1414 "traits": [ "trait3" ],
1415 "state": {
1416 "trait3": {
1417 "prop5": "bar"
1418 }
1419 }
1420 }
1421 }
1422 }
1423 })";
1424 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
1425
1426 EXPECT_JSON_EQ(kExpected1,
1427 *manager_.GetComponentsForUserRole(UserRole::kOwner));
1428
1429 const char kExpected2[] = R"({
1430 "comp1": {
1431 "traits": [ "trait1", "trait2" ],
1432 "state": {
1433 "trait1": {
1434 "prop1": "foo",
1435 "prop2": "bar"
1436 },
1437 "trait2": {
1438 "prop3": "baz"
1439 }
1440 }
1441 },
1442 "comp2": {
1443 "traits": [ "trait2" ],
1444 "state": {
1445 "trait2": {
1446 "prop3": "foo"
1447 }
1448 },
1449 "components": {
1450 "comp3": [
1451 {
1452 "traits": [ "trait3" ],
1453 "state": {
1454 "trait3": {
1455 "prop5": "foo"
1456 }
1457 }
1458 }
1459 ],
1460 "comp4": {
1461 "traits": [ "trait3" ],
1462 "state": {
1463 "trait3": {
1464 "prop5": "bar"
1465 }
1466 }
1467 }
1468 }
1469 }
1470 })";
1471 EXPECT_JSON_EQ(kExpected2,
1472 *manager_.GetComponentsForUserRole(UserRole::kManager));
1473
1474 const char kExpected3[] = R"({
1475 "comp1": {
1476 "traits": [ "trait1", "trait2" ],
1477 "state": {
1478 "trait1": {
1479 "prop1": "foo",
1480 "prop2": "bar"
1481 }
1482 }
1483 },
1484 "comp2": {
1485 "traits": [ "trait2" ],
1486 "components": {
1487 "comp3": [
1488 {
1489 "traits": [ "trait3" ],
1490 "state": {
1491 "trait3": {
1492 "prop5": "foo"
1493 }
1494 }
1495 }
1496 ],
1497 "comp4": {
1498 "traits": [ "trait3" ],
1499 "state": {
1500 "trait3": {
1501 "prop5": "bar"
1502 }
1503 }
1504 }
1505 }
1506 }
1507 })";
1508 EXPECT_JSON_EQ(kExpected3,
1509 *manager_.GetComponentsForUserRole(UserRole::kUser));
1510
1511 const char kExpected4[] = R"({
1512 "comp1": {
1513 "traits": [ "trait1", "trait2" ],
1514 "state": {
1515 "trait1": {
1516 "prop1": "foo"
1517 }
1518 }
1519 },
1520 "comp2": {
1521 "traits": [ "trait2" ],
1522 "components": {
1523 "comp3": [
1524 {
1525 "traits": [ "trait3" ]
1526 }
1527 ],
1528 "comp4": {
1529 "traits": [ "trait3" ]
1530 }
1531 }
1532 }
1533 })";
1534 EXPECT_JSON_EQ(kExpected4,
1535 *manager_.GetComponentsForUserRole(UserRole::kViewer));
1536}
1537
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -08001538} // namespace weave