Fix emulator build error
[platform/framework/web/chromium-efl.git] / dbus / bus_unittest.cc
1 // Copyright 2012 The Chromium Authors
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/bus.h"
6
7 #include <memory>
8
9 #include "base/files/file_descriptor_watcher_posix.h"
10 #include "base/functional/bind.h"
11 #include "base/functional/callback_helpers.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/message_loop/message_pump_type.h"
14 #include "base/run_loop.h"
15 #include "base/test/task_environment.h"
16 #include "base/threading/thread.h"
17 #include "dbus/error.h"
18 #include "dbus/exported_object.h"
19 #include "dbus/object_path.h"
20 #include "dbus/object_proxy.h"
21 #include "dbus/test_service.h"
22
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 namespace dbus {
26
27 namespace {
28
29 // Test helper for BusTest.ListenForServiceOwnerChange that wraps a
30 // base::RunLoop. At Run() time, the caller pass in the expected number of
31 // quit calls, and at QuitIfConditionIsSatisified() time, only quit the RunLoop
32 // if the expected number of quit calls have been reached.
33 class RunLoopWithExpectedCount {
34  public:
35   RunLoopWithExpectedCount() : expected_quit_calls_(0), actual_quit_calls_(0) {}
36
37   RunLoopWithExpectedCount(const RunLoopWithExpectedCount&) = delete;
38   RunLoopWithExpectedCount& operator=(const RunLoopWithExpectedCount&) = delete;
39
40   ~RunLoopWithExpectedCount() = default;
41
42   void Run(int expected_quit_calls) {
43     DCHECK_EQ(0, expected_quit_calls_);
44     DCHECK_EQ(0, actual_quit_calls_);
45     expected_quit_calls_ = expected_quit_calls;
46     run_loop_ = std::make_unique<base::RunLoop>();
47     run_loop_->Run();
48   }
49
50   void QuitIfConditionIsSatisified() {
51     if (++actual_quit_calls_ != expected_quit_calls_)
52       return;
53     run_loop_->Quit();
54     expected_quit_calls_ = 0;
55     actual_quit_calls_ = 0;
56   }
57
58  private:
59   std::unique_ptr<base::RunLoop> run_loop_;
60   int expected_quit_calls_;
61   int actual_quit_calls_;
62 };
63
64 // Test helper for BusTest.ListenForServiceOwnerChange.
65 void OnServiceOwnerChanged(RunLoopWithExpectedCount* run_loop_state,
66                            std::string* service_owner,
67                            int* num_of_owner_changes,
68                            const std::string& new_service_owner) {
69   *service_owner = new_service_owner;
70   ++(*num_of_owner_changes);
71   run_loop_state->QuitIfConditionIsSatisified();
72 }
73
74 }  // namespace
75
76 TEST(BusTest, GetObjectProxy) {
77   Bus::Options options;
78   scoped_refptr<Bus> bus = new Bus(options);
79
80   ObjectProxy* object_proxy1 =
81       bus->GetObjectProxy("org.chromium.TestService",
82                           ObjectPath("/org/chromium/TestObject"));
83   ASSERT_TRUE(object_proxy1);
84
85   // This should return the same object.
86   ObjectProxy* object_proxy2 =
87       bus->GetObjectProxy("org.chromium.TestService",
88                           ObjectPath("/org/chromium/TestObject"));
89   ASSERT_TRUE(object_proxy2);
90   EXPECT_EQ(object_proxy1, object_proxy2);
91
92   // This should not.
93   ObjectProxy* object_proxy3 =
94       bus->GetObjectProxy(
95           "org.chromium.TestService",
96           ObjectPath("/org/chromium/DifferentTestObject"));
97   ASSERT_TRUE(object_proxy3);
98   EXPECT_NE(object_proxy1, object_proxy3);
99
100   bus->ShutdownAndBlock();
101 }
102
103 TEST(BusTest, GetObjectProxyIgnoreUnknownService) {
104   Bus::Options options;
105   scoped_refptr<Bus> bus = new Bus(options);
106
107   ObjectProxy* object_proxy1 =
108       bus->GetObjectProxyWithOptions(
109           "org.chromium.TestService",
110           ObjectPath("/org/chromium/TestObject"),
111           ObjectProxy::IGNORE_SERVICE_UNKNOWN_ERRORS);
112   ASSERT_TRUE(object_proxy1);
113
114   // This should return the same object.
115   ObjectProxy* object_proxy2 =
116       bus->GetObjectProxyWithOptions(
117           "org.chromium.TestService",
118           ObjectPath("/org/chromium/TestObject"),
119           ObjectProxy::IGNORE_SERVICE_UNKNOWN_ERRORS);
120   ASSERT_TRUE(object_proxy2);
121   EXPECT_EQ(object_proxy1, object_proxy2);
122
123   // This should not.
124   ObjectProxy* object_proxy3 =
125       bus->GetObjectProxyWithOptions(
126           "org.chromium.TestService",
127           ObjectPath("/org/chromium/DifferentTestObject"),
128           ObjectProxy::IGNORE_SERVICE_UNKNOWN_ERRORS);
129   ASSERT_TRUE(object_proxy3);
130   EXPECT_NE(object_proxy1, object_proxy3);
131
132   bus->ShutdownAndBlock();
133 }
134
135 TEST(BusTest, RemoveObjectProxy) {
136   base::test::SingleThreadTaskEnvironment task_environment;
137
138   // Start the D-Bus thread.
139   base::Thread::Options thread_options;
140   thread_options.message_pump_type = base::MessagePumpType::IO;
141   base::Thread dbus_thread("D-Bus thread");
142   dbus_thread.StartWithOptions(std::move(thread_options));
143
144   // Create the bus.
145   Bus::Options options;
146   options.dbus_task_runner = dbus_thread.task_runner();
147   scoped_refptr<Bus> bus = new Bus(options);
148   ASSERT_FALSE(bus->shutdown_completed());
149
150   // Try to remove a non existant object proxy should return false.
151   ASSERT_FALSE(bus->RemoveObjectProxy("org.chromium.TestService",
152                                       ObjectPath("/org/chromium/TestObject"),
153                                       base::DoNothing()));
154
155   ObjectProxy* object_proxy1 =
156       bus->GetObjectProxy("org.chromium.TestService",
157                           ObjectPath("/org/chromium/TestObject"));
158   ASSERT_TRUE(object_proxy1);
159
160   // Increment the reference count to the object proxy to avoid destroying it
161   // while removing the object.
162   object_proxy1->AddRef();
163
164   // Remove the object from the bus. This will invalidate any other usage of
165   // object_proxy1 other than destroy it. We keep this object for a comparison
166   // at a later time.
167   ASSERT_TRUE(bus->RemoveObjectProxy("org.chromium.TestService",
168                                      ObjectPath("/org/chromium/TestObject"),
169                                      base::DoNothing()));
170
171   // This should return a different object because the first object was removed
172   // from the bus, but not deleted from memory.
173   ObjectProxy* object_proxy2 =
174       bus->GetObjectProxy("org.chromium.TestService",
175                           ObjectPath("/org/chromium/TestObject"));
176   ASSERT_TRUE(object_proxy2);
177
178   // Compare the new object with the first object. The first object still exists
179   // thanks to the increased reference.
180   EXPECT_NE(object_proxy1, object_proxy2);
181
182   // Release object_proxy1.
183   object_proxy1->Release();
184
185   // Shut down synchronously.
186   bus->ShutdownOnDBusThreadAndBlock();
187   EXPECT_TRUE(bus->shutdown_completed());
188   dbus_thread.Stop();
189 }
190
191 TEST(BusTest, GetExportedObject) {
192   Bus::Options options;
193   scoped_refptr<Bus> bus = new Bus(options);
194
195   ExportedObject* object_proxy1 =
196       bus->GetExportedObject(ObjectPath("/org/chromium/TestObject"));
197   ASSERT_TRUE(object_proxy1);
198
199   // This should return the same object.
200   ExportedObject* object_proxy2 =
201       bus->GetExportedObject(ObjectPath("/org/chromium/TestObject"));
202   ASSERT_TRUE(object_proxy2);
203   EXPECT_EQ(object_proxy1, object_proxy2);
204
205   // This should not.
206   ExportedObject* object_proxy3 =
207       bus->GetExportedObject(
208           ObjectPath("/org/chromium/DifferentTestObject"));
209   ASSERT_TRUE(object_proxy3);
210   EXPECT_NE(object_proxy1, object_proxy3);
211
212   bus->ShutdownAndBlock();
213 }
214
215 TEST(BusTest, UnregisterExportedObject) {
216   // Start the D-Bus thread.
217   base::Thread::Options thread_options;
218   thread_options.message_pump_type = base::MessagePumpType::IO;
219   base::Thread dbus_thread("D-Bus thread");
220   dbus_thread.StartWithOptions(std::move(thread_options));
221
222   // Create the bus.
223   Bus::Options options;
224   options.dbus_task_runner = dbus_thread.task_runner();
225   scoped_refptr<Bus> bus = new Bus(options);
226   ASSERT_FALSE(bus->shutdown_completed());
227
228   ExportedObject* object_proxy1 =
229       bus->GetExportedObject(ObjectPath("/org/chromium/TestObject"));
230   ASSERT_TRUE(object_proxy1);
231
232   // Increment the reference count to the object proxy to avoid destroying it
233   // calling UnregisterExportedObject. This ensures the dbus::ExportedObject is
234   // not freed from memory. See http://crbug.com/137846 for details.
235   object_proxy1->AddRef();
236
237   bus->UnregisterExportedObject(ObjectPath("/org/chromium/TestObject"));
238
239   // This should return a new object because the object_proxy1 is still in
240   // alloc'ed memory.
241   ExportedObject* object_proxy2 =
242       bus->GetExportedObject(ObjectPath("/org/chromium/TestObject"));
243   ASSERT_TRUE(object_proxy2);
244   EXPECT_NE(object_proxy1, object_proxy2);
245
246   // Release the incremented reference.
247   object_proxy1->Release();
248
249   // Shut down synchronously.
250   bus->ShutdownOnDBusThreadAndBlock();
251   EXPECT_TRUE(bus->shutdown_completed());
252   dbus_thread.Stop();
253 }
254
255 TEST(BusTest, ShutdownAndBlock) {
256   Bus::Options options;
257   scoped_refptr<Bus> bus = new Bus(options);
258   ASSERT_FALSE(bus->shutdown_completed());
259
260   // Shut down synchronously.
261   bus->ShutdownAndBlock();
262   EXPECT_TRUE(bus->shutdown_completed());
263 }
264
265 TEST(BusTest, ShutdownAndBlockWithDBusThread) {
266   // Start the D-Bus thread.
267   base::Thread::Options thread_options;
268   thread_options.message_pump_type = base::MessagePumpType::IO;
269   base::Thread dbus_thread("D-Bus thread");
270   dbus_thread.StartWithOptions(std::move(thread_options));
271
272   // Create the bus.
273   Bus::Options options;
274   options.dbus_task_runner = dbus_thread.task_runner();
275   scoped_refptr<Bus> bus = new Bus(options);
276   ASSERT_FALSE(bus->shutdown_completed());
277
278   // Shut down synchronously.
279   bus->ShutdownOnDBusThreadAndBlock();
280   EXPECT_TRUE(bus->shutdown_completed());
281   dbus_thread.Stop();
282 }
283
284 TEST(BusTest, DoubleAddAndRemoveMatch) {
285   Bus::Options options;
286   scoped_refptr<Bus> bus = new Bus(options);
287   dbus::Error error;
288
289   bus->Connect();
290
291   // Adds the same rule twice.
292   bus->AddMatch("type='signal',interface='org.chromium.TestService',path='/'",
293                 &error);
294   ASSERT_FALSE(error.IsValid());
295
296   bus->AddMatch("type='signal',interface='org.chromium.TestService',path='/'",
297                 &error);
298   ASSERT_FALSE(error.IsValid());
299
300   // Removes the same rule twice.
301   ASSERT_TRUE(bus->RemoveMatch(
302       "type='signal',interface='org.chromium.TestService',path='/'", &error));
303   ASSERT_FALSE(error.IsValid());
304
305   // The rule should be still in the bus since it was removed only once.
306   // A second removal shouldn't give an error.
307   ASSERT_TRUE(bus->RemoveMatch(
308       "type='signal',interface='org.chromium.TestService',path='/'", &error));
309   ASSERT_FALSE(error.IsValid());
310
311   // A third attemp to remove the same rule should fail.
312   ASSERT_FALSE(bus->RemoveMatch(
313       "type='signal',interface='org.chromium.TestService',path='/'", &error));
314
315   bus->ShutdownAndBlock();
316 }
317
318 TEST(BusTest, ListenForServiceOwnerChange) {
319   base::test::SingleThreadTaskEnvironment task_environment(
320       base::test::SingleThreadTaskEnvironment::MainThreadType::IO);
321
322   RunLoopWithExpectedCount run_loop_state;
323
324   // Create the bus.
325   Bus::Options bus_options;
326   scoped_refptr<Bus> bus = new Bus(bus_options);
327
328   // Add a listener.
329   std::string service_owner1;
330   int num_of_owner_changes1 = 0;
331   Bus::ServiceOwnerChangeCallback callback1 =
332       base::BindRepeating(&OnServiceOwnerChanged, &run_loop_state,
333                           &service_owner1, &num_of_owner_changes1);
334   bus->ListenForServiceOwnerChange("org.chromium.TestService", callback1);
335   // This should be a no-op.
336   bus->ListenForServiceOwnerChange("org.chromium.TestService", callback1);
337   base::RunLoop().RunUntilIdle();
338
339   // Nothing has happened yet. Check initial state.
340   EXPECT_TRUE(service_owner1.empty());
341   EXPECT_EQ(0, num_of_owner_changes1);
342
343   // Make an ownership change.
344   ASSERT_TRUE(bus->RequestOwnershipAndBlock("org.chromium.TestService",
345                                             Bus::REQUIRE_PRIMARY));
346   run_loop_state.Run(1);
347
348   {
349     // Get the current service owner and check to make sure the listener got
350     // the right value.
351     std::string current_service_owner =
352         bus->GetServiceOwnerAndBlock("org.chromium.TestService",
353                                      Bus::REPORT_ERRORS);
354     ASSERT_FALSE(current_service_owner.empty());
355
356     // Make sure the listener heard about the new owner.
357     EXPECT_EQ(current_service_owner, service_owner1);
358
359     // Test the second ListenForServiceOwnerChange() above is indeed a no-op.
360     EXPECT_EQ(1, num_of_owner_changes1);
361   }
362
363   // Add a second listener.
364   std::string service_owner2;
365   int num_of_owner_changes2 = 0;
366   Bus::ServiceOwnerChangeCallback callback2 =
367       base::BindRepeating(&OnServiceOwnerChanged, &run_loop_state,
368                           &service_owner2, &num_of_owner_changes2);
369   bus->ListenForServiceOwnerChange("org.chromium.TestService", callback2);
370   base::RunLoop().RunUntilIdle();
371
372   // Release the ownership and make sure the service owner listeners fire with
373   // the right values and the right number of times.
374   ASSERT_TRUE(bus->ReleaseOwnership("org.chromium.TestService"));
375   run_loop_state.Run(2);
376
377   EXPECT_TRUE(service_owner1.empty());
378   EXPECT_TRUE(service_owner2.empty());
379   EXPECT_EQ(2, num_of_owner_changes1);
380   EXPECT_EQ(1, num_of_owner_changes2);
381
382   // Unlisten so shutdown can proceed correctly.
383   bus->UnlistenForServiceOwnerChange("org.chromium.TestService", callback1);
384   bus->UnlistenForServiceOwnerChange("org.chromium.TestService", callback2);
385   base::RunLoop().RunUntilIdle();
386
387   // Shut down synchronously.
388   bus->ShutdownAndBlock();
389   EXPECT_TRUE(bus->shutdown_completed());
390 }
391
392 TEST(BusTest, GetConnectionName) {
393   Bus::Options options;
394   scoped_refptr<Bus> bus = new Bus(options);
395
396   // Connection name is empty since bus is not connected.
397   EXPECT_FALSE(bus->IsConnected());
398   EXPECT_TRUE(bus->GetConnectionName().empty());
399
400   // Connect bus to D-Bus.
401   bus->Connect();
402
403   // Connection name is not empty after connection is established.
404   EXPECT_TRUE(bus->IsConnected());
405   EXPECT_FALSE(bus->GetConnectionName().empty());
406
407   // Shut down synchronously.
408   bus->ShutdownAndBlock();
409   EXPECT_TRUE(bus->shutdown_completed());
410 }
411
412 }  // namespace dbus