1 // Copyright 2014 The Chromium OS 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
5 #include <brillo/dbus/exported_property_set.h>
6
7 #include <string>
8 #include <vector>
9
10 #include <base/bind.h>
11 #include <base/macros.h>
12 #include <brillo/dbus/dbus_object.h>
13 #include <brillo/dbus/dbus_object_test_helpers.h>
14 #include <brillo/errors/error_codes.h>
15 #include <dbus/message.h>
16 #include <dbus/property.h>
17 #include <dbus/object_path.h>
18 #include <dbus/mock_bus.h>
19 #include <dbus/mock_exported_object.h>
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22
23 using ::testing::AnyNumber;
24 using ::testing::Return;
25 using ::testing::Invoke;
26 using ::testing::_;
27 using ::testing::Unused;
28
29 namespace brillo {
30
31 namespace dbus_utils {
32
33 namespace {
34
35 const char kBoolPropName[] = "BoolProp";
36 const char kUint8PropName[] = "Uint8Prop";
37 const char kInt16PropName[] = "Int16Prop";
38 const char kUint16PropName[] = "Uint16Prop";
39 const char kInt32PropName[] = "Int32Prop";
40 const char kUint32PropName[] = "Uint32Prop";
41 const char kInt64PropName[] = "Int64Prop";
42 const char kUint64PropName[] = "Uint64Prop";
43 const char kDoublePropName[] = "DoubleProp";
44 const char kStringPropName[] = "StringProp";
45 const char kPathPropName[] = "PathProp";
46 const char kStringListPropName[] = "StringListProp";
47 const char kPathListPropName[] = "PathListProp";
48 const char kUint8ListPropName[] = "Uint8ListProp";
49
50 const char kTestInterface1[] = "org.chromium.TestInterface1";
51 const char kTestInterface2[] = "org.chromium.TestInterface2";
52 const char kTestInterface3[] = "org.chromium.TestInterface3";
53
54 const std::string kTestString("lies");
55 const dbus::ObjectPath kMethodsExportedOnPath(std::string("/export"));
56 const dbus::ObjectPath kTestObjectPathInit(std::string("/path_init"));
57 const dbus::ObjectPath kTestObjectPathUpdate(std::string("/path_update"));
58
59 } // namespace
60
61 class ExportedPropertySetTest : public ::testing::Test {
62 public:
63 struct Properties {
64 public:
65 ExportedProperty<bool> bool_prop_;
66 ExportedProperty<uint8_t> uint8_prop_;
67 ExportedProperty<int16_t> int16_prop_;
68 ExportedProperty<uint16_t> uint16_prop_;
69 ExportedProperty<int32_t> int32_prop_;
70 ExportedProperty<uint32_t> uint32_prop_;
71 ExportedProperty<int64_t> int64_prop_;
72 ExportedProperty<uint64_t> uint64_prop_;
73 ExportedProperty<double> double_prop_;
74 ExportedProperty<std::string> string_prop_;
75 ExportedProperty<dbus::ObjectPath> path_prop_;
76 ExportedProperty<std::vector<std::string>> stringlist_prop_;
77 ExportedProperty<std::vector<dbus::ObjectPath>> pathlist_prop_;
78 ExportedProperty<std::vector<uint8_t>> uint8list_prop_;
79
Propertiesbrillo::dbus_utils::ExportedPropertySetTest::Properties80 Properties(scoped_refptr<dbus::Bus> bus, const dbus::ObjectPath& path)
81 : dbus_object_(nullptr, bus, path) {
82 // The empty string is not a valid value for an ObjectPath.
83 path_prop_.SetValue(kTestObjectPathInit);
84 DBusInterface* itf1 = dbus_object_.AddOrGetInterface(kTestInterface1);
85 itf1->AddProperty(kBoolPropName, &bool_prop_);
86 itf1->AddProperty(kUint8PropName, &uint8_prop_);
87 itf1->AddProperty(kInt16PropName, &int16_prop_);
88 // I chose this weird grouping because N=2 is about all the permutations
89 // of GetAll that I want to anticipate.
90 DBusInterface* itf2 = dbus_object_.AddOrGetInterface(kTestInterface2);
91 itf2->AddProperty(kUint16PropName, &uint16_prop_);
92 itf2->AddProperty(kInt32PropName, &int32_prop_);
93 DBusInterface* itf3 = dbus_object_.AddOrGetInterface(kTestInterface3);
94 itf3->AddProperty(kUint32PropName, &uint32_prop_);
95 itf3->AddProperty(kInt64PropName, &int64_prop_);
96 itf3->AddProperty(kUint64PropName, &uint64_prop_);
97 itf3->AddProperty(kDoublePropName, &double_prop_);
98 itf3->AddProperty(kStringPropName, &string_prop_);
99 itf3->AddProperty(kPathPropName, &path_prop_);
100 itf3->AddProperty(kStringListPropName, &stringlist_prop_);
101 itf3->AddProperty(kPathListPropName, &pathlist_prop_);
102 itf3->AddProperty(kUint8ListPropName, &uint8list_prop_);
103 dbus_object_.RegisterAsync(
104 AsyncEventSequencer::GetDefaultCompletionAction());
105 }
~Propertiesbrillo::dbus_utils::ExportedPropertySetTest::Properties106 virtual ~Properties() {}
107
108 DBusObject dbus_object_;
109 };
110
SetUp()111 void SetUp() override {
112 dbus::Bus::Options options;
113 options.bus_type = dbus::Bus::SYSTEM;
114 bus_ = new dbus::MockBus(options);
115 // By default, don't worry about threading assertions.
116 EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber());
117 EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
118 // Use a mock exported object.
119 mock_exported_object_ =
120 new dbus::MockExportedObject(bus_.get(), kMethodsExportedOnPath);
121 EXPECT_CALL(*bus_, GetExportedObject(kMethodsExportedOnPath))
122 .Times(1).WillOnce(Return(mock_exported_object_.get()));
123
124 EXPECT_CALL(*mock_exported_object_,
125 ExportMethod(dbus::kPropertiesInterface, _, _, _)).Times(3);
126 p_.reset(new Properties(bus_, kMethodsExportedOnPath));
127 }
128
TearDown()129 void TearDown() override {
130 EXPECT_CALL(*mock_exported_object_, Unregister()).Times(1);
131 }
132
AssertMethodReturnsError(dbus::MethodCall * method_call)133 void AssertMethodReturnsError(dbus::MethodCall* method_call) {
134 method_call->SetSerial(123);
135 auto response = testing::CallMethod(p_->dbus_object_, method_call);
136 ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
137 }
138
GetPropertyOnInterface(const std::string & interface_name,const std::string & property_name)139 std::unique_ptr<dbus::Response> GetPropertyOnInterface(
140 const std::string& interface_name,
141 const std::string& property_name) {
142 dbus::MethodCall method_call(dbus::kPropertiesInterface,
143 dbus::kPropertiesGet);
144 method_call.SetSerial(123);
145 dbus::MessageWriter writer(&method_call);
146 writer.AppendString(interface_name);
147 writer.AppendString(property_name);
148 return testing::CallMethod(p_->dbus_object_, &method_call);
149 }
150
SetPropertyOnInterface(const std::string & interface_name,const std::string & property_name,const brillo::Any & value)151 std::unique_ptr<dbus::Response> SetPropertyOnInterface(
152 const std::string& interface_name,
153 const std::string& property_name,
154 const brillo::Any& value) {
155 dbus::MethodCall method_call(dbus::kPropertiesInterface,
156 dbus::kPropertiesSet);
157 method_call.SetSerial(123);
158 dbus::MessageWriter writer(&method_call);
159 writer.AppendString(interface_name);
160 writer.AppendString(property_name);
161 dbus_utils::AppendValueToWriter(&writer, value);
162 return testing::CallMethod(p_->dbus_object_, &method_call);
163 }
164
165 std::unique_ptr<dbus::Response> last_response_;
166 scoped_refptr<dbus::MockBus> bus_;
167 scoped_refptr<dbus::MockExportedObject> mock_exported_object_;
168 std::unique_ptr<Properties> p_;
169 };
170
171 template<typename T>
172 class PropertyValidatorObserver {
173 public:
PropertyValidatorObserver()174 PropertyValidatorObserver()
175 : validate_property_callback_(
176 base::Bind(&PropertyValidatorObserver::ValidateProperty,
177 base::Unretained(this))) {}
~PropertyValidatorObserver()178 virtual ~PropertyValidatorObserver() {}
179
180 MOCK_METHOD2_T(ValidateProperty,
181 bool(brillo::ErrorPtr* error, const T& value));
182
183 const base::Callback<bool(brillo::ErrorPtr*, const T&)>&
validate_property_callback() const184 validate_property_callback() const {
185 return validate_property_callback_;
186 }
187
188 private:
189 base::Callback<bool(brillo::ErrorPtr*, const T&)>
190 validate_property_callback_;
191
192 DISALLOW_COPY_AND_ASSIGN(PropertyValidatorObserver);
193 };
194
TEST_F(ExportedPropertySetTest,UpdateNotifications)195 TEST_F(ExportedPropertySetTest, UpdateNotifications) {
196 EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(14);
197 p_->bool_prop_.SetValue(true);
198 p_->uint8_prop_.SetValue(1);
199 p_->int16_prop_.SetValue(1);
200 p_->uint16_prop_.SetValue(1);
201 p_->int32_prop_.SetValue(1);
202 p_->uint32_prop_.SetValue(1);
203 p_->int64_prop_.SetValue(1);
204 p_->uint64_prop_.SetValue(1);
205 p_->double_prop_.SetValue(1.0);
206 p_->string_prop_.SetValue(kTestString);
207 p_->path_prop_.SetValue(kTestObjectPathUpdate);
208 p_->stringlist_prop_.SetValue({kTestString});
209 p_->pathlist_prop_.SetValue({kTestObjectPathUpdate});
210 p_->uint8list_prop_.SetValue({1});
211 }
212
TEST_F(ExportedPropertySetTest,UpdateToSameValue)213 TEST_F(ExportedPropertySetTest, UpdateToSameValue) {
214 EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(1);
215 p_->bool_prop_.SetValue(true);
216 p_->bool_prop_.SetValue(true);
217 }
218
TEST_F(ExportedPropertySetTest,GetAllNoArgs)219 TEST_F(ExportedPropertySetTest, GetAllNoArgs) {
220 dbus::MethodCall method_call(dbus::kPropertiesInterface,
221 dbus::kPropertiesGetAll);
222 AssertMethodReturnsError(&method_call);
223 }
224
TEST_F(ExportedPropertySetTest,GetAllInvalidInterface)225 TEST_F(ExportedPropertySetTest, GetAllInvalidInterface) {
226 dbus::MethodCall method_call(dbus::kPropertiesInterface,
227 dbus::kPropertiesGetAll);
228 method_call.SetSerial(123);
229 dbus::MessageWriter writer(&method_call);
230 writer.AppendString("org.chromium.BadInterface");
231 auto response = testing::CallMethod(p_->dbus_object_, &method_call);
232 dbus::MessageReader response_reader(response.get());
233 dbus::MessageReader dict_reader(nullptr);
234 ASSERT_TRUE(response_reader.PopArray(&dict_reader));
235 // The response should just be a an empty array, since there are no properties
236 // on this interface. The spec doesn't say much about error conditions here,
237 // so I'm going to assume this is a valid implementation.
238 ASSERT_FALSE(dict_reader.HasMoreData());
239 ASSERT_FALSE(response_reader.HasMoreData());
240 }
241
TEST_F(ExportedPropertySetTest,GetAllExtraArgs)242 TEST_F(ExportedPropertySetTest, GetAllExtraArgs) {
243 dbus::MethodCall method_call(dbus::kPropertiesInterface,
244 dbus::kPropertiesGetAll);
245 dbus::MessageWriter writer(&method_call);
246 writer.AppendString(kTestInterface1);
247 writer.AppendString(kTestInterface1);
248 AssertMethodReturnsError(&method_call);
249 }
250
TEST_F(ExportedPropertySetTest,GetAllCorrectness)251 TEST_F(ExportedPropertySetTest, GetAllCorrectness) {
252 dbus::MethodCall method_call(dbus::kPropertiesInterface,
253 dbus::kPropertiesGetAll);
254 method_call.SetSerial(123);
255 dbus::MessageWriter writer(&method_call);
256 writer.AppendString(kTestInterface2);
257 auto response = testing::CallMethod(p_->dbus_object_, &method_call);
258 dbus::MessageReader response_reader(response.get());
259 dbus::MessageReader dict_reader(nullptr);
260 dbus::MessageReader entry_reader(nullptr);
261 ASSERT_TRUE(response_reader.PopArray(&dict_reader));
262 ASSERT_TRUE(dict_reader.PopDictEntry(&entry_reader));
263 std::string property_name;
264 ASSERT_TRUE(entry_reader.PopString(&property_name));
265 uint16_t value16;
266 int32_t value32;
267 if (property_name.compare(kUint16PropName) == 0) {
268 ASSERT_TRUE(entry_reader.PopVariantOfUint16(&value16));
269 ASSERT_FALSE(entry_reader.HasMoreData());
270 ASSERT_TRUE(dict_reader.PopDictEntry(&entry_reader));
271 ASSERT_TRUE(entry_reader.PopString(&property_name));
272 ASSERT_EQ(property_name.compare(kInt32PropName), 0);
273 ASSERT_TRUE(entry_reader.PopVariantOfInt32(&value32));
274 } else {
275 ASSERT_EQ(property_name.compare(kInt32PropName), 0);
276 ASSERT_TRUE(entry_reader.PopVariantOfInt32(&value32));
277 ASSERT_FALSE(entry_reader.HasMoreData());
278 ASSERT_TRUE(dict_reader.PopDictEntry(&entry_reader));
279 ASSERT_TRUE(entry_reader.PopString(&property_name));
280 ASSERT_EQ(property_name.compare(kUint16PropName), 0);
281 ASSERT_TRUE(entry_reader.PopVariantOfUint16(&value16));
282 }
283 ASSERT_FALSE(entry_reader.HasMoreData());
284 ASSERT_FALSE(dict_reader.HasMoreData());
285 ASSERT_FALSE(response_reader.HasMoreData());
286 }
287
TEST_F(ExportedPropertySetTest,GetNoArgs)288 TEST_F(ExportedPropertySetTest, GetNoArgs) {
289 dbus::MethodCall method_call(dbus::kPropertiesInterface,
290 dbus::kPropertiesGet);
291 AssertMethodReturnsError(&method_call);
292 }
293
TEST_F(ExportedPropertySetTest,GetInvalidInterface)294 TEST_F(ExportedPropertySetTest, GetInvalidInterface) {
295 dbus::MethodCall method_call(dbus::kPropertiesInterface,
296 dbus::kPropertiesGet);
297 dbus::MessageWriter writer(&method_call);
298 writer.AppendString("org.chromium.BadInterface");
299 writer.AppendString(kInt16PropName);
300 AssertMethodReturnsError(&method_call);
301 }
302
TEST_F(ExportedPropertySetTest,GetBadPropertyName)303 TEST_F(ExportedPropertySetTest, GetBadPropertyName) {
304 dbus::MethodCall method_call(dbus::kPropertiesInterface,
305 dbus::kPropertiesGet);
306 dbus::MessageWriter writer(&method_call);
307 writer.AppendString(kTestInterface1);
308 writer.AppendString("IAmNotAProperty");
309 AssertMethodReturnsError(&method_call);
310 }
311
TEST_F(ExportedPropertySetTest,GetPropIfMismatch)312 TEST_F(ExportedPropertySetTest, GetPropIfMismatch) {
313 dbus::MethodCall method_call(dbus::kPropertiesInterface,
314 dbus::kPropertiesGet);
315 dbus::MessageWriter writer(&method_call);
316 writer.AppendString(kTestInterface1);
317 writer.AppendString(kStringPropName);
318 AssertMethodReturnsError(&method_call);
319 }
320
TEST_F(ExportedPropertySetTest,GetNoPropertyName)321 TEST_F(ExportedPropertySetTest, GetNoPropertyName) {
322 dbus::MethodCall method_call(dbus::kPropertiesInterface,
323 dbus::kPropertiesGet);
324 dbus::MessageWriter writer(&method_call);
325 writer.AppendString(kTestInterface1);
326 AssertMethodReturnsError(&method_call);
327 }
328
TEST_F(ExportedPropertySetTest,GetExtraArgs)329 TEST_F(ExportedPropertySetTest, GetExtraArgs) {
330 dbus::MethodCall method_call(dbus::kPropertiesInterface,
331 dbus::kPropertiesGet);
332 dbus::MessageWriter writer(&method_call);
333 writer.AppendString(kTestInterface1);
334 writer.AppendString(kBoolPropName);
335 writer.AppendString("Extra param");
336 AssertMethodReturnsError(&method_call);
337 }
338
TEST_F(ExportedPropertySetTest,GetRemovedProperty)339 TEST_F(ExportedPropertySetTest, GetRemovedProperty) {
340 DBusInterface* itf1 = p_->dbus_object_.AddOrGetInterface(kTestInterface1);
341 itf1->RemoveProperty(kBoolPropName);
342
343 auto response = GetPropertyOnInterface(kTestInterface1, kBoolPropName);
344 ASSERT_EQ(DBUS_ERROR_UNKNOWN_PROPERTY, response->GetErrorName());
345
346 // Signal should not be emitted for removed property.
347 EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(0);
348 p_->bool_prop_.SetValue(true);
349 }
350
TEST_F(ExportedPropertySetTest,GetWorksWithBool)351 TEST_F(ExportedPropertySetTest, GetWorksWithBool) {
352 auto response = GetPropertyOnInterface(kTestInterface1, kBoolPropName);
353 dbus::MessageReader reader(response.get());
354 bool value;
355 ASSERT_TRUE(reader.PopVariantOfBool(&value));
356 ASSERT_FALSE(reader.HasMoreData());
357 }
358
TEST_F(ExportedPropertySetTest,GetWorksWithUint8)359 TEST_F(ExportedPropertySetTest, GetWorksWithUint8) {
360 auto response = GetPropertyOnInterface(kTestInterface1, kUint8PropName);
361 dbus::MessageReader reader(response.get());
362 uint8_t value;
363 ASSERT_TRUE(reader.PopVariantOfByte(&value));
364 ASSERT_FALSE(reader.HasMoreData());
365 }
366
TEST_F(ExportedPropertySetTest,GetWorksWithInt16)367 TEST_F(ExportedPropertySetTest, GetWorksWithInt16) {
368 auto response = GetPropertyOnInterface(kTestInterface1, kInt16PropName);
369 dbus::MessageReader reader(response.get());
370 int16_t value;
371 ASSERT_TRUE(reader.PopVariantOfInt16(&value));
372 ASSERT_FALSE(reader.HasMoreData());
373 }
374
TEST_F(ExportedPropertySetTest,GetWorksWithUint16)375 TEST_F(ExportedPropertySetTest, GetWorksWithUint16) {
376 auto response = GetPropertyOnInterface(kTestInterface2, kUint16PropName);
377 dbus::MessageReader reader(response.get());
378 uint16_t value;
379 ASSERT_TRUE(reader.PopVariantOfUint16(&value));
380 ASSERT_FALSE(reader.HasMoreData());
381 }
382
TEST_F(ExportedPropertySetTest,GetWorksWithInt32)383 TEST_F(ExportedPropertySetTest, GetWorksWithInt32) {
384 auto response = GetPropertyOnInterface(kTestInterface2, kInt32PropName);
385 dbus::MessageReader reader(response.get());
386 int32_t value;
387 ASSERT_TRUE(reader.PopVariantOfInt32(&value));
388 ASSERT_FALSE(reader.HasMoreData());
389 }
390
TEST_F(ExportedPropertySetTest,GetWorksWithUint32)391 TEST_F(ExportedPropertySetTest, GetWorksWithUint32) {
392 auto response = GetPropertyOnInterface(kTestInterface3, kUint32PropName);
393 dbus::MessageReader reader(response.get());
394 uint32_t value;
395 ASSERT_TRUE(reader.PopVariantOfUint32(&value));
396 ASSERT_FALSE(reader.HasMoreData());
397 }
398
TEST_F(ExportedPropertySetTest,GetWorksWithInt64)399 TEST_F(ExportedPropertySetTest, GetWorksWithInt64) {
400 auto response = GetPropertyOnInterface(kTestInterface3, kInt64PropName);
401 dbus::MessageReader reader(response.get());
402 int64_t value;
403 ASSERT_TRUE(reader.PopVariantOfInt64(&value));
404 ASSERT_FALSE(reader.HasMoreData());
405 }
406
TEST_F(ExportedPropertySetTest,GetWorksWithUint64)407 TEST_F(ExportedPropertySetTest, GetWorksWithUint64) {
408 auto response = GetPropertyOnInterface(kTestInterface3, kUint64PropName);
409 dbus::MessageReader reader(response.get());
410 uint64_t value;
411 ASSERT_TRUE(reader.PopVariantOfUint64(&value));
412 ASSERT_FALSE(reader.HasMoreData());
413 }
414
TEST_F(ExportedPropertySetTest,GetWorksWithDouble)415 TEST_F(ExportedPropertySetTest, GetWorksWithDouble) {
416 auto response = GetPropertyOnInterface(kTestInterface3, kDoublePropName);
417 dbus::MessageReader reader(response.get());
418 double value;
419 ASSERT_TRUE(reader.PopVariantOfDouble(&value));
420 ASSERT_FALSE(reader.HasMoreData());
421 }
422
TEST_F(ExportedPropertySetTest,GetWorksWithString)423 TEST_F(ExportedPropertySetTest, GetWorksWithString) {
424 auto response = GetPropertyOnInterface(kTestInterface3, kStringPropName);
425 dbus::MessageReader reader(response.get());
426 std::string value;
427 ASSERT_TRUE(reader.PopVariantOfString(&value));
428 ASSERT_FALSE(reader.HasMoreData());
429 }
430
TEST_F(ExportedPropertySetTest,GetWorksWithPath)431 TEST_F(ExportedPropertySetTest, GetWorksWithPath) {
432 auto response = GetPropertyOnInterface(kTestInterface3, kPathPropName);
433 dbus::MessageReader reader(response.get());
434 dbus::ObjectPath value;
435 ASSERT_TRUE(reader.PopVariantOfObjectPath(&value));
436 ASSERT_FALSE(reader.HasMoreData());
437 }
438
TEST_F(ExportedPropertySetTest,GetWorksWithStringList)439 TEST_F(ExportedPropertySetTest, GetWorksWithStringList) {
440 auto response = GetPropertyOnInterface(kTestInterface3, kStringListPropName);
441 dbus::MessageReader reader(response.get());
442 dbus::MessageReader variant_reader(nullptr);
443 std::vector<std::string> value;
444 ASSERT_TRUE(reader.PopVariant(&variant_reader));
445 ASSERT_TRUE(variant_reader.PopArrayOfStrings(&value));
446 ASSERT_FALSE(variant_reader.HasMoreData());
447 ASSERT_FALSE(reader.HasMoreData());
448 }
449
TEST_F(ExportedPropertySetTest,GetWorksWithPathList)450 TEST_F(ExportedPropertySetTest, GetWorksWithPathList) {
451 auto response = GetPropertyOnInterface(kTestInterface3, kPathListPropName);
452 dbus::MessageReader reader(response.get());
453 dbus::MessageReader variant_reader(nullptr);
454 std::vector<dbus::ObjectPath> value;
455 ASSERT_TRUE(reader.PopVariant(&variant_reader));
456 ASSERT_TRUE(variant_reader.PopArrayOfObjectPaths(&value));
457 ASSERT_FALSE(variant_reader.HasMoreData());
458 ASSERT_FALSE(reader.HasMoreData());
459 }
460
TEST_F(ExportedPropertySetTest,GetWorksWithUint8List)461 TEST_F(ExportedPropertySetTest, GetWorksWithUint8List) {
462 auto response = GetPropertyOnInterface(kTestInterface3, kPathListPropName);
463 dbus::MessageReader reader(response.get());
464 dbus::MessageReader variant_reader(nullptr);
465 const uint8_t* buffer;
466 size_t buffer_len;
467 ASSERT_TRUE(reader.PopVariant(&variant_reader));
468 // |buffer| remains under the control of the MessageReader.
469 ASSERT_TRUE(variant_reader.PopArrayOfBytes(&buffer, &buffer_len));
470 ASSERT_FALSE(variant_reader.HasMoreData());
471 ASSERT_FALSE(reader.HasMoreData());
472 }
473
TEST_F(ExportedPropertySetTest,SetInvalidInterface)474 TEST_F(ExportedPropertySetTest, SetInvalidInterface) {
475 auto response = SetPropertyOnInterface(
476 "BadInterfaceName", kStringPropName, brillo::Any(kTestString));
477 ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
478 ASSERT_EQ(DBUS_ERROR_UNKNOWN_INTERFACE, response->GetErrorName());
479 }
480
TEST_F(ExportedPropertySetTest,SetBadPropertyName)481 TEST_F(ExportedPropertySetTest, SetBadPropertyName) {
482 auto response = SetPropertyOnInterface(
483 kTestInterface3, "IAmNotAProperty", brillo::Any(kTestString));
484 ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
485 ASSERT_EQ(DBUS_ERROR_UNKNOWN_PROPERTY, response->GetErrorName());
486 }
487
TEST_F(ExportedPropertySetTest,SetFailsWithReadOnlyProperty)488 TEST_F(ExportedPropertySetTest, SetFailsWithReadOnlyProperty) {
489 auto response = SetPropertyOnInterface(
490 kTestInterface3, kStringPropName, brillo::Any(kTestString));
491 ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
492 ASSERT_EQ(DBUS_ERROR_PROPERTY_READ_ONLY, response->GetErrorName());
493 }
494
TEST_F(ExportedPropertySetTest,SetFailsWithMismatchedValueType)495 TEST_F(ExportedPropertySetTest, SetFailsWithMismatchedValueType) {
496 p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite);
497 auto response = SetPropertyOnInterface(
498 kTestInterface3, kStringPropName, brillo::Any(true));
499 ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
500 ASSERT_EQ(DBUS_ERROR_INVALID_ARGS, response->GetErrorName());
501 }
502
503 namespace {
504
SetInvalidProperty(brillo::ErrorPtr * error,Unused)505 bool SetInvalidProperty(brillo::ErrorPtr* error, Unused) {
506 brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
507 DBUS_ERROR_INVALID_ARGS, "Invalid value");
508 return false;
509 }
510
511 } // namespace
512
TEST_F(ExportedPropertySetTest,SetFailsWithValidator)513 TEST_F(ExportedPropertySetTest, SetFailsWithValidator) {
514 PropertyValidatorObserver<std::string> property_validator;
515 p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite);
516 p_->string_prop_.SetValidator(
517 property_validator.validate_property_callback());
518
519 brillo::ErrorPtr error = brillo::Error::Create(
520 FROM_HERE, errors::dbus::kDomain, DBUS_ERROR_INVALID_ARGS, "");
521 EXPECT_CALL(property_validator, ValidateProperty(_, kTestString))
522 .WillOnce(Invoke(SetInvalidProperty));
523 auto response = SetPropertyOnInterface(
524 kTestInterface3, kStringPropName, brillo::Any(kTestString));
525 ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
526 ASSERT_EQ(DBUS_ERROR_INVALID_ARGS, response->GetErrorName());
527 }
528
TEST_F(ExportedPropertySetTest,SetWorksWithValidator)529 TEST_F(ExportedPropertySetTest, SetWorksWithValidator) {
530 PropertyValidatorObserver<std::string> property_validator;
531 p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite);
532 p_->string_prop_.SetValidator(
533 property_validator.validate_property_callback());
534
535 EXPECT_CALL(property_validator, ValidateProperty(_, kTestString))
536 .WillOnce(Return(true));
537 auto response = SetPropertyOnInterface(
538 kTestInterface3, kStringPropName, brillo::Any(kTestString));
539 ASSERT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
540 ASSERT_EQ(kTestString, p_->string_prop_.value());
541 }
542
TEST_F(ExportedPropertySetTest,SetWorksWithSameValue)543 TEST_F(ExportedPropertySetTest, SetWorksWithSameValue) {
544 PropertyValidatorObserver<std::string> property_validator;
545 p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite);
546 p_->string_prop_.SetValidator(
547 property_validator.validate_property_callback());
548 EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(1);
549 p_->string_prop_.SetValue(kTestString);
550
551 // No need to validate the value if it is the same as the current one.
552 EXPECT_CALL(property_validator, ValidateProperty(_, _)).Times(0);
553 auto response = SetPropertyOnInterface(
554 kTestInterface3, kStringPropName, brillo::Any(kTestString));
555 ASSERT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
556 ASSERT_EQ(kTestString, p_->string_prop_.value());
557 }
558
TEST_F(ExportedPropertySetTest,SetWorksWithoutValidator)559 TEST_F(ExportedPropertySetTest, SetWorksWithoutValidator) {
560 p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite);
561 auto response = SetPropertyOnInterface(
562 kTestInterface3, kStringPropName, brillo::Any(kTestString));
563 ASSERT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
564 ASSERT_EQ(kTestString, p_->string_prop_.value());
565 }
566
567 namespace {
568
VerifySignal(dbus::Signal * signal)569 void VerifySignal(dbus::Signal* signal) {
570 ASSERT_NE(signal, nullptr);
571 std::string interface_name;
572 std::string property_name;
573 uint8_t value;
574 dbus::MessageReader reader(signal);
575 dbus::MessageReader array_reader(signal);
576 dbus::MessageReader dict_reader(signal);
577 ASSERT_TRUE(reader.PopString(&interface_name));
578 ASSERT_TRUE(reader.PopArray(&array_reader));
579 ASSERT_TRUE(array_reader.PopDictEntry(&dict_reader));
580 ASSERT_TRUE(dict_reader.PopString(&property_name));
581 ASSERT_TRUE(dict_reader.PopVariantOfByte(&value));
582 ASSERT_FALSE(dict_reader.HasMoreData());
583 ASSERT_FALSE(array_reader.HasMoreData());
584 ASSERT_TRUE(reader.HasMoreData());
585 // Read the (empty) list of invalidated property names.
586 ASSERT_TRUE(reader.PopArray(&array_reader));
587 ASSERT_FALSE(array_reader.HasMoreData());
588 ASSERT_FALSE(reader.HasMoreData());
589 ASSERT_EQ(value, 57);
590 ASSERT_EQ(property_name, std::string(kUint8PropName));
591 ASSERT_EQ(interface_name, std::string(kTestInterface1));
592 }
593
594 } // namespace
595
TEST_F(ExportedPropertySetTest,SignalsAreParsable)596 TEST_F(ExportedPropertySetTest, SignalsAreParsable) {
597 EXPECT_CALL(*mock_exported_object_, SendSignal(_))
598 .Times(1).WillOnce(Invoke(&VerifySignal));
599 p_->uint8_prop_.SetValue(57);
600 }
601
602 } // namespace dbus_utils
603
604 } // namespace brillo
605