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 80 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 } 106 virtual ~Properties() {} 107 108 DBusObject dbus_object_; 109 }; 110 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 129 void TearDown() override { 130 EXPECT_CALL(*mock_exported_object_, Unregister()).Times(1); 131 } 132 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 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 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: 174 PropertyValidatorObserver() 175 : validate_property_callback_( 176 base::Bind(&PropertyValidatorObserver::ValidateProperty, 177 base::Unretained(this))) {} 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&)>& 184 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 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 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 219 TEST_F(ExportedPropertySetTest, GetAllNoArgs) { 220 dbus::MethodCall method_call(dbus::kPropertiesInterface, 221 dbus::kPropertiesGetAll); 222 AssertMethodReturnsError(&method_call); 223 } 224 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 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 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 288 TEST_F(ExportedPropertySetTest, GetNoArgs) { 289 dbus::MethodCall method_call(dbus::kPropertiesInterface, 290 dbus::kPropertiesGet); 291 AssertMethodReturnsError(&method_call); 292 } 293 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 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 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 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 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 339 TEST_F(ExportedPropertySetTest, GetWorksWithBool) { 340 auto response = GetPropertyOnInterface(kTestInterface1, kBoolPropName); 341 dbus::MessageReader reader(response.get()); 342 bool value; 343 ASSERT_TRUE(reader.PopVariantOfBool(&value)); 344 ASSERT_FALSE(reader.HasMoreData()); 345 } 346 347 TEST_F(ExportedPropertySetTest, GetWorksWithUint8) { 348 auto response = GetPropertyOnInterface(kTestInterface1, kUint8PropName); 349 dbus::MessageReader reader(response.get()); 350 uint8_t value; 351 ASSERT_TRUE(reader.PopVariantOfByte(&value)); 352 ASSERT_FALSE(reader.HasMoreData()); 353 } 354 355 TEST_F(ExportedPropertySetTest, GetWorksWithInt16) { 356 auto response = GetPropertyOnInterface(kTestInterface1, kInt16PropName); 357 dbus::MessageReader reader(response.get()); 358 int16_t value; 359 ASSERT_TRUE(reader.PopVariantOfInt16(&value)); 360 ASSERT_FALSE(reader.HasMoreData()); 361 } 362 363 TEST_F(ExportedPropertySetTest, GetWorksWithUint16) { 364 auto response = GetPropertyOnInterface(kTestInterface2, kUint16PropName); 365 dbus::MessageReader reader(response.get()); 366 uint16_t value; 367 ASSERT_TRUE(reader.PopVariantOfUint16(&value)); 368 ASSERT_FALSE(reader.HasMoreData()); 369 } 370 371 TEST_F(ExportedPropertySetTest, GetWorksWithInt32) { 372 auto response = GetPropertyOnInterface(kTestInterface2, kInt32PropName); 373 dbus::MessageReader reader(response.get()); 374 int32_t value; 375 ASSERT_TRUE(reader.PopVariantOfInt32(&value)); 376 ASSERT_FALSE(reader.HasMoreData()); 377 } 378 379 TEST_F(ExportedPropertySetTest, GetWorksWithUint32) { 380 auto response = GetPropertyOnInterface(kTestInterface3, kUint32PropName); 381 dbus::MessageReader reader(response.get()); 382 uint32_t value; 383 ASSERT_TRUE(reader.PopVariantOfUint32(&value)); 384 ASSERT_FALSE(reader.HasMoreData()); 385 } 386 387 TEST_F(ExportedPropertySetTest, GetWorksWithInt64) { 388 auto response = GetPropertyOnInterface(kTestInterface3, kInt64PropName); 389 dbus::MessageReader reader(response.get()); 390 int64_t value; 391 ASSERT_TRUE(reader.PopVariantOfInt64(&value)); 392 ASSERT_FALSE(reader.HasMoreData()); 393 } 394 395 TEST_F(ExportedPropertySetTest, GetWorksWithUint64) { 396 auto response = GetPropertyOnInterface(kTestInterface3, kUint64PropName); 397 dbus::MessageReader reader(response.get()); 398 uint64_t value; 399 ASSERT_TRUE(reader.PopVariantOfUint64(&value)); 400 ASSERT_FALSE(reader.HasMoreData()); 401 } 402 403 TEST_F(ExportedPropertySetTest, GetWorksWithDouble) { 404 auto response = GetPropertyOnInterface(kTestInterface3, kDoublePropName); 405 dbus::MessageReader reader(response.get()); 406 double value; 407 ASSERT_TRUE(reader.PopVariantOfDouble(&value)); 408 ASSERT_FALSE(reader.HasMoreData()); 409 } 410 411 TEST_F(ExportedPropertySetTest, GetWorksWithString) { 412 auto response = GetPropertyOnInterface(kTestInterface3, kStringPropName); 413 dbus::MessageReader reader(response.get()); 414 std::string value; 415 ASSERT_TRUE(reader.PopVariantOfString(&value)); 416 ASSERT_FALSE(reader.HasMoreData()); 417 } 418 419 TEST_F(ExportedPropertySetTest, GetWorksWithPath) { 420 auto response = GetPropertyOnInterface(kTestInterface3, kPathPropName); 421 dbus::MessageReader reader(response.get()); 422 dbus::ObjectPath value; 423 ASSERT_TRUE(reader.PopVariantOfObjectPath(&value)); 424 ASSERT_FALSE(reader.HasMoreData()); 425 } 426 427 TEST_F(ExportedPropertySetTest, GetWorksWithStringList) { 428 auto response = GetPropertyOnInterface(kTestInterface3, kStringListPropName); 429 dbus::MessageReader reader(response.get()); 430 dbus::MessageReader variant_reader(nullptr); 431 std::vector<std::string> value; 432 ASSERT_TRUE(reader.PopVariant(&variant_reader)); 433 ASSERT_TRUE(variant_reader.PopArrayOfStrings(&value)); 434 ASSERT_FALSE(variant_reader.HasMoreData()); 435 ASSERT_FALSE(reader.HasMoreData()); 436 } 437 438 TEST_F(ExportedPropertySetTest, GetWorksWithPathList) { 439 auto response = GetPropertyOnInterface(kTestInterface3, kPathListPropName); 440 dbus::MessageReader reader(response.get()); 441 dbus::MessageReader variant_reader(nullptr); 442 std::vector<dbus::ObjectPath> value; 443 ASSERT_TRUE(reader.PopVariant(&variant_reader)); 444 ASSERT_TRUE(variant_reader.PopArrayOfObjectPaths(&value)); 445 ASSERT_FALSE(variant_reader.HasMoreData()); 446 ASSERT_FALSE(reader.HasMoreData()); 447 } 448 449 TEST_F(ExportedPropertySetTest, GetWorksWithUint8List) { 450 auto response = GetPropertyOnInterface(kTestInterface3, kPathListPropName); 451 dbus::MessageReader reader(response.get()); 452 dbus::MessageReader variant_reader(nullptr); 453 const uint8_t* buffer; 454 size_t buffer_len; 455 ASSERT_TRUE(reader.PopVariant(&variant_reader)); 456 // |buffer| remains under the control of the MessageReader. 457 ASSERT_TRUE(variant_reader.PopArrayOfBytes(&buffer, &buffer_len)); 458 ASSERT_FALSE(variant_reader.HasMoreData()); 459 ASSERT_FALSE(reader.HasMoreData()); 460 } 461 462 TEST_F(ExportedPropertySetTest, SetInvalidInterface) { 463 auto response = SetPropertyOnInterface( 464 "BadInterfaceName", kStringPropName, brillo::Any(kTestString)); 465 ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType()); 466 ASSERT_EQ(DBUS_ERROR_UNKNOWN_INTERFACE, response->GetErrorName()); 467 } 468 469 TEST_F(ExportedPropertySetTest, SetBadPropertyName) { 470 auto response = SetPropertyOnInterface( 471 kTestInterface3, "IAmNotAProperty", brillo::Any(kTestString)); 472 ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType()); 473 ASSERT_EQ(DBUS_ERROR_UNKNOWN_PROPERTY, response->GetErrorName()); 474 } 475 476 TEST_F(ExportedPropertySetTest, SetFailsWithReadOnlyProperty) { 477 auto response = SetPropertyOnInterface( 478 kTestInterface3, kStringPropName, brillo::Any(kTestString)); 479 ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType()); 480 ASSERT_EQ(DBUS_ERROR_PROPERTY_READ_ONLY, response->GetErrorName()); 481 } 482 483 TEST_F(ExportedPropertySetTest, SetFailsWithMismatchedValueType) { 484 p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite); 485 auto response = SetPropertyOnInterface( 486 kTestInterface3, kStringPropName, brillo::Any(true)); 487 ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType()); 488 ASSERT_EQ(DBUS_ERROR_INVALID_ARGS, response->GetErrorName()); 489 } 490 491 namespace { 492 493 bool SetInvalidProperty(brillo::ErrorPtr* error, Unused) { 494 brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain, 495 DBUS_ERROR_INVALID_ARGS, "Invalid value"); 496 return false; 497 } 498 499 } // namespace 500 501 TEST_F(ExportedPropertySetTest, SetFailsWithValidator) { 502 PropertyValidatorObserver<std::string> property_validator; 503 p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite); 504 p_->string_prop_.SetValidator( 505 property_validator.validate_property_callback()); 506 507 brillo::ErrorPtr error = brillo::Error::Create( 508 FROM_HERE, errors::dbus::kDomain, DBUS_ERROR_INVALID_ARGS, ""); 509 EXPECT_CALL(property_validator, ValidateProperty(_, kTestString)) 510 .WillOnce(Invoke(SetInvalidProperty)); 511 auto response = SetPropertyOnInterface( 512 kTestInterface3, kStringPropName, brillo::Any(kTestString)); 513 ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType()); 514 ASSERT_EQ(DBUS_ERROR_INVALID_ARGS, response->GetErrorName()); 515 } 516 517 TEST_F(ExportedPropertySetTest, SetWorksWithValidator) { 518 PropertyValidatorObserver<std::string> property_validator; 519 p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite); 520 p_->string_prop_.SetValidator( 521 property_validator.validate_property_callback()); 522 523 EXPECT_CALL(property_validator, ValidateProperty(_, kTestString)) 524 .WillOnce(Return(true)); 525 auto response = SetPropertyOnInterface( 526 kTestInterface3, kStringPropName, brillo::Any(kTestString)); 527 ASSERT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType()); 528 ASSERT_EQ(kTestString, p_->string_prop_.value()); 529 } 530 531 TEST_F(ExportedPropertySetTest, SetWorksWithSameValue) { 532 PropertyValidatorObserver<std::string> property_validator; 533 p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite); 534 p_->string_prop_.SetValidator( 535 property_validator.validate_property_callback()); 536 EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(1); 537 p_->string_prop_.SetValue(kTestString); 538 539 // No need to validate the value if it is the same as the current one. 540 EXPECT_CALL(property_validator, ValidateProperty(_, _)).Times(0); 541 auto response = SetPropertyOnInterface( 542 kTestInterface3, kStringPropName, brillo::Any(kTestString)); 543 ASSERT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType()); 544 ASSERT_EQ(kTestString, p_->string_prop_.value()); 545 } 546 547 TEST_F(ExportedPropertySetTest, SetWorksWithoutValidator) { 548 p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite); 549 auto response = SetPropertyOnInterface( 550 kTestInterface3, kStringPropName, brillo::Any(kTestString)); 551 ASSERT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType()); 552 ASSERT_EQ(kTestString, p_->string_prop_.value()); 553 } 554 555 namespace { 556 557 void VerifySignal(dbus::Signal* signal) { 558 ASSERT_NE(signal, nullptr); 559 std::string interface_name; 560 std::string property_name; 561 uint8_t value; 562 dbus::MessageReader reader(signal); 563 dbus::MessageReader array_reader(signal); 564 dbus::MessageReader dict_reader(signal); 565 ASSERT_TRUE(reader.PopString(&interface_name)); 566 ASSERT_TRUE(reader.PopArray(&array_reader)); 567 ASSERT_TRUE(array_reader.PopDictEntry(&dict_reader)); 568 ASSERT_TRUE(dict_reader.PopString(&property_name)); 569 ASSERT_TRUE(dict_reader.PopVariantOfByte(&value)); 570 ASSERT_FALSE(dict_reader.HasMoreData()); 571 ASSERT_FALSE(array_reader.HasMoreData()); 572 ASSERT_TRUE(reader.HasMoreData()); 573 // Read the (empty) list of invalidated property names. 574 ASSERT_TRUE(reader.PopArray(&array_reader)); 575 ASSERT_FALSE(array_reader.HasMoreData()); 576 ASSERT_FALSE(reader.HasMoreData()); 577 ASSERT_EQ(value, 57); 578 ASSERT_EQ(property_name, std::string(kUint8PropName)); 579 ASSERT_EQ(interface_name, std::string(kTestInterface1)); 580 } 581 582 } // namespace 583 584 TEST_F(ExportedPropertySetTest, SignalsAreParsable) { 585 EXPECT_CALL(*mock_exported_object_, SendSignal(_)) 586 .Times(1).WillOnce(Invoke(&VerifySignal)); 587 p_->uint8_prop_.SetValue(57); 588 } 589 590 } // namespace dbus_utils 591 592 } // namespace brillo 593