xref: /aosp_15_r20/external/libchrome/dbus/property_unittest.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1 // Copyright (c) 2012 The Chromium 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 "dbus/property.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include <memory>
11 #include <string>
12 #include <vector>
13 
14 #include "base/bind.h"
15 #include "base/logging.h"
16 #include "base/macros.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/run_loop.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/threading/thread.h"
21 #include "base/threading/thread_restrictions.h"
22 #include "dbus/bus.h"
23 #include "dbus/object_path.h"
24 #include "dbus/object_proxy.h"
25 #include "dbus/test_service.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 
28 namespace dbus {
29 
30 // The property test exerises the asynchronous APIs in PropertySet and
31 // Property<>.
32 class PropertyTest : public testing::Test {
33  public:
34   PropertyTest() = default;
35 
36   struct Properties : public PropertySet {
37     Property<std::string> name;
38     Property<int16_t> version;
39     Property<std::vector<std::string>> methods;
40     Property<std::vector<ObjectPath>> objects;
41     Property<std::vector<uint8_t>> bytes;
42 
Propertiesdbus::PropertyTest::Properties43     Properties(ObjectProxy* object_proxy,
44                PropertyChangedCallback property_changed_callback)
45         : PropertySet(object_proxy,
46                       "org.chromium.TestInterface",
47                       property_changed_callback) {
48       RegisterProperty("Name", &name);
49       RegisterProperty("Version", &version);
50       RegisterProperty("Methods", &methods);
51       RegisterProperty("Objects", &objects);
52       RegisterProperty("Bytes", &bytes);
53     }
54   };
55 
SetUp()56   void SetUp() override {
57     // Make the main thread not to allow IO.
58     base::ThreadRestrictions::SetIOAllowed(false);
59 
60     // Start the D-Bus thread.
61     dbus_thread_.reset(new base::Thread("D-Bus Thread"));
62     base::Thread::Options thread_options;
63     thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
64     ASSERT_TRUE(dbus_thread_->StartWithOptions(thread_options));
65 
66     // Start the test service, using the D-Bus thread.
67     TestService::Options options;
68     options.dbus_task_runner = dbus_thread_->task_runner();
69     test_service_.reset(new TestService(options));
70     ASSERT_TRUE(test_service_->StartService());
71     ASSERT_TRUE(test_service_->WaitUntilServiceIsStarted());
72     ASSERT_TRUE(test_service_->HasDBusThread());
73 
74     // Create the client, using the D-Bus thread.
75     Bus::Options bus_options;
76     bus_options.bus_type = Bus::SESSION;
77     bus_options.connection_type = Bus::PRIVATE;
78     bus_options.dbus_task_runner = dbus_thread_->task_runner();
79     bus_ = new Bus(bus_options);
80     object_proxy_ = bus_->GetObjectProxy(
81         test_service_->service_name(),
82         ObjectPath("/org/chromium/TestObject"));
83     ASSERT_TRUE(bus_->HasDBusThread());
84 
85     // Create the properties structure
86     properties_.reset(new Properties(
87         object_proxy_,
88         base::Bind(&PropertyTest::OnPropertyChanged,
89                    base::Unretained(this))));
90     properties_->ConnectSignals();
91     properties_->GetAll();
92   }
93 
TearDown()94   void TearDown() override {
95     bus_->ShutdownOnDBusThreadAndBlock();
96 
97     // Shut down the service.
98     test_service_->ShutdownAndBlock();
99 
100     // Reset to the default.
101     base::ThreadRestrictions::SetIOAllowed(true);
102 
103     // Stopping a thread is considered an IO operation, so do this after
104     // allowing IO.
105     test_service_->Stop();
106   }
107 
108   // Generic callback, bind with a string |id| for passing to
109   // WaitForCallback() to ensure the callback for the right method is
110   // waited for.
PropertyCallback(const std::string & id,bool success)111   void PropertyCallback(const std::string& id, bool success) {
112     last_callback_ = id;
113     run_loop_->Quit();
114   }
115 
116   // Generic method callback, that might be used together with
117   // WaitForMethodCallback to test wether method was succesfully called.
MethodCallback(Response * response)118   void MethodCallback(Response* response) { run_loop_->Quit(); }
119 
120  protected:
121   // Called when a property value is updated.
OnPropertyChanged(const std::string & name)122   void OnPropertyChanged(const std::string& name) {
123     updated_properties_.push_back(name);
124     run_loop_->Quit();
125   }
126 
127   // Waits for the given number of updates.
WaitForUpdates(size_t num_updates)128   void WaitForUpdates(size_t num_updates) {
129     while (updated_properties_.size() < num_updates) {
130       run_loop_.reset(new base::RunLoop);
131       run_loop_->Run();
132     }
133     for (size_t i = 0; i < num_updates; ++i)
134       updated_properties_.erase(updated_properties_.begin());
135   }
136 
137   // Name, Version, Methods, Objects
138   static const int kExpectedSignalUpdates = 5;
139 
140   // Waits for initial values to be set.
WaitForGetAll()141   void WaitForGetAll() {
142     WaitForUpdates(kExpectedSignalUpdates);
143   }
144 
145   // Waits until MethodCallback is called.
WaitForMethodCallback()146   void WaitForMethodCallback() {
147     run_loop_.reset(new base::RunLoop);
148     run_loop_->Run();
149   }
150 
151   // Waits for the callback. |id| is the string bound to the callback when
152   // the method call is made that identifies it and distinguishes from any
153   // other; you can set this to whatever you wish.
WaitForCallback(const std::string & id)154   void WaitForCallback(const std::string& id) {
155     while (last_callback_ != id) {
156       run_loop_.reset(new base::RunLoop);
157       run_loop_->Run();
158     }
159   }
160 
161   base::MessageLoop message_loop_;
162   std::unique_ptr<base::RunLoop> run_loop_;
163   std::unique_ptr<base::Thread> dbus_thread_;
164   scoped_refptr<Bus> bus_;
165   ObjectProxy* object_proxy_;
166   std::unique_ptr<Properties> properties_;
167   std::unique_ptr<TestService> test_service_;
168   // Properties updated.
169   std::vector<std::string> updated_properties_;
170   // Last callback received.
171   std::string last_callback_;
172 };
173 
TEST_F(PropertyTest,InitialValues)174 TEST_F(PropertyTest, InitialValues) {
175   EXPECT_FALSE(properties_->name.is_valid());
176   EXPECT_FALSE(properties_->version.is_valid());
177 
178   WaitForGetAll();
179 
180   EXPECT_TRUE(properties_->name.is_valid());
181   EXPECT_EQ("TestService", properties_->name.value());
182   EXPECT_TRUE(properties_->version.is_valid());
183   EXPECT_EQ(10, properties_->version.value());
184 
185   std::vector<std::string> methods = properties_->methods.value();
186   ASSERT_EQ(4U, methods.size());
187   EXPECT_EQ("Echo", methods[0]);
188   EXPECT_EQ("SlowEcho", methods[1]);
189   EXPECT_EQ("AsyncEcho", methods[2]);
190   EXPECT_EQ("BrokenMethod", methods[3]);
191 
192   std::vector<ObjectPath> objects = properties_->objects.value();
193   ASSERT_EQ(1U, objects.size());
194   EXPECT_EQ(ObjectPath("/TestObjectPath"), objects[0]);
195 
196   std::vector<uint8_t> bytes = properties_->bytes.value();
197   ASSERT_EQ(4U, bytes.size());
198   EXPECT_EQ('T', bytes[0]);
199   EXPECT_EQ('e', bytes[1]);
200   EXPECT_EQ('s', bytes[2]);
201   EXPECT_EQ('t', bytes[3]);
202 }
203 
TEST_F(PropertyTest,UpdatedValues)204 TEST_F(PropertyTest, UpdatedValues) {
205   WaitForGetAll();
206 
207   // Update the value of the "Name" property, this value should not change.
208   properties_->name.Get(base::Bind(&PropertyTest::PropertyCallback,
209                                    base::Unretained(this),
210                                    "Name"));
211   WaitForCallback("Name");
212   WaitForUpdates(1);
213 
214   EXPECT_EQ("TestService", properties_->name.value());
215 
216   // Update the value of the "Version" property, this value should be changed.
217   properties_->version.Get(base::Bind(&PropertyTest::PropertyCallback,
218                                       base::Unretained(this),
219                                       "Version"));
220   WaitForCallback("Version");
221   WaitForUpdates(1);
222 
223   EXPECT_EQ(20, properties_->version.value());
224 
225   // Update the value of the "Methods" property, this value should not change
226   // and should not grow to contain duplicate entries.
227   properties_->methods.Get(base::Bind(&PropertyTest::PropertyCallback,
228                                       base::Unretained(this),
229                                       "Methods"));
230   WaitForCallback("Methods");
231   WaitForUpdates(1);
232 
233   std::vector<std::string> methods = properties_->methods.value();
234   ASSERT_EQ(4U, methods.size());
235   EXPECT_EQ("Echo", methods[0]);
236   EXPECT_EQ("SlowEcho", methods[1]);
237   EXPECT_EQ("AsyncEcho", methods[2]);
238   EXPECT_EQ("BrokenMethod", methods[3]);
239 
240   // Update the value of the "Objects" property, this value should not change
241   // and should not grow to contain duplicate entries.
242   properties_->objects.Get(base::Bind(&PropertyTest::PropertyCallback,
243                                       base::Unretained(this),
244                                       "Objects"));
245   WaitForCallback("Objects");
246   WaitForUpdates(1);
247 
248   std::vector<ObjectPath> objects = properties_->objects.value();
249   ASSERT_EQ(1U, objects.size());
250   EXPECT_EQ(ObjectPath("/TestObjectPath"), objects[0]);
251 
252   // Update the value of the "Bytes" property, this value should not change
253   // and should not grow to contain duplicate entries.
254   properties_->bytes.Get(base::Bind(&PropertyTest::PropertyCallback,
255                                     base::Unretained(this),
256                                    "Bytes"));
257   WaitForCallback("Bytes");
258   WaitForUpdates(1);
259 
260   std::vector<uint8_t> bytes = properties_->bytes.value();
261   ASSERT_EQ(4U, bytes.size());
262   EXPECT_EQ('T', bytes[0]);
263   EXPECT_EQ('e', bytes[1]);
264   EXPECT_EQ('s', bytes[2]);
265   EXPECT_EQ('t', bytes[3]);
266 }
267 
TEST_F(PropertyTest,Get)268 TEST_F(PropertyTest, Get) {
269   WaitForGetAll();
270 
271   // Ask for the new Version property.
272   properties_->version.Get(base::Bind(&PropertyTest::PropertyCallback,
273                                       base::Unretained(this),
274                                       "Get"));
275   WaitForCallback("Get");
276 
277   // Make sure we got a property update too.
278   WaitForUpdates(1);
279 
280   EXPECT_EQ(20, properties_->version.value());
281 }
282 
TEST_F(PropertyTest,Set)283 TEST_F(PropertyTest, Set) {
284   WaitForGetAll();
285 
286   // Set a new name.
287   properties_->name.Set("NewService",
288                         base::Bind(&PropertyTest::PropertyCallback,
289                                    base::Unretained(this),
290                                    "Set"));
291   WaitForCallback("Set");
292 
293   // TestService sends a property update.
294   WaitForUpdates(1);
295 
296   EXPECT_EQ("NewService", properties_->name.value());
297 }
298 
TEST_F(PropertyTest,Invalidate)299 TEST_F(PropertyTest, Invalidate) {
300   WaitForGetAll();
301 
302   EXPECT_TRUE(properties_->name.is_valid());
303 
304   // Invalidate name.
305   MethodCall method_call("org.chromium.TestInterface", "PerformAction");
306   MessageWriter writer(&method_call);
307   writer.AppendString("InvalidateProperty");
308   writer.AppendObjectPath(ObjectPath("/org/chromium/TestService"));
309   object_proxy_->CallMethod(
310       &method_call, ObjectProxy::TIMEOUT_USE_DEFAULT,
311       base::Bind(&PropertyTest::MethodCallback, base::Unretained(this)));
312   WaitForMethodCallback();
313 
314   // TestService sends a property update.
315   WaitForUpdates(1);
316 
317   EXPECT_FALSE(properties_->name.is_valid());
318 
319   // Set name to something valid.
320   properties_->name.Set("NewService",
321                         base::Bind(&PropertyTest::PropertyCallback,
322                                    base::Unretained(this), "Set"));
323   WaitForCallback("Set");
324 
325   // TestService sends a property update.
326   WaitForUpdates(1);
327 
328   EXPECT_TRUE(properties_->name.is_valid());
329 }
330 
TEST(PropertyTestStatic,ReadWriteStringMap)331 TEST(PropertyTestStatic, ReadWriteStringMap) {
332   std::unique_ptr<Response> message(Response::CreateEmpty());
333   MessageWriter writer(message.get());
334   MessageWriter variant_writer(nullptr);
335   MessageWriter variant_array_writer(nullptr);
336   MessageWriter struct_entry_writer(nullptr);
337 
338   writer.OpenVariant("a{ss}", &variant_writer);
339   variant_writer.OpenArray("{ss}", &variant_array_writer);
340   const char* items[] = {"One", "Two", "Three", "Four"};
341   for (unsigned i = 0; i < arraysize(items); ++i) {
342     variant_array_writer.OpenDictEntry(&struct_entry_writer);
343     struct_entry_writer.AppendString(items[i]);
344     struct_entry_writer.AppendString(base::UintToString(i + 1));
345     variant_array_writer.CloseContainer(&struct_entry_writer);
346   }
347   variant_writer.CloseContainer(&variant_array_writer);
348   writer.CloseContainer(&variant_writer);
349 
350   MessageReader reader(message.get());
351   Property<std::map<std::string, std::string>> string_map;
352   EXPECT_TRUE(string_map.PopValueFromReader(&reader));
353   ASSERT_EQ(4U, string_map.value().size());
354   EXPECT_EQ("1", string_map.value().at("One"));
355   EXPECT_EQ("2", string_map.value().at("Two"));
356   EXPECT_EQ("3", string_map.value().at("Three"));
357   EXPECT_EQ("4", string_map.value().at("Four"));
358 }
359 
TEST(PropertyTestStatic,SerializeStringMap)360 TEST(PropertyTestStatic, SerializeStringMap) {
361   std::map<std::string, std::string> test_map;
362   test_map["Hi"] = "There";
363   test_map["Map"] = "Test";
364   test_map["Random"] = "Text";
365 
366   std::unique_ptr<Response> message(Response::CreateEmpty());
367   MessageWriter writer(message.get());
368 
369   Property<std::map<std::string, std::string>> string_map;
370   string_map.ReplaceSetValueForTesting(test_map);
371   string_map.AppendSetValueToWriter(&writer);
372 
373   MessageReader reader(message.get());
374   EXPECT_TRUE(string_map.PopValueFromReader(&reader));
375   EXPECT_EQ(test_map, string_map.value());
376 }
377 
TEST(PropertyTestStatic,ReadWriteNetAddressArray)378 TEST(PropertyTestStatic, ReadWriteNetAddressArray) {
379   std::unique_ptr<Response> message(Response::CreateEmpty());
380   MessageWriter writer(message.get());
381   MessageWriter variant_writer(nullptr);
382   MessageWriter variant_array_writer(nullptr);
383   MessageWriter struct_entry_writer(nullptr);
384 
385   writer.OpenVariant("a(ayq)", &variant_writer);
386   variant_writer.OpenArray("(ayq)", &variant_array_writer);
387   uint8_t ip_bytes[] = {0x54, 0x65, 0x73, 0x74, 0x30};
388   for (uint16_t i = 0; i < 5; ++i) {
389     variant_array_writer.OpenStruct(&struct_entry_writer);
390     ip_bytes[4] = 0x30 + i;
391     struct_entry_writer.AppendArrayOfBytes(ip_bytes, arraysize(ip_bytes));
392     struct_entry_writer.AppendUint16(i);
393     variant_array_writer.CloseContainer(&struct_entry_writer);
394   }
395   variant_writer.CloseContainer(&variant_array_writer);
396   writer.CloseContainer(&variant_writer);
397 
398   MessageReader reader(message.get());
399   Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>> ip_list;
400   EXPECT_TRUE(ip_list.PopValueFromReader(&reader));
401 
402   ASSERT_EQ(5U, ip_list.value().size());
403   size_t item_index = 0;
404   for (auto& item : ip_list.value()) {
405     ASSERT_EQ(5U, item.first.size());
406     ip_bytes[4] = 0x30 + item_index;
407     EXPECT_EQ(0, memcmp(ip_bytes, item.first.data(), 5U));
408     EXPECT_EQ(item_index, item.second);
409     ++item_index;
410   }
411 }
412 
TEST(PropertyTestStatic,SerializeNetAddressArray)413 TEST(PropertyTestStatic, SerializeNetAddressArray) {
414   std::vector<std::pair<std::vector<uint8_t>, uint16_t>> test_list;
415 
416   uint8_t ip_bytes[] = {0x54, 0x65, 0x73, 0x74, 0x30};
417   for (uint16_t i = 0; i < 5; ++i) {
418     ip_bytes[4] = 0x30 + i;
419     std::vector<uint8_t> bytes(ip_bytes, ip_bytes + arraysize(ip_bytes));
420     test_list.push_back(make_pair(bytes, 16));
421   }
422 
423   std::unique_ptr<Response> message(Response::CreateEmpty());
424   MessageWriter writer(message.get());
425 
426   Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>> ip_list;
427   ip_list.ReplaceSetValueForTesting(test_list);
428   ip_list.AppendSetValueToWriter(&writer);
429 
430   MessageReader reader(message.get());
431   EXPECT_TRUE(ip_list.PopValueFromReader(&reader));
432   EXPECT_EQ(test_list, ip_list.value());
433 }
434 
TEST(PropertyTestStatic,ReadWriteStringToByteVectorMap)435 TEST(PropertyTestStatic, ReadWriteStringToByteVectorMap) {
436   std::unique_ptr<Response> message(Response::CreateEmpty());
437   MessageWriter writer(message.get());
438   MessageWriter variant_writer(nullptr);
439   MessageWriter dict_writer(nullptr);
440 
441   writer.OpenVariant("a{sv}", &variant_writer);
442   variant_writer.OpenArray("{sv}", &dict_writer);
443 
444   const char* keys[] = {"One", "Two", "Three", "Four"};
445   const std::vector<uint8_t> values[] = {{1}, {1, 2}, {1, 2, 3}, {1, 2, 3, 4}};
446   for (unsigned i = 0; i < arraysize(keys); ++i) {
447     MessageWriter entry_writer(nullptr);
448     dict_writer.OpenDictEntry(&entry_writer);
449 
450     entry_writer.AppendString(keys[i]);
451 
452     MessageWriter value_varient_writer(nullptr);
453     entry_writer.OpenVariant("ay", &value_varient_writer);
454     value_varient_writer.AppendArrayOfBytes(values[i].data(), values[i].size());
455     entry_writer.CloseContainer(&value_varient_writer);
456 
457     dict_writer.CloseContainer(&entry_writer);
458   }
459 
460   variant_writer.CloseContainer(&dict_writer);
461   writer.CloseContainer(&variant_writer);
462 
463   MessageReader reader(message.get());
464   Property<std::map<std::string, std::vector<uint8_t>>> test_property;
465   EXPECT_TRUE(test_property.PopValueFromReader(&reader));
466 
467   ASSERT_EQ(arraysize(keys), test_property.value().size());
468   for (unsigned i = 0; i < arraysize(keys); ++i)
469     EXPECT_EQ(values[i], test_property.value().at(keys[i]));
470 }
471 
TEST(PropertyTestStatic,SerializeStringToByteVectorMap)472 TEST(PropertyTestStatic, SerializeStringToByteVectorMap) {
473   std::map<std::string, std::vector<uint8_t>> test_map;
474   test_map["Hi"] = {1, 2, 3};
475   test_map["Map"] = {0xab, 0xcd};
476   test_map["Random"] = {0x0};
477 
478   std::unique_ptr<Response> message(Response::CreateEmpty());
479   MessageWriter writer(message.get());
480 
481   Property<std::map<std::string, std::vector<uint8_t>>> test_property;
482   test_property.ReplaceSetValueForTesting(test_map);
483   test_property.AppendSetValueToWriter(&writer);
484 
485   MessageReader reader(message.get());
486   EXPECT_TRUE(test_property.PopValueFromReader(&reader));
487   EXPECT_EQ(test_map, test_property.value());
488 }
489 
TEST(PropertyTestStatic,ReadWriteUInt16ToByteVectorMap)490 TEST(PropertyTestStatic, ReadWriteUInt16ToByteVectorMap) {
491   std::unique_ptr<Response> message(Response::CreateEmpty());
492   MessageWriter writer(message.get());
493   MessageWriter variant_writer(nullptr);
494   MessageWriter dict_writer(nullptr);
495 
496   writer.OpenVariant("a{qv}", &variant_writer);
497   variant_writer.OpenArray("{qv}", &dict_writer);
498 
499   const uint16_t keys[] = {11, 12, 13, 14};
500   const std::vector<uint8_t> values[] = {{1}, {1, 2}, {1, 2, 3}, {1, 2, 3, 4}};
501   for (unsigned i = 0; i < arraysize(keys); ++i) {
502     MessageWriter entry_writer(nullptr);
503     dict_writer.OpenDictEntry(&entry_writer);
504 
505     entry_writer.AppendUint16(keys[i]);
506 
507     MessageWriter value_varient_writer(nullptr);
508     entry_writer.OpenVariant("ay", &value_varient_writer);
509     value_varient_writer.AppendArrayOfBytes(values[i].data(), values[i].size());
510     entry_writer.CloseContainer(&value_varient_writer);
511 
512     dict_writer.CloseContainer(&entry_writer);
513   }
514 
515   variant_writer.CloseContainer(&dict_writer);
516   writer.CloseContainer(&variant_writer);
517 
518   MessageReader reader(message.get());
519   Property<std::map<uint16_t, std::vector<uint8_t>>> test_property;
520   EXPECT_TRUE(test_property.PopValueFromReader(&reader));
521 
522   ASSERT_EQ(arraysize(keys), test_property.value().size());
523   for (unsigned i = 0; i < arraysize(keys); ++i)
524     EXPECT_EQ(values[i], test_property.value().at(keys[i]));
525 }
526 
TEST(PropertyTestStatic,SerializeUInt16ToByteVectorMap)527 TEST(PropertyTestStatic, SerializeUInt16ToByteVectorMap) {
528   std::map<uint16_t, std::vector<uint8_t>> test_map;
529   test_map[11] = {1, 2, 3};
530   test_map[12] = {0xab, 0xcd};
531   test_map[13] = {0x0};
532 
533   std::unique_ptr<Response> message(Response::CreateEmpty());
534   MessageWriter writer(message.get());
535 
536   Property<std::map<uint16_t, std::vector<uint8_t>>> test_property;
537   test_property.ReplaceSetValueForTesting(test_map);
538   test_property.AppendSetValueToWriter(&writer);
539 
540   MessageReader reader(message.get());
541   EXPECT_TRUE(test_property.PopValueFromReader(&reader));
542   EXPECT_EQ(test_map, test_property.value());
543 }
544 
545 }  // namespace dbus
546