diff options
author | thestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-10 22:52:34 +0000 |
---|---|---|
committer | thestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-10 22:52:34 +0000 |
commit | 049616e0afc089f4816ee521e937eafd0beb335d (patch) | |
tree | 14fa8b98ed6f07d448a1308403bf34d2838f6fa1 /dbus/bus_unittest.cc | |
parent | 36116cea8b862285f0e133170fb2ec7cd09f72ae (diff) | |
download | chromium_src-049616e0afc089f4816ee521e937eafd0beb335d.zip chromium_src-049616e0afc089f4816ee521e937eafd0beb335d.tar.gz chromium_src-049616e0afc089f4816ee521e937eafd0beb335d.tar.bz2 |
Linux/CrOS: Listen for mtpd service owner change events and communicate with the new service owner.
The mtpd dbus service may not start right away. Any attempts to use it may be racy due to the lack of a service owner. Listening for service owner changes fixes this race.
BUG=241302
TEST=Manual, see bug for repro case.
Review URL: https://chromiumcodereview.appspot.com/15741025
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@205331 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'dbus/bus_unittest.cc')
-rw-r--r-- | dbus/bus_unittest.cc | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/dbus/bus_unittest.cc b/dbus/bus_unittest.cc index 82949d3..3c453f7 100644 --- a/dbus/bus_unittest.cc +++ b/dbus/bus_unittest.cc @@ -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,49 @@ DBusHandlerResult DummyHandler(DBusConnection* connection, return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } +// Test helper for BusTest.ListenForServiceOwnerChange that wraps a +// base::RunLoop. At Run() time, the caller pass in the expected number of +// quit calls, and at QuitIfConditionIsSatisified() time, only quit the RunLoop +// if the expected number of quit calls have been reached. +class RunLoopWithExpectedCount { + public: + RunLoopWithExpectedCount() : expected_quit_calls_(0), actual_quit_calls_(0) {} + ~RunLoopWithExpectedCount() {} + + void Run(int expected_quit_calls) { + DCHECK_EQ(0, expected_quit_calls_); + DCHECK_EQ(0, actual_quit_calls_); + expected_quit_calls_ = expected_quit_calls; + run_loop_.reset(new base::RunLoop()); + run_loop_->Run(); + } + + void QuitIfConditionIsSatisified() { + if (++actual_quit_calls_ != expected_quit_calls_) + return; + run_loop_->Quit(); + expected_quit_calls_ = 0; + actual_quit_calls_ = 0; + } + + private: + scoped_ptr<base::RunLoop> run_loop_; + int expected_quit_calls_; + int actual_quit_calls_; + + DISALLOW_COPY_AND_ASSIGN(RunLoopWithExpectedCount); +}; + +// Test helper for BusTest.ListenForServiceOwnerChange. +void OnServiceOwnerChanged(RunLoopWithExpectedCount* run_loop_state, + std::string* service_owner, + int* num_of_owner_changes, + const std::string& new_service_owner) { + *service_owner = new_service_owner; + ++(*num_of_owner_changes); + run_loop_state->QuitIfConditionIsSatisified(); +} + } // namespace TEST(BusTest, GetObjectProxy) { @@ -296,3 +341,80 @@ TEST(BusTest, DoubleAddAndRemoveMatch) { bus->ShutdownAndBlock(); } + +TEST(BusTest, ListenForServiceOwnerChange) { + // Setup the current thread's MessageLoop. Must be of TYPE_IO for the + // listeners to work. + base::MessageLoop message_loop(base::MessageLoop::TYPE_IO); + RunLoopWithExpectedCount run_loop_state; + + // Create the bus. + dbus::Bus::Options bus_options; + scoped_refptr<dbus::Bus> bus = new dbus::Bus(bus_options); + + // Add a listener. + std::string service_owner1; + int num_of_owner_changes1 = 0; + dbus::Bus::GetServiceOwnerCallback callback1 = + base::Bind(&OnServiceOwnerChanged, + &run_loop_state, + &service_owner1, + &num_of_owner_changes1); + bus->ListenForServiceOwnerChange("org.chromium.TestService", callback1); + // This should be a no-op. + bus->ListenForServiceOwnerChange("org.chromium.TestService", callback1); + base::RunLoop().RunUntilIdle(); + + // Nothing has happened yet. Check initial state. + EXPECT_TRUE(service_owner1.empty()); + EXPECT_EQ(0, num_of_owner_changes1); + + // Make an ownership change. + ASSERT_TRUE(bus->RequestOwnershipAndBlock("org.chromium.TestService")); + run_loop_state.Run(1); + + { + // Get the current service owner and check to make sure the listener got + // the right value. + std::string current_service_owner = + bus->GetServiceOwnerAndBlock("org.chromium.TestService", + dbus::Bus::REPORT_ERRORS); + ASSERT_FALSE(current_service_owner.empty()); + + // Make sure the listener heard about the new owner. + EXPECT_EQ(current_service_owner, service_owner1); + + // Test the second ListenForServiceOwnerChange() above is indeed a no-op. + EXPECT_EQ(1, num_of_owner_changes1); + } + + // Add a second listener. + std::string service_owner2; + int num_of_owner_changes2 = 0; + dbus::Bus::GetServiceOwnerCallback callback2 = + base::Bind(&OnServiceOwnerChanged, + &run_loop_state, + &service_owner2, + &num_of_owner_changes2); + bus->ListenForServiceOwnerChange("org.chromium.TestService", callback2); + base::RunLoop().RunUntilIdle(); + + // Release the ownership and make sure the service owner listeners fire with + // the right values and the right number of times. + ASSERT_TRUE(bus->ReleaseOwnership("org.chromium.TestService")); + run_loop_state.Run(2); + + EXPECT_TRUE(service_owner1.empty()); + EXPECT_TRUE(service_owner2.empty()); + EXPECT_EQ(2, num_of_owner_changes1); + EXPECT_EQ(1, num_of_owner_changes2); + + // Unlisten so shutdown can proceed correctly. + bus->UnlistenForServiceOwnerChange("org.chromium.TestService", callback1); + bus->UnlistenForServiceOwnerChange("org.chromium.TestService", callback2); + base::RunLoop().RunUntilIdle(); + + // Shut down synchronously. + bus->ShutdownAndBlock(); + EXPECT_TRUE(bus->shutdown_completed()); +} |