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 23using ::testing::AnyNumber; 24using ::testing::Return; 25using ::testing::Invoke; 26using ::testing::_; 27using ::testing::Unused; 28 29namespace brillo { 30 31namespace dbus_utils { 32 33namespace { 34 35const char kBoolPropName[] = "BoolProp"; 36const char kUint8PropName[] = "Uint8Prop"; 37const char kInt16PropName[] = "Int16Prop"; 38const char kUint16PropName[] = "Uint16Prop"; 39const char kInt32PropName[] = "Int32Prop"; 40const char kUint32PropName[] = "Uint32Prop"; 41const char kInt64PropName[] = "Int64Prop"; 42const char kUint64PropName[] = "Uint64Prop"; 43const char kDoublePropName[] = "DoubleProp"; 44const char kStringPropName[] = "StringProp"; 45const char kPathPropName[] = "PathProp"; 46const char kStringListPropName[] = "StringListProp"; 47const char kPathListPropName[] = "PathListProp"; 48const char kUint8ListPropName[] = "Uint8ListProp"; 49 50const char kTestInterface1[] = "org.chromium.TestInterface1"; 51const char kTestInterface2[] = "org.chromium.TestInterface2"; 52const char kTestInterface3[] = "org.chromium.TestInterface3"; 53 54const std::string kTestString("lies"); 55const dbus::ObjectPath kMethodsExportedOnPath(std::string("/export")); 56const dbus::ObjectPath kTestObjectPathInit(std::string("/path_init")); 57const dbus::ObjectPath kTestObjectPathUpdate(std::string("/path_update")); 58 59} // namespace 60 61class 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 171template<typename T> 172class 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 195TEST_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 213TEST_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 219TEST_F(ExportedPropertySetTest, GetAllNoArgs) { 220 dbus::MethodCall method_call(dbus::kPropertiesInterface, 221 dbus::kPropertiesGetAll); 222 AssertMethodReturnsError(&method_call); 223} 224 225TEST_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 242TEST_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 251TEST_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 288TEST_F(ExportedPropertySetTest, GetNoArgs) { 289 dbus::MethodCall method_call(dbus::kPropertiesInterface, 290 dbus::kPropertiesGet); 291 AssertMethodReturnsError(&method_call); 292} 293 294TEST_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 303TEST_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 312TEST_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 321TEST_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 329TEST_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 339TEST_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 347TEST_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 355TEST_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 363TEST_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 371TEST_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 379TEST_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 387TEST_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 395TEST_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 403TEST_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 411TEST_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 419TEST_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 427TEST_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 438TEST_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 449TEST_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 462TEST_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 469TEST_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 476TEST_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 483TEST_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 491namespace { 492 493bool 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 501TEST_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 517TEST_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 531TEST_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 547TEST_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 555namespace { 556 557void 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 584TEST_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