Chromium Code Reviews| Index: dbus/bus_unittest.cc |
| =================================================================== |
| --- dbus/bus_unittest.cc (revision 203477) |
| +++ dbus/bus_unittest.cc (working copy) |
| @@ -7,11 +7,13 @@ |
| #include "base/bind.h" |
| #include "base/message_loop.h" |
| #include "base/memory/ref_counted.h" |
| +#include "base/run_loop.h" |
| #include "base/threading/thread.h" |
| #include "dbus/exported_object.h" |
| #include "dbus/object_path.h" |
| #include "dbus/object_proxy.h" |
| #include "dbus/scoped_dbus_error.h" |
| +#include "dbus/test_service.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| @@ -24,6 +26,94 @@ |
| return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| } |
| +// The test helpers below are for BusTest.ListenForServiceOwnerChange. |
| + |
| +class OwnershipChangeListener { |
| + public: |
| + OwnershipChangeListener() : owner_changes_(0) {} |
| + ~OwnershipChangeListener() {} |
| + |
| + void OnServiceOwnerChanged(const std::string& new_service_owner) { |
| + current_owner_ = new_service_owner; |
| + ++owner_changes_; |
| + } |
| + |
| + void set_current_owner(const std::string& owner) { current_owner_ = owner; } |
| + const std::string& current_owner() const { return current_owner_; } |
| + |
| + int owner_changes() const { return owner_changes_; } |
| + |
| + private: |
| + std::string current_owner_; |
| + int owner_changes_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(OwnershipChangeListener); |
| +}; |
| + |
| +void RequestOwnershipHelper(const base::Closure& quit_closure, |
| + std::string* service_name, |
| + bool* is_owner, |
| + const std::string& actual_service_name, |
| + bool actual_is_owner) { |
| + *service_name = actual_service_name; |
| + *is_owner = actual_is_owner; |
| + quit_closure.Run(); |
| +} |
| + |
| +void RequestOwnership(dbus::Bus* bus, const std::string& service_name) { |
| + base::RunLoop run_loop; |
| + std::string requested_service_name; |
| + bool got_owner = false; |
| + bus->RequestOwnership(service_name, |
| + base::Bind(&RequestOwnershipHelper, |
| + run_loop.QuitClosure(), |
| + &requested_service_name, |
| + &got_owner)); |
| + run_loop.Run(); |
| + ASSERT_TRUE(got_owner); |
| + ASSERT_EQ(service_name, requested_service_name); |
| +} |
| + |
| +void ReleaseOwnershipHelper(const base::Closure& quit_closure, |
| + dbus::Bus* bus, |
| + const std::string& service_name, |
| + bool* released) { |
| + *released = bus->ReleaseOwnership(service_name); |
| + bus->PostTaskToOriginThread(FROM_HERE, quit_closure); |
| +} |
| + |
| +void ReleaseOwnership(dbus::Bus* bus, const std::string& service_name) { |
| + base::RunLoop run_loop; |
| + bool released = false; |
| + bus->PostTaskToDBusThread( |
| + FROM_HERE, |
| + base::Bind(&ReleaseOwnershipHelper, |
| + run_loop.QuitClosure(), |
| + make_scoped_refptr(bus), |
| + service_name, |
| + &released)); |
| + run_loop.Run(); |
| + ASSERT_TRUE(released); |
| +} |
| + |
| +void GetServiceOwnerHelper(const base::Closure& quit_closure, |
| + std::string* service_owner, |
| + const std::string& actual_service_owner) { |
| + *service_owner = actual_service_owner; |
| + quit_closure.Run(); |
| +} |
| + |
| +std::string GetServiceOwner(dbus::Bus* bus, const std::string& service_name) { |
| + base::RunLoop run_loop; |
| + std::string service_owner; |
| + bus->GetServiceOwner(service_name, |
| + base::Bind(&GetServiceOwnerHelper, |
| + run_loop.QuitClosure(), |
| + &service_owner)); |
| + run_loop.Run(); |
| + return service_owner; |
| +} |
| + |
| } // namespace |
| TEST(BusTest, GetObjectProxy) { |
| @@ -296,3 +386,77 @@ |
| bus->ShutdownAndBlock(); |
| } |
| + |
| +TEST(BusTest, ListenForServiceOwnerChange) { |
| + // Setup the current thread's MessageLoop. |
| + base::MessageLoop message_loop; |
| + |
| + // Start the D-Bus thread. |
| + base::Thread::Options thread_options; |
| + thread_options.message_loop_type = base::MessageLoop::TYPE_IO; |
| + base::Thread dbus_thread("D-Bus thread"); |
|
satorux1
2013/06/05 01:33:58
Do we need to create a D-Bus thread? Other test ca
Lei Zhang
2013/06/09 04:37:57
I copied it from the test right above this one and
|
| + dbus_thread.StartWithOptions(thread_options); |
| + |
| + // Create the bus. |
| + dbus::Bus::Options bus_options; |
| + bus_options.dbus_task_runner = dbus_thread.message_loop_proxy(); |
| + scoped_refptr<dbus::Bus> bus = new dbus::Bus(bus_options); |
| + ASSERT_FALSE(bus->shutdown_completed()); |
| + |
| + // Add a listener. |
| + OwnershipChangeListener ownership_change_listener_1; |
|
satorux1
2013/06/05 01:33:58
nit: ownership_change_listener1 ? having _ before
Lei Zhang
2013/06/09 04:37:57
Done.
|
| + ownership_change_listener_1.set_current_owner("dummy1"); |
|
satorux1
2013/06/05 01:33:58
At first, I was confused about why a dummy value w
|
| + dbus::Bus::GetServiceOwnerCallback callback1 = |
| + base::Bind(&OwnershipChangeListener::OnServiceOwnerChanged, |
|
satorux1
2013/06/05 01:33:58
This class seems to be unnecessary. Can we just pa
Lei Zhang
2013/06/09 04:37:57
Done
|
| + base::Unretained(&ownership_change_listener_1)); |
| + bus->ListenForServiceOwnerChange("org.chromium.TestService", callback1); |
| + // This should be a no-op. |
| + bus->ListenForServiceOwnerChange("org.chromium.TestService", callback1); |
| + |
| + // Nothing has happened yet. Check initial state. |
| + // The blocking GetServiceOwner() call makes sure the |
| + // ListenForServiceOwnerChange() calls happen first. |
| + std::string service_owner = GetServiceOwner(bus, "org.chromium.TestService"); |
| + ASSERT_TRUE(service_owner.empty()); |
| + ASSERT_EQ("dummy1", ownership_change_listener_1.current_owner()); |
| + EXPECT_EQ(0, ownership_change_listener_1.owner_changes()); |
| + |
| + // Make an ownership change. |
| + RequestOwnership(bus, "org.chromium.TestService"); |
| + service_owner = GetServiceOwner(bus, "org.chromium.TestService"); |
|
satorux1
2013/06/05 01:33:58
How does the |service_owner_| look like? Could you
|
| + ASSERT_FALSE(service_owner.empty()); |
| + ASSERT_EQ(service_owner, ownership_change_listener_1.current_owner()); |
| + |
| + // Test the second ListenForServiceOwnerChange() above is indeed a no-op. |
| + EXPECT_EQ(1, ownership_change_listener_1.owner_changes()); |
| + |
| + // Add a second listener. |
| + OwnershipChangeListener ownership_change_listener_2; |
| + ownership_change_listener_2.set_current_owner("dummy2"); |
| + dbus::Bus::GetServiceOwnerCallback callback2 = |
| + base::Bind(&OwnershipChangeListener::OnServiceOwnerChanged, |
| + base::Unretained(&ownership_change_listener_2)); |
| + bus->ListenForServiceOwnerChange("org.chromium.TestService", callback2); |
| + bus->ListenForServiceOwnerChange("org.chromium.FakeService", callback2); |
|
satorux1
2013/06/05 01:33:58
Why do we listen to "org.chromium.FakeService"? Co
Lei Zhang
2013/06/09 04:37:57
I guess it doesn't add too much value to the test,
|
| + |
| + // The blocking ReleaseOwnership() call makes sure the |
| + // ListenForServiceOwnerChange() calls happen first. |
| + ReleaseOwnership(bus, "org.chromium.TestService"); |
| + service_owner = GetServiceOwner(bus, "org.chromium.TestService"); |
| + ASSERT_TRUE(service_owner.empty()); |
| + ASSERT_TRUE(ownership_change_listener_1.current_owner().empty()); |
| + ASSERT_TRUE(ownership_change_listener_2.current_owner().empty()); |
| + EXPECT_EQ(2, ownership_change_listener_1.owner_changes()); |
| + EXPECT_EQ(1, ownership_change_listener_2.owner_changes()); |
| + |
| + bus->UnlistenForServiceOwnerChange("org.chromium.FakeService", callback2); |
| + bus->UnlistenForServiceOwnerChange("org.chromium.TestService", callback1); |
| + bus->UnlistenForServiceOwnerChange("org.chromium.TestService", callback2); |
| + |
| + // Shut down synchronously. The pending UnlistenForServiceOwnerChange() |
| + // calls will happen first. |
| + bus->ShutdownOnDBusThreadAndBlock(); |
| + EXPECT_TRUE(bus->shutdown_completed()); |
| + dbus_thread.Stop(); |
| +} |
| + |