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.
6 #include "base/memory/scoped_ptr.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/metrics/histogram.h"
9 #include "base/metrics/histogram_samples.h"
10 #include "base/metrics/statistics_recorder.h"
11 #include "base/run_loop.h"
12 #include "base/test/test_timeouts.h"
13 #include "base/threading/platform_thread.h"
14 #include "base/threading/thread_restrictions.h"
16 #include "dbus/message.h"
17 #include "dbus/object_proxy.h"
18 #include "dbus/test_service.h"
19 #include "testing/gtest/include/gtest/gtest.h"
23 // The test for sender verification in ObjectProxy.
24 class SignalSenderVerificationTest
: public testing::Test
{
26 SignalSenderVerificationTest()
27 : on_name_owner_changed_called_(false),
28 on_ownership_called_(false) {
31 void SetUp() override
{
32 base::StatisticsRecorder::Initialize();
34 // Make the main thread not to allow IO.
35 base::ThreadRestrictions::SetIOAllowed(false);
37 // Start the D-Bus thread.
38 dbus_thread_
.reset(new base::Thread("D-Bus Thread"));
39 base::Thread::Options thread_options
;
40 thread_options
.message_loop_type
= base::MessageLoop::TYPE_IO
;
41 ASSERT_TRUE(dbus_thread_
->StartWithOptions(thread_options
));
43 // Create the client, using the D-Bus thread.
44 Bus::Options bus_options
;
45 bus_options
.bus_type
= Bus::SESSION
;
46 bus_options
.connection_type
= Bus::PRIVATE
;
47 bus_options
.dbus_task_runner
= dbus_thread_
->message_loop_proxy();
48 bus_
= new Bus(bus_options
);
49 object_proxy_
= bus_
->GetObjectProxy(
50 "org.chromium.TestService",
51 ObjectPath("/org/chromium/TestObject"));
52 ASSERT_TRUE(bus_
->HasDBusThread());
54 object_proxy_
->SetNameOwnerChangedCallback(
55 base::Bind(&SignalSenderVerificationTest::OnNameOwnerChanged
,
56 base::Unretained(this),
57 &on_name_owner_changed_called_
));
59 // Connect to the "Test" signal of "org.chromium.TestInterface" from
61 object_proxy_
->ConnectToSignal(
62 "org.chromium.TestInterface",
64 base::Bind(&SignalSenderVerificationTest::OnTestSignal
,
65 base::Unretained(this)),
66 base::Bind(&SignalSenderVerificationTest::OnConnected
,
67 base::Unretained(this)));
68 // Wait until the object proxy is connected to the signal.
69 run_loop_
.reset(new base::RunLoop
);
72 // Start the test service, using the D-Bus thread.
73 TestService::Options options
;
74 options
.dbus_task_runner
= dbus_thread_
->message_loop_proxy();
75 test_service_
.reset(new TestService(options
));
76 ASSERT_TRUE(test_service_
->StartService());
77 ASSERT_TRUE(test_service_
->WaitUntilServiceIsStarted());
78 ASSERT_TRUE(test_service_
->HasDBusThread());
79 ASSERT_TRUE(test_service_
->has_ownership());
81 // Same setup for the second TestService. This service should not have the
82 // ownership of the name at this point.
83 test_service2_
.reset(new TestService(options
));
84 ASSERT_TRUE(test_service2_
->StartService());
85 ASSERT_TRUE(test_service2_
->WaitUntilServiceIsStarted());
86 ASSERT_TRUE(test_service2_
->HasDBusThread());
87 ASSERT_FALSE(test_service2_
->has_ownership());
89 // The name should be owned and known at this point.
90 if (!on_name_owner_changed_called_
) {
91 run_loop_
.reset(new base::RunLoop
);
94 ASSERT_FALSE(latest_name_owner_
.empty());
97 void TearDown() override
{
98 bus_
->ShutdownOnDBusThreadAndBlock();
100 // Shut down the service.
101 test_service_
->ShutdownAndBlock();
102 test_service2_
->ShutdownAndBlock();
104 // Reset to the default.
105 base::ThreadRestrictions::SetIOAllowed(true);
107 // Stopping a thread is considered an IO operation, so do this after
109 test_service_
->Stop();
110 test_service2_
->Stop();
113 void OnOwnership(bool expected
, bool success
) {
114 ASSERT_EQ(expected
, success
);
115 // PostTask to quit the MessageLoop as this is called from D-Bus thread.
116 message_loop_
.PostTask(
118 base::Bind(&SignalSenderVerificationTest::OnOwnershipInternal
,
119 base::Unretained(this)));
122 void OnOwnershipInternal() {
123 on_ownership_called_
= true;
127 void OnNameOwnerChanged(bool* called_flag
,
128 const std::string
& old_owner
,
129 const std::string
& new_owner
) {
130 latest_name_owner_
= new_owner
;
135 // Called when the "Test" signal is received, in the main thread.
136 // Copy the string payload to |test_signal_string_|.
137 void OnTestSignal(Signal
* signal
) {
138 MessageReader
reader(signal
);
139 ASSERT_TRUE(reader
.PopString(&test_signal_string_
));
143 // Called when connected to the signal.
144 void OnConnected(const std::string
& interface_name
,
145 const std::string
& signal_name
,
147 ASSERT_TRUE(success
);
152 // Wait for the hey signal to be received.
153 void WaitForTestSignal() {
154 // OnTestSignal() will quit the message loop.
155 run_loop_
.reset(new base::RunLoop
);
159 // Stopping a thread is considered an IO operation, so we need to fiddle with
160 // thread restrictions before and after calling Stop() on a TestService.
161 void SafeServiceStop(TestService
* test_service
) {
162 base::ThreadRestrictions::SetIOAllowed(true);
163 test_service
->Stop();
164 base::ThreadRestrictions::SetIOAllowed(false);
167 base::MessageLoop message_loop_
;
168 scoped_ptr
<base::RunLoop
> run_loop_
;
169 scoped_ptr
<base::Thread
> dbus_thread_
;
170 scoped_refptr
<Bus
> bus_
;
171 ObjectProxy
* object_proxy_
;
172 scoped_ptr
<TestService
> test_service_
;
173 scoped_ptr
<TestService
> test_service2_
;
174 // Text message from "Test" signal.
175 std::string test_signal_string_
;
177 // The known latest name owner of TestService. Updated in OnNameOwnerChanged.
178 std::string latest_name_owner_
;
180 // Boolean flags to record callback calls.
181 bool on_name_owner_changed_called_
;
182 bool on_ownership_called_
;
185 TEST_F(SignalSenderVerificationTest
, TestSignalAccepted
) {
186 const char kMessage
[] = "hello, world";
187 // Send the test signal from the exported object.
188 test_service_
->SendTestSignal(kMessage
);
189 // Receive the signal with the object proxy. The signal is handled in
190 // SignalSenderVerificationTest::OnTestSignal() in the main thread.
192 ASSERT_EQ(kMessage
, test_signal_string_
);
195 // Disabled, http://crbug.com/407063 .
196 TEST_F(SignalSenderVerificationTest
, DISABLED_TestSignalRejected
) {
197 // To make sure the histogram instance is created.
198 UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 0);
199 base::HistogramBase
* reject_signal_histogram
=
200 base::StatisticsRecorder::FindHistogram("DBus.RejectedSignalCount");
201 scoped_ptr
<base::HistogramSamples
> samples1(
202 reject_signal_histogram
->SnapshotSamples());
204 const char kNewMessage
[] = "hello, new world";
205 test_service2_
->SendTestSignal(kNewMessage
);
207 // This test tests that our callback is NOT called by the ObjectProxy.
208 // Sleep to have message delivered to the client via the D-Bus service.
209 base::PlatformThread::Sleep(TestTimeouts::action_timeout());
211 scoped_ptr
<base::HistogramSamples
> samples2(
212 reject_signal_histogram
->SnapshotSamples());
214 ASSERT_EQ("", test_signal_string_
);
215 EXPECT_EQ(samples1
->TotalCount() + 1, samples2
->TotalCount());
218 TEST_F(SignalSenderVerificationTest
, TestOwnerChanged
) {
219 const char kMessage
[] = "hello, world";
221 // Send the test signal from the exported object.
222 test_service_
->SendTestSignal(kMessage
);
223 // Receive the signal with the object proxy. The signal is handled in
224 // SignalSenderVerificationTest::OnTestSignal() in the main thread.
226 ASSERT_EQ(kMessage
, test_signal_string_
);
228 // Release and acquire the name ownership.
229 // latest_name_owner_ should be non empty as |test_service_| owns the name.
230 ASSERT_FALSE(latest_name_owner_
.empty());
231 test_service_
->ShutdownAndBlock();
232 // OnNameOwnerChanged will PostTask to quit the message loop.
233 run_loop_
.reset(new base::RunLoop
);
235 // latest_name_owner_ should be empty as the owner is gone.
236 ASSERT_TRUE(latest_name_owner_
.empty());
238 // Reset the flag as NameOwnerChanged is already received in setup.
239 on_name_owner_changed_called_
= false;
240 on_ownership_called_
= false;
241 test_service2_
->RequestOwnership(
242 base::Bind(&SignalSenderVerificationTest::OnOwnership
,
243 base::Unretained(this), true));
244 // Both of OnNameOwnerChanged() and OnOwnership() should quit the MessageLoop,
245 // but there's no expected order of those 2 event.
246 run_loop_
.reset(new base::RunLoop
);
248 if (!on_name_owner_changed_called_
|| !on_ownership_called_
) {
249 run_loop_
.reset(new base::RunLoop
);
252 ASSERT_TRUE(on_name_owner_changed_called_
);
253 ASSERT_TRUE(on_ownership_called_
);
255 // latest_name_owner_ becomes non empty as the new owner appears.
256 ASSERT_FALSE(latest_name_owner_
.empty());
258 // Now the second service owns the name.
259 const char kNewMessage
[] = "hello, new world";
261 test_service2_
->SendTestSignal(kNewMessage
);
263 ASSERT_EQ(kNewMessage
, test_signal_string_
);
266 TEST_F(SignalSenderVerificationTest
, TestOwnerStealing
) {
267 // Release and acquire the name ownership.
268 // latest_name_owner_ should be non empty as |test_service_| owns the name.
269 ASSERT_FALSE(latest_name_owner_
.empty());
270 test_service_
->ShutdownAndBlock();
271 // OnNameOwnerChanged will PostTask to quit the message loop.
272 run_loop_
.reset(new base::RunLoop
);
274 // latest_name_owner_ should be empty as the owner is gone.
275 ASSERT_TRUE(latest_name_owner_
.empty());
276 // Reset the flag as NameOwnerChanged is already received in setup.
277 on_name_owner_changed_called_
= false;
279 // Start a test service that allows theft, using the D-Bus thread.
280 TestService::Options options
;
281 options
.dbus_task_runner
= dbus_thread_
->message_loop_proxy();
282 options
.request_ownership_options
= Bus::REQUIRE_PRIMARY_ALLOW_REPLACEMENT
;
283 TestService
stealable_test_service(options
);
284 ASSERT_TRUE(stealable_test_service
.StartService());
285 ASSERT_TRUE(stealable_test_service
.WaitUntilServiceIsStarted());
286 ASSERT_TRUE(stealable_test_service
.HasDBusThread());
287 ASSERT_TRUE(stealable_test_service
.has_ownership());
289 // OnNameOwnerChanged will PostTask to quit the message loop.
290 run_loop_
.reset(new base::RunLoop
);
293 // Send a signal to check that the service is correctly owned.
294 const char kMessage
[] = "hello, world";
296 // Send the test signal from the exported object.
297 stealable_test_service
.SendTestSignal(kMessage
);
298 // Receive the signal with the object proxy. The signal is handled in
299 // SignalSenderVerificationTest::OnTestSignal() in the main thread.
301 ASSERT_EQ(kMessage
, test_signal_string_
);
303 // Reset the flag as NameOwnerChanged was called above.
304 on_name_owner_changed_called_
= false;
305 test_service2_
->RequestOwnership(
306 base::Bind(&SignalSenderVerificationTest::OnOwnership
,
307 base::Unretained(this), true));
308 // Both of OnNameOwnerChanged() and OnOwnership() should quit the MessageLoop,
309 // but there's no expected order of those 2 event.
310 run_loop_
.reset(new base::RunLoop
);
312 if (!on_name_owner_changed_called_
|| !on_ownership_called_
) {
313 run_loop_
.reset(new base::RunLoop
);
316 ASSERT_TRUE(on_name_owner_changed_called_
);
317 ASSERT_TRUE(on_ownership_called_
);
319 // Now the second service owns the name.
320 const char kNewMessage
[] = "hello, new world";
322 test_service2_
->SendTestSignal(kNewMessage
);
324 ASSERT_EQ(kNewMessage
, test_signal_string_
);
326 SafeServiceStop(&stealable_test_service
);
329 // Fails on Linux ChromiumOS Tests
330 TEST_F(SignalSenderVerificationTest
, DISABLED_TestMultipleObjects
) {
331 const char kMessage
[] = "hello, world";
333 ObjectProxy
* object_proxy2
= bus_
->GetObjectProxy(
334 "org.chromium.TestService",
335 ObjectPath("/org/chromium/DifferentObject"));
337 bool second_name_owner_changed_called
= false;
338 object_proxy2
->SetNameOwnerChangedCallback(
339 base::Bind(&SignalSenderVerificationTest::OnNameOwnerChanged
,
340 base::Unretained(this),
341 &second_name_owner_changed_called
));
343 // Connect to a signal on the additional remote object to trigger the
344 // name owner matching.
345 object_proxy2
->ConnectToSignal(
346 "org.chromium.DifferentTestInterface",
348 base::Bind(&SignalSenderVerificationTest::OnTestSignal
,
349 base::Unretained(this)),
350 base::Bind(&SignalSenderVerificationTest::OnConnected
,
351 base::Unretained(this)));
352 // Wait until the object proxy is connected to the signal.
353 run_loop_
.reset(new base::RunLoop
);
356 // Send the test signal from the exported object.
357 test_service_
->SendTestSignal(kMessage
);
358 // Receive the signal with the object proxy. The signal is handled in
359 // SignalSenderVerificationTest::OnTestSignal() in the main thread.
361 ASSERT_EQ(kMessage
, test_signal_string_
);
363 // Release and acquire the name ownership.
364 // latest_name_owner_ should be non empty as |test_service_| owns the name.
365 ASSERT_FALSE(latest_name_owner_
.empty());
366 test_service_
->ShutdownAndBlock();
367 // OnNameOwnerChanged will PostTask to quit the message loop.
368 run_loop_
.reset(new base::RunLoop
);
370 // latest_name_owner_ should be empty as the owner is gone.
371 ASSERT_TRUE(latest_name_owner_
.empty());
373 // Reset the flag as NameOwnerChanged is already received in setup.
374 on_name_owner_changed_called_
= false;
375 second_name_owner_changed_called
= false;
376 test_service2_
->RequestOwnership(
377 base::Bind(&SignalSenderVerificationTest::OnOwnership
,
378 base::Unretained(this), true));
379 // Both of OnNameOwnerChanged() and OnOwnership() should quit the MessageLoop,
380 // but there's no expected order of those 2 event.
381 while (!on_name_owner_changed_called_
|| !second_name_owner_changed_called
||
382 !on_ownership_called_
) {
383 run_loop_
.reset(new base::RunLoop
);
386 ASSERT_TRUE(on_name_owner_changed_called_
);
387 ASSERT_TRUE(second_name_owner_changed_called
);
388 ASSERT_TRUE(on_ownership_called_
);
390 // latest_name_owner_ becomes non empty as the new owner appears.
391 ASSERT_FALSE(latest_name_owner_
.empty());
393 // Now the second service owns the name.
394 const char kNewMessage
[] = "hello, new world";
396 test_service2_
->SendTestSignal(kNewMessage
);
398 ASSERT_EQ(kNewMessage
, test_signal_string_
);