blob: f0db3ef5ee02f62a5003460dc17649b267a7a9c0 [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;
30 for (const base::Value* item : *list) {
31 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;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800244 manager_.AddTraitDefChangedCallback(base::Bind([&count]() { count++; }));
245 manager_.AddTraitDefChangedCallback(base::Bind([&count2]() { count2++; }));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800246 EXPECT_EQ(1, count);
247 EXPECT_EQ(1, count2);
248 // New definitions.
249 const char kTraits1[] = R"({
250 "trait1": {
251 "state": {
252 "property1": {"type": "boolean"}
253 }
254 },
255 "trait2": {
256 "state": {
257 "property2": {"type": "string"}
258 }
259 }
260 })";
261 auto json = CreateDictionaryValue(kTraits1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800262 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800263 EXPECT_EQ(2, count);
264 // Duplicate definition, shouldn't call the callback.
265 const char kTraits2[] = R"({
266 "trait1": {
267 "state": {
268 "property1": {"type": "boolean"}
269 }
270 }
271 })";
272 json = CreateDictionaryValue(kTraits2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800273 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800274 EXPECT_EQ(2, count);
275 // New definition, should call the callback now.
276 const char kTraits3[] = R"({
277 "trait3": {
278 "state": {
279 "property3": {"type": "string"}
280 }
281 }
282 })";
283 json = CreateDictionaryValue(kTraits3);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800284 EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800285 EXPECT_EQ(3, count);
286 // Wrong definition, shouldn't call the callback.
287 const char kTraits4[] = R"({
288 "trait4": "foo"
289 })";
290 json = CreateDictionaryValue(kTraits4);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800291 EXPECT_FALSE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800292 EXPECT_EQ(3, count);
293 // Make sure both callbacks were called the same number of times.
294 EXPECT_EQ(count2, count);
295}
296
Vitaly Bukaece713e2015-12-09 10:59:33 -0800297TEST_F(ComponentManagerTest, LoadTraitsNotAnObject) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800298 const char kTraits1[] = R"({"trait1": 0})";
299 auto json = CreateDictionaryValue(kTraits1);
300 ErrorPtr error;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800301 EXPECT_FALSE(manager_.LoadTraits(*json, &error));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800302 EXPECT_EQ(errors::commands::kTypeMismatch, error->GetCode());
303}
304
Vitaly Bukaece713e2015-12-09 10:59:33 -0800305TEST_F(ComponentManagerTest, FindTraitDefinition) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800306 const char kTraits[] = R"({
307 "trait1": {
308 "commands": {
309 "command1": {
310 "minimalRole": "user",
311 "parameters": {"height": {"type": "integer"}}
312 }
313 },
314 "state": {
315 "property1": {"type": "boolean"}
316 }
317 },
318 "trait2": {
319 "state": {
320 "property2": {"type": "string"}
321 }
322 }
323 })";
324 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800325 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800326
Vitaly Bukaece713e2015-12-09 10:59:33 -0800327 const base::DictionaryValue* trait = manager_.FindTraitDefinition("trait1");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800328 ASSERT_NE(nullptr, trait);
329 const char kExpected1[] = R"({
330 "commands": {
331 "command1": {
332 "minimalRole": "user",
333 "parameters": {"height": {"type": "integer"}}
334 }
335 },
336 "state": {
337 "property1": {"type": "boolean"}
338 }
339 })";
340 EXPECT_JSON_EQ(kExpected1, *trait);
341
Vitaly Bukaece713e2015-12-09 10:59:33 -0800342 trait = manager_.FindTraitDefinition("trait2");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800343 ASSERT_NE(nullptr, trait);
344 const char kExpected2[] = R"({
345 "state": {
346 "property2": {"type": "string"}
347 }
348 })";
349 EXPECT_JSON_EQ(kExpected2, *trait);
350
Vitaly Bukaece713e2015-12-09 10:59:33 -0800351 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait3"));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800352}
353
Vitaly Bukaece713e2015-12-09 10:59:33 -0800354TEST_F(ComponentManagerTest, FindCommandDefinition) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800355 const char kTraits[] = R"({
356 "trait1": {
357 "commands": {
358 "command1": {
359 "minimalRole": "user",
360 "parameters": {"height": {"type": "integer"}}
361 }
362 }
363 },
364 "trait2": {
365 "commands": {
366 "command1": {
367 "minimalRole": "manager"
368 },
369 "command2": {
370 "minimalRole": "owner"
371 }
372 }
373 }
374 })";
375 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800376 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800377
Vitaly Bukaece713e2015-12-09 10:59:33 -0800378 const auto* cmd_def = manager_.FindCommandDefinition("trait1.command1");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800379 ASSERT_NE(nullptr, cmd_def);
380 const char kExpected1[] = R"({
381 "minimalRole": "user",
382 "parameters": {"height": {"type": "integer"}}
383 })";
384 EXPECT_JSON_EQ(kExpected1, *cmd_def);
385
Vitaly Bukaece713e2015-12-09 10:59:33 -0800386 cmd_def = manager_.FindCommandDefinition("trait2.command1");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800387 ASSERT_NE(nullptr, cmd_def);
388 const char kExpected2[] = R"({
389 "minimalRole": "manager"
390 })";
391 EXPECT_JSON_EQ(kExpected2, *cmd_def);
392
Vitaly Bukaece713e2015-12-09 10:59:33 -0800393 cmd_def = manager_.FindCommandDefinition("trait2.command2");
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800394 ASSERT_NE(nullptr, cmd_def);
395 const char kExpected3[] = R"({
396 "minimalRole": "owner"
397 })";
398 EXPECT_JSON_EQ(kExpected3, *cmd_def);
399
Vitaly Bukaece713e2015-12-09 10:59:33 -0800400 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait1.command2"));
401 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait3.command1"));
402 EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait"));
403 EXPECT_EQ(nullptr,
404 manager_.FindTraitDefinition("trait1.command1.parameters"));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800405}
406
Alex Vakulenko0d3062e2016-02-23 16:03:43 -0800407TEST_F(ComponentManagerTest, GetCommandMinimalRole) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800408 const char kTraits[] = R"({
409 "trait1": {
410 "commands": {
411 "command1": { "minimalRole": "user" },
412 "command2": { "minimalRole": "viewer" }
413 }
414 },
415 "trait2": {
416 "commands": {
417 "command1": { "minimalRole": "manager" },
418 "command2": { "minimalRole": "owner" }
419 }
420 }
421 })";
422 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800423 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800424
425 UserRole role;
Alex Vakulenko0d3062e2016-02-23 16:03:43 -0800426 ASSERT_TRUE(manager_.GetCommandMinimalRole("trait1.command1", &role,
427 nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800428 EXPECT_EQ(UserRole::kUser, role);
429
Alex Vakulenko0d3062e2016-02-23 16:03:43 -0800430 ASSERT_TRUE(manager_.GetCommandMinimalRole("trait1.command2", &role,
431 nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800432 EXPECT_EQ(UserRole::kViewer, role);
433
Alex Vakulenko0d3062e2016-02-23 16:03:43 -0800434 ASSERT_TRUE(manager_.GetCommandMinimalRole("trait2.command1", &role,
435 nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800436 EXPECT_EQ(UserRole::kManager, role);
437
Alex Vakulenko0d3062e2016-02-23 16:03:43 -0800438 ASSERT_TRUE(manager_.GetCommandMinimalRole("trait2.command2", &role,
439 nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800440 EXPECT_EQ(UserRole::kOwner, role);
441
Alex Vakulenko0d3062e2016-02-23 16:03:43 -0800442 EXPECT_FALSE(manager_.GetCommandMinimalRole("trait1.command3", &role,
443 nullptr));
444}
445
446TEST_F(ComponentManagerTest, GetStateMinimalRole) {
447 const char kTraits[] = R"({
448 "trait1": {
449 "state": {
450 "property1": {"type": "integer"},
451 "property2": {"type": "boolean", "minimalRole": "viewer"},
452 "property3": {"type": "integer", "minimalRole": "user"}
453 }
454 },
455 "trait2": {
456 "state": {
457 "property1": {"type": "string", "minimalRole": "manager"},
458 "property2": {"type": "integer", "minimalRole": "owner"}
459 }
460 }
461 })";
462 auto json = CreateDictionaryValue(kTraits);
463 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
464
465 UserRole role;
466 ASSERT_TRUE(manager_.GetStateMinimalRole("trait1.property1", &role, nullptr));
467 EXPECT_EQ(UserRole::kUser, role);
468
469 ASSERT_TRUE(manager_.GetStateMinimalRole("trait1.property2", &role, nullptr));
470 EXPECT_EQ(UserRole::kViewer, role);
471
472 ASSERT_TRUE(manager_.GetStateMinimalRole("trait1.property3", &role, nullptr));
473 EXPECT_EQ(UserRole::kUser, role);
474
475 ASSERT_TRUE(manager_.GetStateMinimalRole("trait2.property1", &role, nullptr));
476 EXPECT_EQ(UserRole::kManager, role);
477
478 ASSERT_TRUE(manager_.GetStateMinimalRole("trait2.property2", &role, nullptr));
479 EXPECT_EQ(UserRole::kOwner, role);
480
481 ASSERT_FALSE(manager_.GetStateMinimalRole("trait2.property3", &role,
482 nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800483}
484
Vitaly Bukaece713e2015-12-09 10:59:33 -0800485TEST_F(ComponentManagerTest, AddComponent) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800486 const char kTraits[] = R"({"trait1": {}, "trait2": {}, "trait3": {}})";
487 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800488 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
489 EXPECT_TRUE(
490 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
491 EXPECT_TRUE(manager_.AddComponent("", "comp2", {"trait3"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800492 const char kExpected[] = R"({
493 "comp1": {
494 "traits": ["trait1", "trait2"]
495 },
496 "comp2": {
497 "traits": ["trait3"]
498 }
499 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800500 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800501
502 // 'trait4' is undefined, so can't add a component referring to it.
Vitaly Bukaece713e2015-12-09 10:59:33 -0800503 EXPECT_FALSE(manager_.AddComponent("", "comp3", {"trait4"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800504}
505
Vitaly Bukaece713e2015-12-09 10:59:33 -0800506TEST_F(ComponentManagerTest, AddSubComponent) {
507 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
508 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
509 EXPECT_TRUE(manager_.AddComponent("comp1", "comp3", {}, nullptr));
510 EXPECT_TRUE(manager_.AddComponent("comp1.comp2", "comp4", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800511 const char kExpected[] = R"({
512 "comp1": {
513 "traits": [],
514 "components": {
515 "comp2": {
516 "traits": [],
517 "components": {
518 "comp4": {
519 "traits": []
520 }
521 }
522 },
523 "comp3": {
524 "traits": []
525 }
526 }
527 }
528 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800529 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800530}
531
Vitaly Bukaece713e2015-12-09 10:59:33 -0800532TEST_F(ComponentManagerTest, AddComponentArrayItem) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800533 const char kTraits[] = R"({"foo": {}, "bar": {}})";
534 auto json = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800535 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800536
Vitaly Bukaece713e2015-12-09 10:59:33 -0800537 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
538 EXPECT_TRUE(
539 manager_.AddComponentArrayItem("comp1", "comp2", {"foo"}, nullptr));
540 EXPECT_TRUE(
541 manager_.AddComponentArrayItem("comp1", "comp2", {"bar"}, nullptr));
542 EXPECT_TRUE(manager_.AddComponent("comp1.comp2[1]", "comp3", {}, nullptr));
543 EXPECT_TRUE(
544 manager_.AddComponent("comp1.comp2[1].comp3", "comp4", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800545 const char kExpected[] = R"({
546 "comp1": {
547 "traits": [],
548 "components": {
549 "comp2": [
550 {
551 "traits": ["foo"]
552 },
553 {
554 "traits": ["bar"],
555 "components": {
556 "comp3": {
557 "traits": [],
558 "components": {
559 "comp4": {
560 "traits": []
561 }
562 }
563 }
564 }
565 }
566 ]
567 }
568 }
569 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800570 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800571}
572
Alex Vakulenkoce850b52016-01-04 09:27:50 -0800573TEST_F(ComponentManagerTest, RemoveComponent) {
574 CreateTestComponentTree(&manager_);
575 EXPECT_TRUE(manager_.RemoveComponent("comp1.comp2[1].comp3", "comp4",
576 nullptr));
577 const char kExpected1[] = R"({
578 "comp1": {
579 "traits": [ "t1" ],
580 "components": {
581 "comp2": [
582 {
583 "traits": [ "t2" ]
584 },
585 {
586 "traits": [ "t3" ],
587 "components": {
588 "comp3": {
589 "traits": [ "t4" ],
590 "components": {}
591 }
592 }
593 }
594 ]
595 }
596 }
597 })";
598 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
599 EXPECT_TRUE(manager_.RemoveComponentArrayItem("comp1", "comp2", 1, nullptr));
600 const char kExpected2[] = R"({
601 "comp1": {
602 "traits": [ "t1" ],
603 "components": {
604 "comp2": [
605 {
606 "traits": [ "t2" ]
607 }
608 ]
609 }
610 }
611 })";
612 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
613}
614
Vitaly Bukaece713e2015-12-09 10:59:33 -0800615TEST_F(ComponentManagerTest, AddComponentExist) {
616 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
617 EXPECT_FALSE(manager_.AddComponent("", "comp1", {}, nullptr));
618 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
619 EXPECT_FALSE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800620}
621
Vitaly Bukaece713e2015-12-09 10:59:33 -0800622TEST_F(ComponentManagerTest, AddComponentDoesNotExist) {
623 EXPECT_FALSE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800624}
625
Vitaly Bukaece713e2015-12-09 10:59:33 -0800626TEST_F(ComponentManagerTest, AddComponentTreeChangedCallback) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800627 int count = 0;
628 int count2 = 0;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800629 manager_.AddComponentTreeChangedCallback(base::Bind([&count]() { count++; }));
630 manager_.AddComponentTreeChangedCallback(
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800631 base::Bind([&count2]() { count2++; }));
632 EXPECT_EQ(1, count);
633 EXPECT_EQ(1, count2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800634 EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800635 EXPECT_EQ(2, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800636 EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800637 EXPECT_EQ(3, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800638 EXPECT_TRUE(manager_.AddComponent("comp1.comp2", "comp4", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800639 EXPECT_EQ(4, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800640 EXPECT_TRUE(manager_.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800641 EXPECT_EQ(5, count);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800642 EXPECT_TRUE(manager_.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800643 EXPECT_EQ(6, count);
Alex Vakulenkoce850b52016-01-04 09:27:50 -0800644 EXPECT_TRUE(manager_.RemoveComponentArrayItem("comp1", "comp3", 1, nullptr));
645 EXPECT_EQ(7, count);
646 EXPECT_TRUE(manager_.RemoveComponent("", "comp1", nullptr));
647 EXPECT_EQ(8, count);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800648 // Make sure both callbacks were called the same number of times.
649 EXPECT_EQ(count2, count);
650}
651
Vitaly Bukaece713e2015-12-09 10:59:33 -0800652TEST_F(ComponentManagerTest, FindComponent) {
653 CreateTestComponentTree(&manager_);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800654
Vitaly Bukaece713e2015-12-09 10:59:33 -0800655 const base::DictionaryValue* comp = manager_.FindComponent("comp1", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800656 ASSERT_NE(nullptr, comp);
657 EXPECT_TRUE(HasTrait(*comp, "t1"));
658
Vitaly Bukaece713e2015-12-09 10:59:33 -0800659 comp = manager_.FindComponent("comp1.comp2[0]", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800660 ASSERT_NE(nullptr, comp);
661 EXPECT_TRUE(HasTrait(*comp, "t2"));
662
Vitaly Bukaece713e2015-12-09 10:59:33 -0800663 comp = manager_.FindComponent("comp1.comp2[1]", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800664 ASSERT_NE(nullptr, comp);
665 EXPECT_TRUE(HasTrait(*comp, "t3"));
666
Vitaly Bukaece713e2015-12-09 10:59:33 -0800667 comp = manager_.FindComponent("comp1.comp2[1].comp3", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800668 ASSERT_NE(nullptr, comp);
669 EXPECT_TRUE(HasTrait(*comp, "t4"));
670
Vitaly Bukaece713e2015-12-09 10:59:33 -0800671 comp = manager_.FindComponent("comp1.comp2[1].comp3.comp4", nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800672 ASSERT_NE(nullptr, comp);
673 EXPECT_TRUE(HasTrait(*comp, "t5"));
674
675 // Some whitespaces don't hurt.
Vitaly Bukaece713e2015-12-09 10:59:33 -0800676 comp = manager_.FindComponent(" comp1 . comp2 [ \t 1 ] . comp3.comp4 ",
677 nullptr);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800678 EXPECT_NE(nullptr, comp);
679
680 // Now check some failure cases.
681 ErrorPtr error;
Vitaly Bukaece713e2015-12-09 10:59:33 -0800682 EXPECT_EQ(nullptr, manager_.FindComponent("", &error));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800683 EXPECT_NE(nullptr, error.get());
684 // 'comp2' doesn't exist:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800685 EXPECT_EQ(nullptr, manager_.FindComponent("comp2", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800686 // 'comp1.comp2' is an array, not a component:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800687 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800688 // 'comp1.comp2[3]' doesn't exist:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800689 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[3]", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800690 // Empty component names:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800691 EXPECT_EQ(nullptr, manager_.FindComponent(".comp2[1]", nullptr));
692 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.[1]", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800693 // Invalid array indices:
Vitaly Bukaece713e2015-12-09 10:59:33 -0800694 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[s]", nullptr));
695 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[-2]", nullptr));
696 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[1e1]", nullptr));
697 EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[1", nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800698}
699
Vitaly Bukaece713e2015-12-09 10:59:33 -0800700TEST_F(ComponentManagerTest, ParseCommandInstance) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800701 const char kTraits[] = R"({
702 "trait1": {
703 "commands": {
704 "command1": { "minimalRole": "user" },
705 "command2": { "minimalRole": "viewer" }
706 }
707 },
708 "trait2": {
709 "commands": {
710 "command1": { "minimalRole": "manager" },
711 "command2": { "minimalRole": "owner" }
712 }
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800713 },
714 "trait3": {
715 "commands": {
716 "command1": { "minimalRole": "manager" },
717 "command2": { "minimalRole": "owner" }
718 }
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800719 }
720 })";
721 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800722 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
723 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
724 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait2"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800725
726 std::string id;
727 const char kCommand1[] = R"({
728 "name": "trait1.command1",
Alex Vakulenkob736c982015-12-05 14:09:27 -0800729 "id": "1234-12345",
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800730 "component": "comp1",
731 "parameters": {}
732 })";
733 auto command1 = CreateDictionaryValue(kCommand1);
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800734 EXPECT_NE(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800735 manager_.ParseCommandInstance(*command1, Command::Origin::kLocal,
736 UserRole::kUser, &id, nullptr)
737 .get());
Alex Vakulenkob736c982015-12-05 14:09:27 -0800738 EXPECT_EQ("1234-12345", id);
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800739 // Not enough access rights
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800740 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800741 manager_.ParseCommandInstance(*command1, Command::Origin::kLocal,
742 UserRole::kViewer, &id, nullptr)
743 .get());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800744
745 const char kCommand2[] = R"({
746 "name": "trait1.command3",
747 "component": "comp1",
748 "parameters": {}
749 })";
750 auto command2 = CreateDictionaryValue(kCommand2);
751 // trait1.command3 doesn't exist
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800752 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800753 manager_.ParseCommandInstance(*command2, Command::Origin::kLocal,
754 UserRole::kOwner, &id, nullptr)
755 .get());
Alex Vakulenkob736c982015-12-05 14:09:27 -0800756 EXPECT_TRUE(id.empty());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800757
758 const char kCommand3[] = R"({
759 "name": "trait2.command1",
760 "component": "comp1",
761 "parameters": {}
762 })";
763 auto command3 = CreateDictionaryValue(kCommand3);
764 // Component comp1 doesn't have trait2.
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800765 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800766 manager_.ParseCommandInstance(*command3, Command::Origin::kLocal,
767 UserRole::kOwner, &id, nullptr)
768 .get());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800769
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800770 // No component specified, find the suitable component
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800771 const char kCommand4[] = R"({
772 "name": "trait1.command1",
773 "parameters": {}
774 })";
775 auto command4 = CreateDictionaryValue(kCommand4);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800776 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800777 *command4, Command::Origin::kLocal, UserRole::kOwner, &id, nullptr);
778 EXPECT_NE(nullptr, command_instance.get());
779 EXPECT_EQ("comp1", command_instance->GetComponent());
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800780
781 const char kCommand5[] = R"({
782 "name": "trait2.command1",
783 "parameters": {}
784 })";
785 auto command5 = CreateDictionaryValue(kCommand5);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800786 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800787 *command5, Command::Origin::kLocal, UserRole::kOwner, &id, nullptr);
788 EXPECT_NE(nullptr, command_instance.get());
789 EXPECT_EQ("comp2", command_instance->GetComponent());
790
791 // Cannot route the command, no component with 'trait3'.
792 const char kCommand6[] = R"({
793 "name": "trait3.command1",
794 "parameters": {}
795 })";
796 auto command6 = CreateDictionaryValue(kCommand6);
797 EXPECT_EQ(nullptr,
Vitaly Bukaece713e2015-12-09 10:59:33 -0800798 manager_.ParseCommandInstance(*command6, Command::Origin::kLocal,
799 UserRole::kOwner, &id, nullptr)
800 .get());
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800801}
802
Vitaly Bukaece713e2015-12-09 10:59:33 -0800803TEST_F(ComponentManagerTest, AddCommand) {
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800804 const char kTraits[] = R"({
805 "trait1": {
806 "commands": {
807 "command1": { "minimalRole": "user" }
808 }
809 }
810 })";
811 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800812 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
813 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800814
815 std::string id;
816 const char kCommand[] = R"({
817 "name": "trait1.command1",
818 "id": "1234-12345",
819 "component": "comp1",
820 "parameters": {}
821 })";
822 auto command = CreateDictionaryValue(kCommand);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800823 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800824 *command, Command::Origin::kLocal, UserRole::kUser, &id, nullptr);
825 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800826 manager_.AddCommand(std::move(command_instance));
827 const auto* queued_command = manager_.FindCommand(id);
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800828 ASSERT_NE(nullptr, queued_command);
829 EXPECT_EQ("trait1.command1", queued_command->GetName());
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800830}
831
Vitaly Bukaece713e2015-12-09 10:59:33 -0800832TEST_F(ComponentManagerTest, AddCommandHandler) {
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800833 const char kTraits[] = R"({
834 "trait1": {
835 "commands": {
836 "command1": { "minimalRole": "user" }
837 }
838 },
839 "trait2": {
840 "commands": {
841 "command2": { "minimalRole": "user" }
842 }
843 }
844 })";
845 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800846 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
847 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
848 ASSERT_TRUE(
849 manager_.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800850
851 std::string last_tags;
852 auto handler = [&last_tags](int tag, const std::weak_ptr<Command>& command) {
853 if (!last_tags.empty())
854 last_tags += ',';
855 last_tags += std::to_string(tag);
856 };
857
Vitaly Bukaece713e2015-12-09 10:59:33 -0800858 manager_.AddCommandHandler("comp1", "trait1.command1",
859 base::Bind(handler, 1));
860 manager_.AddCommandHandler("comp2", "trait1.command1",
861 base::Bind(handler, 2));
862 manager_.AddCommandHandler("comp2", "trait2.command2",
863 base::Bind(handler, 3));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800864 EXPECT_TRUE(last_tags.empty());
865
866 const char kCommand1[] = R"({
867 "name": "trait1.command1",
868 "component": "comp1"
869 })";
870 auto command1 = CreateDictionaryValue(kCommand1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800871 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800872 *command1, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
873 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800874 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800875 EXPECT_EQ("1", last_tags);
876 last_tags.clear();
877
878 const char kCommand2[] = R"({
879 "name": "trait1.command1",
880 "component": "comp2"
881 })";
882 auto command2 = CreateDictionaryValue(kCommand2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800883 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800884 *command2, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
885 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800886 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800887 EXPECT_EQ("2", last_tags);
888 last_tags.clear();
889
890 const char kCommand3[] = R"({
891 "name": "trait2.command2",
892 "component": "comp2",
893 "parameters": {}
894 })";
895 auto command3 = CreateDictionaryValue(kCommand3);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800896 command_instance = manager_.ParseCommandInstance(
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800897 *command3, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
898 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800899 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -0800900 EXPECT_EQ("3", last_tags);
901 last_tags.clear();
902}
903
Vitaly Bukaece713e2015-12-09 10:59:33 -0800904TEST_F(ComponentManagerTest, AddDefaultCommandHandler) {
Alex Vakulenko20334332015-12-08 13:19:49 -0800905 const char kTraits[] = R"({
906 "trait1": {
907 "commands": {
908 "command1": { "minimalRole": "user" }
909 }
910 },
911 "trait2": {
912 "commands": {
913 "command2": { "minimalRole": "user" }
914 }
915 }
916 })";
917 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800918 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
919 ASSERT_TRUE(manager_.AddComponent("", "comp", {"trait1", "trait2"}, nullptr));
Alex Vakulenko20334332015-12-08 13:19:49 -0800920
921 int count = 0;
922 auto handler = [&count](int tag, const std::weak_ptr<Command>& command) {
923 count++;
924 };
925
Vitaly Bukaece713e2015-12-09 10:59:33 -0800926 manager_.AddCommandHandler("", "", base::Bind(handler, 1));
Alex Vakulenko20334332015-12-08 13:19:49 -0800927 EXPECT_EQ(0, count);
928
929 const char kCommand1[] = R"({
930 "name": "trait1.command1",
931 "component": "comp"
932 })";
933 auto command1 = CreateDictionaryValue(kCommand1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800934 auto command_instance = manager_.ParseCommandInstance(
Alex Vakulenko20334332015-12-08 13:19:49 -0800935 *command1, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
936 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800937 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko20334332015-12-08 13:19:49 -0800938 EXPECT_EQ(1, count);
939
940 const char kCommand2[] = R"({
941 "name": "trait2.command2",
942 "component": "comp"
943 })";
944 auto command2 = CreateDictionaryValue(kCommand2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800945 command_instance = manager_.ParseCommandInstance(
Alex Vakulenko20334332015-12-08 13:19:49 -0800946 *command2, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
947 ASSERT_NE(nullptr, command_instance.get());
Vitaly Bukaece713e2015-12-09 10:59:33 -0800948 manager_.AddCommand(std::move(command_instance));
Alex Vakulenko20334332015-12-08 13:19:49 -0800949 EXPECT_EQ(2, count);
950}
951
Vitaly Bukaece713e2015-12-09 10:59:33 -0800952TEST_F(ComponentManagerTest, SetStateProperties) {
953 CreateTestComponentTree(&manager_);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800954
955 const char kState1[] = R"({"t1": {"p1": 0, "p2": "foo"}})";
956 auto state1 = CreateDictionaryValue(kState1);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800957 ASSERT_TRUE(manager_.SetStateProperties("comp1", *state1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800958 const char kExpected1[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800959 "comp1": {
960 "traits": [ "t1" ],
961 "state": {"t1": {"p1": 0, "p2": "foo"}},
962 "components": {
963 "comp2": [
964 {
965 "traits": [ "t2" ]
966 },
967 {
968 "traits": [ "t3" ],
969 "components": {
970 "comp3": {
971 "traits": [ "t4" ],
972 "components": {
973 "comp4": {
974 "traits": [ "t5", "t6" ]
975 }
976 }
977 }
978 }
979 }
980 ]
981 }
982 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800983 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -0800984 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800985
986 const char kState2[] = R"({"t1": {"p1": {"bar": "baz"}}})";
987 auto state2 = CreateDictionaryValue(kState2);
Vitaly Bukaece713e2015-12-09 10:59:33 -0800988 ASSERT_TRUE(manager_.SetStateProperties("comp1", *state2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -0800989
990 const char kExpected2[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -0800991 "comp1": {
992 "traits": [ "t1" ],
993 "state": {"t1": {"p1": {"bar": "baz"}, "p2": "foo"}},
994 "components": {
995 "comp2": [
996 {
997 "traits": [ "t2" ]
998 },
999 {
1000 "traits": [ "t3" ],
1001 "components": {
1002 "comp3": {
1003 "traits": [ "t4" ],
1004 "components": {
1005 "comp4": {
1006 "traits": [ "t5", "t6" ]
1007 }
1008 }
1009 }
1010 }
1011 }
1012 ]
1013 }
1014 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001015 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001016 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001017
1018 const char kState3[] = R"({"t5": {"p1": 1}})";
1019 auto state3 = CreateDictionaryValue(kState3);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001020 ASSERT_TRUE(manager_.SetStateProperties("comp1.comp2[1].comp3.comp4", *state3,
1021 nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001022
1023 const char kExpected3[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001024 "comp1": {
1025 "traits": [ "t1" ],
1026 "state": {"t1": {"p1": {"bar": "baz"}, "p2": "foo"}},
1027 "components": {
1028 "comp2": [
1029 {
1030 "traits": [ "t2" ]
1031 },
1032 {
1033 "traits": [ "t3" ],
1034 "components": {
1035 "comp3": {
1036 "traits": [ "t4" ],
1037 "components": {
1038 "comp4": {
1039 "traits": [ "t5", "t6" ],
1040 "state": { "t5": { "p1": 1 } }
1041 }
1042 }
1043 }
1044 }
1045 }
1046 ]
1047 }
1048 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001049 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001050 EXPECT_JSON_EQ(kExpected3, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001051}
1052
Vitaly Bukaece713e2015-12-09 10:59:33 -08001053TEST_F(ComponentManagerTest, SetStatePropertiesFromJson) {
1054 CreateTestComponentTree(&manager_);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001055
Vitaly Bukaece713e2015-12-09 10:59:33 -08001056 ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
Vitaly Buka34668e72015-12-15 14:46:47 -08001057 "comp1.comp2[1].comp3.comp4",
1058 R"({"t5": {"p1": 3}, "t6": {"p2": 5}})", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001059
1060 const char kExpected[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001061 "comp1": {
1062 "traits": [ "t1" ],
1063 "components": {
1064 "comp2": [
1065 {
1066 "traits": [ "t2" ]
1067 },
1068 {
1069 "traits": [ "t3" ],
1070 "components": {
1071 "comp3": {
1072 "traits": [ "t4" ],
1073 "components": {
1074 "comp4": {
1075 "traits": [ "t5", "t6" ],
1076 "state": {
1077 "t5": { "p1": 3 },
1078 "t6": { "p2": 5 }
1079 }
1080 }
1081 }
1082 }
1083 }
1084 }
1085 ]
1086 }
1087 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001088 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001089 EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001090}
1091
Vitaly Bukaece713e2015-12-09 10:59:33 -08001092TEST_F(ComponentManagerTest, SetGetStateProperty) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001093 const char kTraits[] = R"({
1094 "trait1": {
1095 "state": {
1096 "prop1": { "type": "string" },
1097 "prop2": { "type": "integer" }
1098 }
1099 },
1100 "trait2": {
1101 "state": {
1102 "prop3": { "type": "string" },
1103 "prop4": { "type": "string" }
1104 }
1105 }
1106 })";
1107 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001108 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1109 ASSERT_TRUE(
1110 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001111
1112 base::StringValue p1("foo");
Vitaly Bukaece713e2015-12-09 10:59:33 -08001113 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001114
1115 const char kExpected1[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001116 "comp1": {
1117 "traits": [ "trait1", "trait2" ],
1118 "state": {
1119 "trait1": { "prop1": "foo" }
1120 }
1121 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001122 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001123 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001124
1125 base::FundamentalValue p2(2);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001126 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait2.prop3", p2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001127
1128 const char kExpected2[] = R"({
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001129 "comp1": {
1130 "traits": [ "trait1", "trait2" ],
1131 "state": {
1132 "trait1": { "prop1": "foo" },
1133 "trait2": { "prop3": 2 }
1134 }
1135 }
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001136 })";
Vitaly Bukaece713e2015-12-09 10:59:33 -08001137 EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001138 // Just the package name without property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001139 EXPECT_FALSE(manager_.SetStateProperty("comp1", "trait2", p2, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001140
Vitaly Bukaece713e2015-12-09 10:59:33 -08001141 const base::Value* value =
1142 manager_.GetStateProperty("comp1", "trait1.prop1", nullptr);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001143 ASSERT_NE(nullptr, value);
1144 EXPECT_TRUE(p1.Equals(value));
Vitaly Bukaece713e2015-12-09 10:59:33 -08001145 value = manager_.GetStateProperty("comp1", "trait2.prop3", nullptr);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001146 ASSERT_NE(nullptr, value);
1147 EXPECT_TRUE(p2.Equals(value));
1148
1149 // Non-existing property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001150 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp1", "trait2.p", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001151 // Non-existing component
Vitaly Bukaece713e2015-12-09 10:59:33 -08001152 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp2", "trait.prop", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001153 // Just the package name without property:
Vitaly Bukaece713e2015-12-09 10:59:33 -08001154 EXPECT_EQ(nullptr, manager_.GetStateProperty("comp1", "trait2", nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001155}
1156
Vitaly Bukaece713e2015-12-09 10:59:33 -08001157TEST_F(ComponentManagerTest, AddStateChangedCallback) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001158 const char kTraits[] = R"({
1159 "trait1": {
1160 "state": {
1161 "prop1": { "type": "string" },
1162 "prop2": { "type": "string" }
1163 }
1164 }
1165 })";
1166 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001167 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1168 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001169
1170 int count = 0;
1171 int count2 = 0;
Vitaly Bukaece713e2015-12-09 10:59:33 -08001172 manager_.AddStateChangedCallback(base::Bind([&count]() { count++; }));
1173 manager_.AddStateChangedCallback(base::Bind([&count2]() { count2++; }));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001174 EXPECT_EQ(1, count);
1175 EXPECT_EQ(1, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001176 EXPECT_EQ(0u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001177
1178 base::StringValue p1("foo");
Vitaly Bukaece713e2015-12-09 10:59:33 -08001179 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001180 EXPECT_EQ(2, count);
1181 EXPECT_EQ(2, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001182 EXPECT_EQ(1u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001183
Vitaly Bukaece713e2015-12-09 10:59:33 -08001184 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001185 EXPECT_EQ(3, count);
1186 EXPECT_EQ(3, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001187 EXPECT_EQ(2u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001188
1189 // Fail - no component.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001190 ASSERT_FALSE(manager_.SetStateProperty("comp2", "trait1.prop2", p1, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001191 EXPECT_EQ(3, count);
1192 EXPECT_EQ(3, count2);
Johan Euphrosine6fdca1f2015-12-11 09:20:02 +00001193 EXPECT_EQ(2u, manager_.GetLastStateChangeId());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001194}
1195
Vitaly Bukaece713e2015-12-09 10:59:33 -08001196TEST_F(ComponentManagerTest, ComponentStateUpdates) {
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001197 const char kTraits[] = R"({
1198 "trait1": {
1199 "state": {
1200 "prop1": { "type": "string" },
1201 "prop2": { "type": "string" }
1202 }
1203 },
1204 "trait2": {
1205 "state": {
1206 "prop3": { "type": "string" },
1207 "prop4": { "type": "string" }
1208 }
1209 }
1210 })";
1211 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001212 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1213 ASSERT_TRUE(
1214 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
1215 ASSERT_TRUE(
1216 manager_.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001217
1218 std::vector<ComponentManager::UpdateID> updates1;
1219 auto callback1 = [&updates1](ComponentManager::UpdateID id) {
1220 updates1.push_back(id);
1221 };
1222 // State change queue is empty, callback should be called immediately.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001223 auto token1 = manager_.AddServerStateUpdatedCallback(base::Bind(callback1));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001224 ASSERT_EQ(1u, updates1.size());
Vitaly Bukaece713e2015-12-09 10:59:33 -08001225 EXPECT_EQ(manager_.GetLastStateChangeId(), updates1.front());
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001226 updates1.clear();
1227
1228 base::StringValue foo("foo");
1229 base::Time time1 = base::Time::Now();
Vitaly Bukaece713e2015-12-09 10:59:33 -08001230 EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(time1));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001231 // These three updates should be grouped into two separate state change queue
1232 // items, since they all happen at the same time, but for two different
1233 // components.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001234 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", foo, nullptr));
1235 ASSERT_TRUE(manager_.SetStateProperty("comp2", "trait2.prop3", foo, nullptr));
1236 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", foo, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001237
1238 std::vector<ComponentManager::UpdateID> updates2;
1239 auto callback2 = [&updates2](ComponentManager::UpdateID id) {
1240 updates2.push_back(id);
1241 };
1242 // State change queue is not empty, so callback will be called later.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001243 auto token2 = manager_.AddServerStateUpdatedCallback(base::Bind(callback2));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001244 EXPECT_TRUE(updates2.empty());
1245
1246 base::StringValue bar("bar");
1247 base::Time time2 = time1 + base::TimeDelta::FromSeconds(1);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001248 EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(time2));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001249 // Two more update events (as above) but at |time2|.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001250 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", bar, nullptr));
1251 ASSERT_TRUE(manager_.SetStateProperty("comp2", "trait2.prop3", bar, nullptr));
1252 ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", bar, nullptr));
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001253
Vitaly Bukaece713e2015-12-09 10:59:33 -08001254 auto snapshot = manager_.GetAndClearRecordedStateChanges();
1255 EXPECT_EQ(manager_.GetLastStateChangeId(), snapshot.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001256 ASSERT_EQ(4u, snapshot.state_changes.size());
1257
1258 EXPECT_EQ("comp1", snapshot.state_changes[0].component);
1259 EXPECT_EQ(time1, snapshot.state_changes[0].timestamp);
1260 EXPECT_JSON_EQ(R"({"trait1":{"prop1":"foo","prop2":"foo"}})",
1261 *snapshot.state_changes[0].changed_properties);
1262
1263 EXPECT_EQ("comp2", snapshot.state_changes[1].component);
1264 EXPECT_EQ(time1, snapshot.state_changes[1].timestamp);
1265 EXPECT_JSON_EQ(R"({"trait2":{"prop3":"foo"}})",
1266 *snapshot.state_changes[1].changed_properties);
1267
1268 EXPECT_EQ("comp1", snapshot.state_changes[2].component);
1269 EXPECT_EQ(time2, snapshot.state_changes[2].timestamp);
1270 EXPECT_JSON_EQ(R"({"trait1":{"prop1":"bar","prop2":"bar"}})",
1271 *snapshot.state_changes[2].changed_properties);
1272
1273 EXPECT_EQ("comp2", snapshot.state_changes[3].component);
1274 EXPECT_EQ(time2, snapshot.state_changes[3].timestamp);
1275 EXPECT_JSON_EQ(R"({"trait2":{"prop3":"bar"}})",
1276 *snapshot.state_changes[3].changed_properties);
1277
1278 // Make sure previous GetAndClearRecordedStateChanges() clears the queue.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001279 auto snapshot2 = manager_.GetAndClearRecordedStateChanges();
1280 EXPECT_EQ(manager_.GetLastStateChangeId(), snapshot2.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001281 EXPECT_TRUE(snapshot2.state_changes.empty());
1282
1283 // Now indicate that we have update the changes on the server.
Vitaly Bukaece713e2015-12-09 10:59:33 -08001284 manager_.NotifyStateUpdatedOnServer(snapshot.update_id);
Alex Vakulenko7b588fc2015-12-04 16:03:59 -08001285 ASSERT_EQ(1u, updates1.size());
1286 EXPECT_EQ(snapshot.update_id, updates1.front());
1287 ASSERT_EQ(1u, updates2.size());
1288 EXPECT_EQ(snapshot.update_id, updates2.front());
1289}
1290
Vitaly Bukaece713e2015-12-09 10:59:33 -08001291TEST_F(ComponentManagerTest, FindComponentWithTrait) {
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001292 const char kTraits[] = R"({
1293 "trait1": {},
1294 "trait2": {},
1295 "trait3": {}
1296 })";
1297 auto traits = CreateDictionaryValue(kTraits);
Vitaly Bukaece713e2015-12-09 10:59:33 -08001298 ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
1299 ASSERT_TRUE(
1300 manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
1301 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait3"}, nullptr));
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001302
Vitaly Bukaece713e2015-12-09 10:59:33 -08001303 EXPECT_EQ("comp1", manager_.FindComponentWithTrait("trait1"));
1304 EXPECT_EQ("comp1", manager_.FindComponentWithTrait("trait2"));
1305 EXPECT_EQ("comp2", manager_.FindComponentWithTrait("trait3"));
1306 EXPECT_EQ("", manager_.FindComponentWithTrait("trait4"));
Alex Vakulenkoa3c5e6d2015-12-04 17:54:38 -08001307}
1308
Vitaly Bukaece713e2015-12-09 10:59:33 -08001309TEST_F(ComponentManagerTest, TestMockComponentManager) {
Alex Vakulenkoba981152015-12-05 13:58:22 -08001310 // Check that all the virtual methods are mocked out.
Vitaly Buka012cd982016-02-22 17:18:49 -08001311 test::MockComponentManager mock;
Alex Vakulenkoba981152015-12-05 13:58:22 -08001312}
1313
Alex Vakulenko0d3062e2016-02-23 16:03:43 -08001314TEST_F(ComponentManagerTest, GetComponentsForUserRole) {
1315 const char kTraits[] = R"({
1316 "trait1": {
1317 "state": {
1318 "prop1": { "type": "string", "minimalRole": "viewer" },
1319 "prop2": { "type": "string", "minimalRole": "user" }
1320 }
1321 },
1322 "trait2": {
1323 "state": {
1324 "prop3": { "type": "string", "minimalRole": "manager" },
1325 "prop4": { "type": "string", "minimalRole": "owner" }
1326 }
1327 },
1328 "trait3": {
1329 "state": {
1330 "prop5": { "type": "string" }
1331 }
1332 }
1333 })";
1334 auto json = CreateDictionaryValue(kTraits);
1335 ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
1336 ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1", "trait2"},
1337 nullptr));
1338 ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait2"}, nullptr));
1339 ASSERT_TRUE(manager_.AddComponentArrayItem("comp2", "comp3", {"trait3"},
1340 nullptr));
1341 ASSERT_TRUE(manager_.AddComponent("comp2", "comp4", {"trait3"}, nullptr));
1342
1343 const char kComp1Properties[] = R"({
1344 "trait1": { "prop1": "foo", "prop2": "bar" },
1345 "trait2": { "prop3": "baz", "prop4": "quux" }
1346 })";
1347 ASSERT_TRUE(manager_.SetStatePropertiesFromJson("comp1", kComp1Properties,
1348 nullptr));
1349
1350 const char kComp2Properties[] = R"({
1351 "trait2": { "prop3": "foo", "prop4": "bar" }
1352 })";
1353 ASSERT_TRUE(manager_.SetStatePropertiesFromJson("comp2", kComp2Properties,
1354 nullptr));
1355
1356 const char kComp3Properties[] = R"({
1357 "trait3": { "prop5": "foo" }
1358 })";
1359 ASSERT_TRUE(manager_.SetStatePropertiesFromJson("comp2.comp3[0]",
1360 kComp3Properties, nullptr));
1361
1362 const char kComp4Properties[] = R"({
1363 "trait3": { "prop5": "bar" }
1364 })";
1365 ASSERT_TRUE(manager_.SetStatePropertiesFromJson("comp2.comp4",
1366 kComp4Properties, nullptr));
1367
1368 const char kExpected1[] = R"({
1369 "comp1": {
1370 "traits": [ "trait1", "trait2" ],
1371 "state": {
1372 "trait1": {
1373 "prop1": "foo",
1374 "prop2": "bar"
1375 },
1376 "trait2": {
1377 "prop3": "baz",
1378 "prop4": "quux"
1379 }
1380 }
1381 },
1382 "comp2": {
1383 "traits": [ "trait2" ],
1384 "state": {
1385 "trait2": {
1386 "prop3": "foo",
1387 "prop4": "bar"
1388 }
1389 },
1390 "components": {
1391 "comp3": [
1392 {
1393 "traits": [ "trait3" ],
1394 "state": {
1395 "trait3": {
1396 "prop5": "foo"
1397 }
1398 }
1399 }
1400 ],
1401 "comp4": {
1402 "traits": [ "trait3" ],
1403 "state": {
1404 "trait3": {
1405 "prop5": "bar"
1406 }
1407 }
1408 }
1409 }
1410 }
1411 })";
1412 EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
1413
1414 EXPECT_JSON_EQ(kExpected1,
1415 *manager_.GetComponentsForUserRole(UserRole::kOwner));
1416
1417 const char kExpected2[] = R"({
1418 "comp1": {
1419 "traits": [ "trait1", "trait2" ],
1420 "state": {
1421 "trait1": {
1422 "prop1": "foo",
1423 "prop2": "bar"
1424 },
1425 "trait2": {
1426 "prop3": "baz"
1427 }
1428 }
1429 },
1430 "comp2": {
1431 "traits": [ "trait2" ],
1432 "state": {
1433 "trait2": {
1434 "prop3": "foo"
1435 }
1436 },
1437 "components": {
1438 "comp3": [
1439 {
1440 "traits": [ "trait3" ],
1441 "state": {
1442 "trait3": {
1443 "prop5": "foo"
1444 }
1445 }
1446 }
1447 ],
1448 "comp4": {
1449 "traits": [ "trait3" ],
1450 "state": {
1451 "trait3": {
1452 "prop5": "bar"
1453 }
1454 }
1455 }
1456 }
1457 }
1458 })";
1459 EXPECT_JSON_EQ(kExpected2,
1460 *manager_.GetComponentsForUserRole(UserRole::kManager));
1461
1462 const char kExpected3[] = R"({
1463 "comp1": {
1464 "traits": [ "trait1", "trait2" ],
1465 "state": {
1466 "trait1": {
1467 "prop1": "foo",
1468 "prop2": "bar"
1469 }
1470 }
1471 },
1472 "comp2": {
1473 "traits": [ "trait2" ],
1474 "components": {
1475 "comp3": [
1476 {
1477 "traits": [ "trait3" ],
1478 "state": {
1479 "trait3": {
1480 "prop5": "foo"
1481 }
1482 }
1483 }
1484 ],
1485 "comp4": {
1486 "traits": [ "trait3" ],
1487 "state": {
1488 "trait3": {
1489 "prop5": "bar"
1490 }
1491 }
1492 }
1493 }
1494 }
1495 })";
1496 EXPECT_JSON_EQ(kExpected3,
1497 *manager_.GetComponentsForUserRole(UserRole::kUser));
1498
1499 const char kExpected4[] = R"({
1500 "comp1": {
1501 "traits": [ "trait1", "trait2" ],
1502 "state": {
1503 "trait1": {
1504 "prop1": "foo"
1505 }
1506 }
1507 },
1508 "comp2": {
1509 "traits": [ "trait2" ],
1510 "components": {
1511 "comp3": [
1512 {
1513 "traits": [ "trait3" ]
1514 }
1515 ],
1516 "comp4": {
1517 "traits": [ "trait3" ]
1518 }
1519 }
1520 }
1521 })";
1522 EXPECT_JSON_EQ(kExpected4,
1523 *manager_.GetComponentsForUserRole(UserRole::kViewer));
1524}
1525
Alex Vakulenko44c1dbe2015-12-03 15:35:09 -08001526} // namespace weave