xref: /aosp_15_r20/external/libbrillo/brillo/dbus/exported_property_set_test.cc (revision 1a96fba65179ea7d3f56207137718607415c5953)
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_METHOD(bool, ValidateProperty, (brillo::ErrorPtr*, const T&));
181 
182   const base::Callback<bool(brillo::ErrorPtr*, const T&)>&
validate_property_callback() const183   validate_property_callback() const {
184     return validate_property_callback_;
185   }
186 
187  private:
188   base::Callback<bool(brillo::ErrorPtr*, const T&)>
189       validate_property_callback_;
190 
191   DISALLOW_COPY_AND_ASSIGN(PropertyValidatorObserver);
192 };
193 
TEST_F(ExportedPropertySetTest,UpdateNotifications)194 TEST_F(ExportedPropertySetTest, UpdateNotifications) {
195   EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(14);
196   p_->bool_prop_.SetValue(true);
197   p_->uint8_prop_.SetValue(1);
198   p_->int16_prop_.SetValue(1);
199   p_->uint16_prop_.SetValue(1);
200   p_->int32_prop_.SetValue(1);
201   p_->uint32_prop_.SetValue(1);
202   p_->int64_prop_.SetValue(1);
203   p_->uint64_prop_.SetValue(1);
204   p_->double_prop_.SetValue(1.0);
205   p_->string_prop_.SetValue(kTestString);
206   p_->path_prop_.SetValue(kTestObjectPathUpdate);
207   p_->stringlist_prop_.SetValue({kTestString});
208   p_->pathlist_prop_.SetValue({kTestObjectPathUpdate});
209   p_->uint8list_prop_.SetValue({1});
210 }
211 
TEST_F(ExportedPropertySetTest,UpdateToSameValue)212 TEST_F(ExportedPropertySetTest, UpdateToSameValue) {
213   EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(1);
214   p_->bool_prop_.SetValue(true);
215   p_->bool_prop_.SetValue(true);
216 }
217 
TEST_F(ExportedPropertySetTest,GetAllNoArgs)218 TEST_F(ExportedPropertySetTest, GetAllNoArgs) {
219   dbus::MethodCall method_call(dbus::kPropertiesInterface,
220                                dbus::kPropertiesGetAll);
221   AssertMethodReturnsError(&method_call);
222 }
223 
TEST_F(ExportedPropertySetTest,GetAllInvalidInterface)224 TEST_F(ExportedPropertySetTest, GetAllInvalidInterface) {
225   dbus::MethodCall method_call(dbus::kPropertiesInterface,
226                                dbus::kPropertiesGetAll);
227   method_call.SetSerial(123);
228   dbus::MessageWriter writer(&method_call);
229   writer.AppendString("org.chromium.BadInterface");
230   auto response = testing::CallMethod(p_->dbus_object_, &method_call);
231   dbus::MessageReader response_reader(response.get());
232   dbus::MessageReader dict_reader(nullptr);
233   ASSERT_TRUE(response_reader.PopArray(&dict_reader));
234   // The response should just be a an empty array, since there are no properties
235   // on this interface.  The spec doesn't say much about error conditions here,
236   // so I'm going to assume this is a valid implementation.
237   ASSERT_FALSE(dict_reader.HasMoreData());
238   ASSERT_FALSE(response_reader.HasMoreData());
239 }
240 
TEST_F(ExportedPropertySetTest,GetAllExtraArgs)241 TEST_F(ExportedPropertySetTest, GetAllExtraArgs) {
242   dbus::MethodCall method_call(dbus::kPropertiesInterface,
243                                dbus::kPropertiesGetAll);
244   dbus::MessageWriter writer(&method_call);
245   writer.AppendString(kTestInterface1);
246   writer.AppendString(kTestInterface1);
247   AssertMethodReturnsError(&method_call);
248 }
249 
TEST_F(ExportedPropertySetTest,GetAllCorrectness)250 TEST_F(ExportedPropertySetTest, GetAllCorrectness) {
251   dbus::MethodCall method_call(dbus::kPropertiesInterface,
252                                dbus::kPropertiesGetAll);
253   method_call.SetSerial(123);
254   dbus::MessageWriter writer(&method_call);
255   writer.AppendString(kTestInterface2);
256   auto response = testing::CallMethod(p_->dbus_object_, &method_call);
257   dbus::MessageReader response_reader(response.get());
258   dbus::MessageReader dict_reader(nullptr);
259   dbus::MessageReader entry_reader(nullptr);
260   ASSERT_TRUE(response_reader.PopArray(&dict_reader));
261   ASSERT_TRUE(dict_reader.PopDictEntry(&entry_reader));
262   std::string property_name;
263   ASSERT_TRUE(entry_reader.PopString(&property_name));
264   uint16_t value16;
265   int32_t value32;
266   if (property_name.compare(kUint16PropName) == 0) {
267     ASSERT_TRUE(entry_reader.PopVariantOfUint16(&value16));
268     ASSERT_FALSE(entry_reader.HasMoreData());
269     ASSERT_TRUE(dict_reader.PopDictEntry(&entry_reader));
270     ASSERT_TRUE(entry_reader.PopString(&property_name));
271     ASSERT_EQ(property_name.compare(kInt32PropName), 0);
272     ASSERT_TRUE(entry_reader.PopVariantOfInt32(&value32));
273   } else {
274     ASSERT_EQ(property_name.compare(kInt32PropName), 0);
275     ASSERT_TRUE(entry_reader.PopVariantOfInt32(&value32));
276     ASSERT_FALSE(entry_reader.HasMoreData());
277     ASSERT_TRUE(dict_reader.PopDictEntry(&entry_reader));
278     ASSERT_TRUE(entry_reader.PopString(&property_name));
279     ASSERT_EQ(property_name.compare(kUint16PropName), 0);
280     ASSERT_TRUE(entry_reader.PopVariantOfUint16(&value16));
281   }
282   ASSERT_FALSE(entry_reader.HasMoreData());
283   ASSERT_FALSE(dict_reader.HasMoreData());
284   ASSERT_FALSE(response_reader.HasMoreData());
285 }
286 
TEST_F(ExportedPropertySetTest,GetNoArgs)287 TEST_F(ExportedPropertySetTest, GetNoArgs) {
288   dbus::MethodCall method_call(dbus::kPropertiesInterface,
289                                dbus::kPropertiesGet);
290   AssertMethodReturnsError(&method_call);
291 }
292 
TEST_F(ExportedPropertySetTest,GetInvalidInterface)293 TEST_F(ExportedPropertySetTest, GetInvalidInterface) {
294   dbus::MethodCall method_call(dbus::kPropertiesInterface,
295                                dbus::kPropertiesGet);
296   dbus::MessageWriter writer(&method_call);
297   writer.AppendString("org.chromium.BadInterface");
298   writer.AppendString(kInt16PropName);
299   AssertMethodReturnsError(&method_call);
300 }
301 
TEST_F(ExportedPropertySetTest,GetBadPropertyName)302 TEST_F(ExportedPropertySetTest, GetBadPropertyName) {
303   dbus::MethodCall method_call(dbus::kPropertiesInterface,
304                                dbus::kPropertiesGet);
305   dbus::MessageWriter writer(&method_call);
306   writer.AppendString(kTestInterface1);
307   writer.AppendString("IAmNotAProperty");
308   AssertMethodReturnsError(&method_call);
309 }
310 
TEST_F(ExportedPropertySetTest,GetPropIfMismatch)311 TEST_F(ExportedPropertySetTest, GetPropIfMismatch) {
312   dbus::MethodCall method_call(dbus::kPropertiesInterface,
313                                dbus::kPropertiesGet);
314   dbus::MessageWriter writer(&method_call);
315   writer.AppendString(kTestInterface1);
316   writer.AppendString(kStringPropName);
317   AssertMethodReturnsError(&method_call);
318 }
319 
TEST_F(ExportedPropertySetTest,GetNoPropertyName)320 TEST_F(ExportedPropertySetTest, GetNoPropertyName) {
321   dbus::MethodCall method_call(dbus::kPropertiesInterface,
322                                dbus::kPropertiesGet);
323   dbus::MessageWriter writer(&method_call);
324   writer.AppendString(kTestInterface1);
325   AssertMethodReturnsError(&method_call);
326 }
327 
TEST_F(ExportedPropertySetTest,GetExtraArgs)328 TEST_F(ExportedPropertySetTest, GetExtraArgs) {
329   dbus::MethodCall method_call(dbus::kPropertiesInterface,
330                                dbus::kPropertiesGet);
331   dbus::MessageWriter writer(&method_call);
332   writer.AppendString(kTestInterface1);
333   writer.AppendString(kBoolPropName);
334   writer.AppendString("Extra param");
335   AssertMethodReturnsError(&method_call);
336 }
337 
TEST_F(ExportedPropertySetTest,GetRemovedProperty)338 TEST_F(ExportedPropertySetTest, GetRemovedProperty) {
339   DBusInterface* itf1 = p_->dbus_object_.AddOrGetInterface(kTestInterface1);
340   itf1->RemoveProperty(kBoolPropName);
341 
342   auto response = GetPropertyOnInterface(kTestInterface1, kBoolPropName);
343   ASSERT_EQ(DBUS_ERROR_UNKNOWN_PROPERTY, response->GetErrorName());
344 
345   // Signal should not be emitted for removed property.
346   EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(0);
347   p_->bool_prop_.SetValue(true);
348 }
349 
TEST_F(ExportedPropertySetTest,GetWorksWithBool)350 TEST_F(ExportedPropertySetTest, GetWorksWithBool) {
351   auto response = GetPropertyOnInterface(kTestInterface1, kBoolPropName);
352   dbus::MessageReader reader(response.get());
353   bool value;
354   ASSERT_TRUE(reader.PopVariantOfBool(&value));
355   ASSERT_FALSE(reader.HasMoreData());
356 }
357 
TEST_F(ExportedPropertySetTest,GetWorksWithUint8)358 TEST_F(ExportedPropertySetTest, GetWorksWithUint8) {
359   auto response = GetPropertyOnInterface(kTestInterface1, kUint8PropName);
360   dbus::MessageReader reader(response.get());
361   uint8_t value;
362   ASSERT_TRUE(reader.PopVariantOfByte(&value));
363   ASSERT_FALSE(reader.HasMoreData());
364 }
365 
TEST_F(ExportedPropertySetTest,GetWorksWithInt16)366 TEST_F(ExportedPropertySetTest, GetWorksWithInt16) {
367   auto response = GetPropertyOnInterface(kTestInterface1, kInt16PropName);
368   dbus::MessageReader reader(response.get());
369   int16_t value;
370   ASSERT_TRUE(reader.PopVariantOfInt16(&value));
371   ASSERT_FALSE(reader.HasMoreData());
372 }
373 
TEST_F(ExportedPropertySetTest,GetWorksWithUint16)374 TEST_F(ExportedPropertySetTest, GetWorksWithUint16) {
375   auto response = GetPropertyOnInterface(kTestInterface2, kUint16PropName);
376   dbus::MessageReader reader(response.get());
377   uint16_t value;
378   ASSERT_TRUE(reader.PopVariantOfUint16(&value));
379   ASSERT_FALSE(reader.HasMoreData());
380 }
381 
TEST_F(ExportedPropertySetTest,GetWorksWithInt32)382 TEST_F(ExportedPropertySetTest, GetWorksWithInt32) {
383   auto response = GetPropertyOnInterface(kTestInterface2, kInt32PropName);
384   dbus::MessageReader reader(response.get());
385   int32_t value;
386   ASSERT_TRUE(reader.PopVariantOfInt32(&value));
387   ASSERT_FALSE(reader.HasMoreData());
388 }
389 
TEST_F(ExportedPropertySetTest,GetWorksWithUint32)390 TEST_F(ExportedPropertySetTest, GetWorksWithUint32) {
391   auto response = GetPropertyOnInterface(kTestInterface3, kUint32PropName);
392   dbus::MessageReader reader(response.get());
393   uint32_t value;
394   ASSERT_TRUE(reader.PopVariantOfUint32(&value));
395   ASSERT_FALSE(reader.HasMoreData());
396 }
397 
TEST_F(ExportedPropertySetTest,GetWorksWithInt64)398 TEST_F(ExportedPropertySetTest, GetWorksWithInt64) {
399   auto response = GetPropertyOnInterface(kTestInterface3, kInt64PropName);
400   dbus::MessageReader reader(response.get());
401   int64_t value;
402   ASSERT_TRUE(reader.PopVariantOfInt64(&value));
403   ASSERT_FALSE(reader.HasMoreData());
404 }
405 
TEST_F(ExportedPropertySetTest,GetWorksWithUint64)406 TEST_F(ExportedPropertySetTest, GetWorksWithUint64) {
407   auto response = GetPropertyOnInterface(kTestInterface3, kUint64PropName);
408   dbus::MessageReader reader(response.get());
409   uint64_t value;
410   ASSERT_TRUE(reader.PopVariantOfUint64(&value));
411   ASSERT_FALSE(reader.HasMoreData());
412 }
413 
TEST_F(ExportedPropertySetTest,GetWorksWithDouble)414 TEST_F(ExportedPropertySetTest, GetWorksWithDouble) {
415   auto response = GetPropertyOnInterface(kTestInterface3, kDoublePropName);
416   dbus::MessageReader reader(response.get());
417   double value;
418   ASSERT_TRUE(reader.PopVariantOfDouble(&value));
419   ASSERT_FALSE(reader.HasMoreData());
420 }
421 
TEST_F(ExportedPropertySetTest,GetWorksWithString)422 TEST_F(ExportedPropertySetTest, GetWorksWithString) {
423   auto response = GetPropertyOnInterface(kTestInterface3, kStringPropName);
424   dbus::MessageReader reader(response.get());
425   std::string value;
426   ASSERT_TRUE(reader.PopVariantOfString(&value));
427   ASSERT_FALSE(reader.HasMoreData());
428 }
429 
TEST_F(ExportedPropertySetTest,GetWorksWithPath)430 TEST_F(ExportedPropertySetTest, GetWorksWithPath) {
431   auto response = GetPropertyOnInterface(kTestInterface3, kPathPropName);
432   dbus::MessageReader reader(response.get());
433   dbus::ObjectPath value;
434   ASSERT_TRUE(reader.PopVariantOfObjectPath(&value));
435   ASSERT_FALSE(reader.HasMoreData());
436 }
437 
TEST_F(ExportedPropertySetTest,GetWorksWithStringList)438 TEST_F(ExportedPropertySetTest, GetWorksWithStringList) {
439   auto response = GetPropertyOnInterface(kTestInterface3, kStringListPropName);
440   dbus::MessageReader reader(response.get());
441   dbus::MessageReader variant_reader(nullptr);
442   std::vector<std::string> value;
443   ASSERT_TRUE(reader.PopVariant(&variant_reader));
444   ASSERT_TRUE(variant_reader.PopArrayOfStrings(&value));
445   ASSERT_FALSE(variant_reader.HasMoreData());
446   ASSERT_FALSE(reader.HasMoreData());
447 }
448 
TEST_F(ExportedPropertySetTest,GetWorksWithPathList)449 TEST_F(ExportedPropertySetTest, GetWorksWithPathList) {
450   auto response = GetPropertyOnInterface(kTestInterface3, kPathListPropName);
451   dbus::MessageReader reader(response.get());
452   dbus::MessageReader variant_reader(nullptr);
453   std::vector<dbus::ObjectPath> value;
454   ASSERT_TRUE(reader.PopVariant(&variant_reader));
455   ASSERT_TRUE(variant_reader.PopArrayOfObjectPaths(&value));
456   ASSERT_FALSE(variant_reader.HasMoreData());
457   ASSERT_FALSE(reader.HasMoreData());
458 }
459 
TEST_F(ExportedPropertySetTest,GetWorksWithUint8List)460 TEST_F(ExportedPropertySetTest, GetWorksWithUint8List) {
461   auto response = GetPropertyOnInterface(kTestInterface3, kPathListPropName);
462   dbus::MessageReader reader(response.get());
463   dbus::MessageReader variant_reader(nullptr);
464   const uint8_t* buffer;
465   size_t buffer_len;
466   ASSERT_TRUE(reader.PopVariant(&variant_reader));
467   // |buffer| remains under the control of the MessageReader.
468   ASSERT_TRUE(variant_reader.PopArrayOfBytes(&buffer, &buffer_len));
469   ASSERT_FALSE(variant_reader.HasMoreData());
470   ASSERT_FALSE(reader.HasMoreData());
471 }
472 
TEST_F(ExportedPropertySetTest,SetInvalidInterface)473 TEST_F(ExportedPropertySetTest, SetInvalidInterface) {
474   auto response = SetPropertyOnInterface(
475       "BadInterfaceName", kStringPropName, brillo::Any(kTestString));
476   ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
477   ASSERT_EQ(DBUS_ERROR_UNKNOWN_INTERFACE, response->GetErrorName());
478 }
479 
TEST_F(ExportedPropertySetTest,SetBadPropertyName)480 TEST_F(ExportedPropertySetTest, SetBadPropertyName) {
481   auto response = SetPropertyOnInterface(
482       kTestInterface3, "IAmNotAProperty", brillo::Any(kTestString));
483   ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
484   ASSERT_EQ(DBUS_ERROR_UNKNOWN_PROPERTY, response->GetErrorName());
485 }
486 
TEST_F(ExportedPropertySetTest,SetFailsWithReadOnlyProperty)487 TEST_F(ExportedPropertySetTest, SetFailsWithReadOnlyProperty) {
488   auto response = SetPropertyOnInterface(
489       kTestInterface3, kStringPropName, brillo::Any(kTestString));
490   ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
491   ASSERT_EQ(DBUS_ERROR_PROPERTY_READ_ONLY, response->GetErrorName());
492 }
493 
TEST_F(ExportedPropertySetTest,SetFailsWithMismatchedValueType)494 TEST_F(ExportedPropertySetTest, SetFailsWithMismatchedValueType) {
495   p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite);
496   auto response = SetPropertyOnInterface(
497       kTestInterface3, kStringPropName, brillo::Any(true));
498   ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
499   ASSERT_EQ(DBUS_ERROR_INVALID_ARGS, response->GetErrorName());
500 }
501 
502 namespace {
503 
SetInvalidProperty(brillo::ErrorPtr * error,Unused)504 bool SetInvalidProperty(brillo::ErrorPtr* error, Unused) {
505   brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
506                        DBUS_ERROR_INVALID_ARGS, "Invalid value");
507   return false;
508 }
509 
510 }  // namespace
511 
TEST_F(ExportedPropertySetTest,SetFailsWithValidator)512 TEST_F(ExportedPropertySetTest, SetFailsWithValidator) {
513   PropertyValidatorObserver<std::string> property_validator;
514   p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite);
515   p_->string_prop_.SetValidator(
516       property_validator.validate_property_callback());
517 
518   brillo::ErrorPtr error = brillo::Error::Create(
519       FROM_HERE, errors::dbus::kDomain, DBUS_ERROR_INVALID_ARGS, "");
520   EXPECT_CALL(property_validator, ValidateProperty(_, kTestString))
521       .WillOnce(Invoke(SetInvalidProperty));
522   auto response = SetPropertyOnInterface(
523       kTestInterface3, kStringPropName, brillo::Any(kTestString));
524   ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
525   ASSERT_EQ(DBUS_ERROR_INVALID_ARGS, response->GetErrorName());
526 }
527 
TEST_F(ExportedPropertySetTest,SetWorksWithValidator)528 TEST_F(ExportedPropertySetTest, SetWorksWithValidator) {
529   PropertyValidatorObserver<std::string> property_validator;
530   p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite);
531   p_->string_prop_.SetValidator(
532       property_validator.validate_property_callback());
533 
534   EXPECT_CALL(property_validator, ValidateProperty(_, kTestString))
535       .WillOnce(Return(true));
536   auto response = SetPropertyOnInterface(
537       kTestInterface3, kStringPropName, brillo::Any(kTestString));
538   ASSERT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
539   ASSERT_EQ(kTestString, p_->string_prop_.value());
540 }
541 
TEST_F(ExportedPropertySetTest,SetWorksWithSameValue)542 TEST_F(ExportedPropertySetTest, SetWorksWithSameValue) {
543   PropertyValidatorObserver<std::string> property_validator;
544   p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite);
545   p_->string_prop_.SetValidator(
546       property_validator.validate_property_callback());
547   EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(1);
548   p_->string_prop_.SetValue(kTestString);
549 
550   // No need to validate the value if it is the same as the current one.
551   EXPECT_CALL(property_validator, ValidateProperty(_, _)).Times(0);
552   auto response = SetPropertyOnInterface(
553       kTestInterface3, kStringPropName, brillo::Any(kTestString));
554   ASSERT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
555   ASSERT_EQ(kTestString, p_->string_prop_.value());
556 }
557 
TEST_F(ExportedPropertySetTest,SetWorksWithoutValidator)558 TEST_F(ExportedPropertySetTest, SetWorksWithoutValidator) {
559   p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite);
560   auto response = SetPropertyOnInterface(
561       kTestInterface3, kStringPropName, brillo::Any(kTestString));
562   ASSERT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
563   ASSERT_EQ(kTestString, p_->string_prop_.value());
564 }
565 
566 namespace {
567 
VerifySignal(dbus::Signal * signal)568 void VerifySignal(dbus::Signal* signal) {
569   ASSERT_NE(signal, nullptr);
570   std::string interface_name;
571   std::string property_name;
572   uint8_t value;
573   dbus::MessageReader reader(signal);
574   dbus::MessageReader array_reader(signal);
575   dbus::MessageReader dict_reader(signal);
576   ASSERT_TRUE(reader.PopString(&interface_name));
577   ASSERT_TRUE(reader.PopArray(&array_reader));
578   ASSERT_TRUE(array_reader.PopDictEntry(&dict_reader));
579   ASSERT_TRUE(dict_reader.PopString(&property_name));
580   ASSERT_TRUE(dict_reader.PopVariantOfByte(&value));
581   ASSERT_FALSE(dict_reader.HasMoreData());
582   ASSERT_FALSE(array_reader.HasMoreData());
583   ASSERT_TRUE(reader.HasMoreData());
584   // Read the (empty) list of invalidated property names.
585   ASSERT_TRUE(reader.PopArray(&array_reader));
586   ASSERT_FALSE(array_reader.HasMoreData());
587   ASSERT_FALSE(reader.HasMoreData());
588   ASSERT_EQ(value, 57);
589   ASSERT_EQ(property_name, std::string(kUint8PropName));
590   ASSERT_EQ(interface_name, std::string(kTestInterface1));
591 }
592 
593 }  // namespace
594 
TEST_F(ExportedPropertySetTest,SignalsAreParsable)595 TEST_F(ExportedPropertySetTest, SignalsAreParsable) {
596   EXPECT_CALL(*mock_exported_object_, SendSignal(_))
597       .Times(1).WillOnce(Invoke(&VerifySignal));
598   p_->uint8_prop_.SetValue(57);
599 }
600 
601 }  // namespace dbus_utils
602 
603 }  // namespace brillo
604