Chromium Code Reviews| Index: dbus/object_manager_unittest.cc |
| diff --git a/dbus/object_manager_unittest.cc b/dbus/object_manager_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..53b4ca085c1602d055614885b1489c1308c2f8da |
| --- /dev/null |
| +++ b/dbus/object_manager_unittest.cc |
| @@ -0,0 +1,338 @@ |
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "dbus/object_manager.h" |
| + |
| +#include <string> |
| +#include <vector> |
| + |
| +#include "base/basictypes.h" |
| +#include "base/bind.h" |
| +#include "base/message_loop.h" |
| +#include "base/threading/thread.h" |
| +#include "base/threading/thread_restrictions.h" |
| +#include "dbus/bus.h" |
| +#include "dbus/object_path.h" |
| +#include "dbus/object_proxy.h" |
| +#include "dbus/property.h" |
| +#include "dbus/test_service.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +// The object manager test exercises the asynchronous APIs in ObjectManager, |
| +// and by extension PropertySet and Property<>. |
| +class ObjectManagerTest |
| + : public testing::Test, |
| + public dbus::ObjectManager::Interface { |
| + public: |
| + ObjectManagerTest() { |
| + } |
| + |
| + struct Properties : public dbus::PropertySet { |
| + dbus::Property<std::string> name; |
| + dbus::Property<int16> version; |
| + dbus::Property<std::vector<std::string> > methods; |
| + dbus::Property<std::vector<dbus::ObjectPath> > objects; |
| + |
| + Properties(dbus::ObjectProxy* object_proxy, |
| + const std::string& interface_name, |
| + PropertyChangedCallback property_changed_callback) |
| + : dbus::PropertySet(object_proxy, interface_name, |
| + property_changed_callback) { |
| + RegisterProperty("Name", &name); |
| + RegisterProperty("Version", &version); |
| + RegisterProperty("Methods", &methods); |
| + RegisterProperty("Objects", &objects); |
| + } |
| + }; |
| + |
| + virtual dbus::PropertySet* CreateProperties( |
| + dbus::ObjectProxy* object_proxy, |
| + const dbus::ObjectPath& object_path, |
| + const std::string& interface_name) OVERRIDE { |
| + Properties* properties = new Properties( |
| + object_proxy, interface_name, |
| + base::Bind(&ObjectManagerTest::OnPropertyChanged, |
| + base::Unretained(this), object_path)); |
| + return static_cast<dbus::PropertySet*>(properties); |
| + } |
| + |
| + virtual void SetUp() { |
| + // Make the main thread not to allow IO. |
| + base::ThreadRestrictions::SetIOAllowed(false); |
| + |
| + // Start the D-Bus thread. |
| + dbus_thread_.reset(new base::Thread("D-Bus Thread")); |
| + base::Thread::Options thread_options; |
| + thread_options.message_loop_type = MessageLoop::TYPE_IO; |
| + ASSERT_TRUE(dbus_thread_->StartWithOptions(thread_options)); |
| + |
| + // Start the test service, using the D-Bus thread. |
| + dbus::TestService::Options options; |
| + options.dbus_task_runner = dbus_thread_->message_loop_proxy(); |
| + test_service_.reset(new dbus::TestService(options)); |
| + ASSERT_TRUE(test_service_->StartService()); |
| + ASSERT_TRUE(test_service_->WaitUntilServiceIsStarted()); |
| + ASSERT_TRUE(test_service_->HasDBusThread()); |
| + |
| + // Create the client, using the D-Bus thread. |
| + dbus::Bus::Options bus_options; |
| + bus_options.bus_type = dbus::Bus::SESSION; |
| + bus_options.connection_type = dbus::Bus::PRIVATE; |
| + bus_options.dbus_task_runner = dbus_thread_->message_loop_proxy(); |
| + bus_ = new dbus::Bus(bus_options); |
| + ASSERT_TRUE(bus_->HasDBusThread()); |
| + |
| + object_manager_ = bus_->GetObjectManager( |
| + "org.chromium.TestService", |
| + dbus::ObjectPath("/org/chromium/TestService")); |
| + object_manager_->RegisterInterface("org.chromium.TestInterface", this); |
| + |
| + object_manager_->GetManagedObjects(); |
| + WaitForObject(); |
| + } |
| + |
| + virtual void TearDown() { |
| + bus_->ShutdownOnDBusThreadAndBlock(); |
| + |
| + // Shut down the service. |
| + test_service_->ShutdownAndBlock(); |
| + |
| + // Reset to the default. |
| + base::ThreadRestrictions::SetIOAllowed(true); |
| + |
| + // Stopping a thread is considered an IO operation, so do this after |
| + // allowing IO. |
| + test_service_->Stop(); |
| + } |
| + |
| + void MethodCallback(dbus::Response* response) { |
| + method_callback_called_ = true; |
| + message_loop_.Quit(); |
| + } |
| + |
| +protected: |
| + // Called when an object is added. |
| + void ObjectAdded(const dbus::ObjectPath& object_path, |
| + const std::string& interface_name) OVERRIDE { |
| + added_objects_.push_back(std::make_pair(object_path, interface_name)); |
| + message_loop_.Quit(); |
| + } |
| + |
| + // Called when an object is removed. |
| + void ObjectRemoved(const dbus::ObjectPath& object_path, |
| + const std::string& interface_name) OVERRIDE { |
| + removed_objects_.push_back(std::make_pair(object_path, interface_name)); |
| + message_loop_.Quit(); |
| + } |
| + |
| + // Called when a property value is updated. |
| + void OnPropertyChanged(const dbus::ObjectPath& object_path, |
| + const std::string& name) OVERRIDE { |
| + updated_properties_.push_back(name); |
| + message_loop_.Quit(); |
| + } |
| + |
| + static const size_t kExpectedObjects = 1; |
| + static const size_t kExpectedProperties = 4; |
| + |
| + void WaitForObject() { |
| + while (added_objects_.size() < kExpectedObjects || |
| + updated_properties_.size() < kExpectedProperties) |
| + message_loop_.Run(); |
| + for (size_t i = 0; i < kExpectedObjects; ++i) |
| + added_objects_.erase(added_objects_.begin()); |
| + for (size_t i = 0; i < kExpectedProperties; ++i) |
| + updated_properties_.erase(updated_properties_.begin()); |
| + } |
| + |
| + void WaitForRemoveObject() { |
| + while (removed_objects_.size() < kExpectedObjects) |
| + message_loop_.Run(); |
| + for (size_t i = 0; i < kExpectedObjects; ++i) |
| + removed_objects_.erase(removed_objects_.begin()); |
| + } |
| + |
| + void WaitForMethodCallback() { |
| + message_loop_.Run(); |
| + method_callback_called_ = false; |
| + } |
| + |
| + void PerformAction(const std::string& action, |
| + const dbus::ObjectPath& object_path) { |
| + dbus::ObjectProxy* object_proxy = bus_->GetObjectProxy( |
| + "org.chromium.TestService", |
| + dbus::ObjectPath("/org/chromium/TestObject")); |
| + |
| + dbus::MethodCall method_call("org.chromium.TestInterface", "PerformAction"); |
| + dbus::MessageWriter writer(&method_call); |
| + writer.AppendString(action); |
| + writer.AppendObjectPath(object_path); |
| + |
| + object_proxy->CallMethod(&method_call, |
| + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| + base::Bind(&ObjectManagerTest::MethodCallback, |
| + base::Unretained(this))); |
| + WaitForMethodCallback(); |
| + } |
| + |
| + MessageLoop message_loop_; |
| + scoped_ptr<base::Thread> dbus_thread_; |
| + scoped_refptr<dbus::Bus> bus_; |
| + dbus::ObjectManager* object_manager_; |
| + scoped_ptr<dbus::TestService> test_service_; |
| + |
| + std::vector<std::pair<dbus::ObjectPath, std::string> > added_objects_; |
| + std::vector<std::pair<dbus::ObjectPath, std::string> > removed_objects_; |
| + std::vector<std::string> updated_properties_; |
| + |
| + bool method_callback_called_; |
| +}; |
| + |
| + |
| +TEST_F(ObjectManagerTest, InitialObject) { |
| + dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy( |
| + dbus::ObjectPath("/org/chromium/TestObject")); |
| + EXPECT_TRUE(object_proxy != NULL); |
|
satorux1
2013/03/21 05:45:43
I think EXPECT_TRUE(object_proxy) should compile
keybuk
2013/03/21 17:50:00
One or the other of these doesn't compile, because
satorux1
2013/03/22 01:41:33
Ah I see.
|
| + |
| + Properties* properties = static_cast<Properties*>( |
| + object_manager_->GetProperties( |
| + dbus::ObjectPath("/org/chromium/TestObject"), |
| + "org.chromium.TestInterface")); |
| + EXPECT_TRUE(properties != NULL); |
| + |
| + EXPECT_EQ("TestService", properties->name.value()); |
| + EXPECT_EQ(10, properties->version.value()); |
| + |
| + std::vector<std::string> methods = properties->methods.value(); |
| + ASSERT_EQ(4U, methods.size()); |
| + EXPECT_EQ("Echo", methods[0]); |
| + EXPECT_EQ("SlowEcho", methods[1]); |
| + EXPECT_EQ("AsyncEcho", methods[2]); |
| + EXPECT_EQ("BrokenMethod", methods[3]); |
| + |
| + std::vector<dbus::ObjectPath> objects = properties->objects.value(); |
| + ASSERT_EQ(1U, objects.size()); |
| + EXPECT_EQ(dbus::ObjectPath("/TestObjectPath"), objects[0]); |
| +} |
| + |
| +TEST_F(ObjectManagerTest, UnknownObjectProxy) { |
| + dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy( |
| + dbus::ObjectPath("/org/chromium/UnknownObject")); |
| + EXPECT_TRUE(object_proxy == NULL); |
|
satorux1
2013/03/21 05:45:43
EXPECT_FALSE(object_proxy) ?
keybuk
2013/03/21 17:50:00
See above.
|
| +} |
| + |
| +TEST_F(ObjectManagerTest, UnknownObjectProperties) { |
| + Properties* properties = static_cast<Properties*>( |
| + object_manager_->GetProperties( |
| + dbus::ObjectPath("/org/chromium/UnknownObject"), |
| + "org.chromium.TestInterface")); |
| + EXPECT_TRUE(properties == NULL); |
| +} |
| + |
| +TEST_F(ObjectManagerTest, UnknownInterfaceProperties) { |
| + Properties* properties = static_cast<Properties*>( |
| + object_manager_->GetProperties( |
| + dbus::ObjectPath("/org/chromium/TestObject"), |
| + "org.chromium.UnknownService")); |
| + EXPECT_TRUE(properties == NULL); |
| +} |
| + |
| +TEST_F(ObjectManagerTest, GetObjects) { |
| + std::vector<dbus::ObjectPath> object_paths = object_manager_->GetObjects(); |
| + ASSERT_EQ(1U, object_paths.size()); |
| + EXPECT_EQ(dbus::ObjectPath("/org/chromium/TestObject"), object_paths[0]); |
| +} |
| + |
| +TEST_F(ObjectManagerTest, GetObjectsWithInterface) { |
| + std::vector<dbus::ObjectPath> object_paths = |
| + object_manager_->GetObjectsWithInterface("org.chromium.TestInterface"); |
| + ASSERT_EQ(1U, object_paths.size()); |
| + EXPECT_EQ(dbus::ObjectPath("/org/chromium/TestObject"), object_paths[0]); |
| +} |
| + |
| +TEST_F(ObjectManagerTest, GetObjectsWithUnknownInterface) { |
| + std::vector<dbus::ObjectPath> object_paths = |
| + object_manager_->GetObjectsWithInterface("org.chromium.UnknownService"); |
| + EXPECT_EQ(0U, object_paths.size()); |
| +} |
| + |
| +TEST_F(ObjectManagerTest, SameObject) { |
| + dbus::ObjectManager* object_manager = bus_->GetObjectManager( |
| + "org.chromium.TestService", |
| + dbus::ObjectPath("/org/chromium/TestService")); |
| + EXPECT_EQ(object_manager_, object_manager); |
| +} |
| + |
| +TEST_F(ObjectManagerTest, DifferentObjectForService) { |
| + dbus::ObjectManager* object_manager = bus_->GetObjectManager( |
| + "org.chromium.DifferentService", |
| + dbus::ObjectPath("/org/chromium/TestService")); |
| + EXPECT_NE(object_manager_, object_manager); |
| +} |
| + |
| +TEST_F(ObjectManagerTest, DifferentObjectForPath) { |
| + dbus::ObjectManager* object_manager = bus_->GetObjectManager( |
| + "org.chromium.TestService", |
| + dbus::ObjectPath("/org/chromium/DifferentService")); |
| + EXPECT_NE(object_manager_, object_manager); |
| +} |
| + |
| +TEST_F(ObjectManagerTest, SecondObject) { |
| + PerformAction("AddObject", dbus::ObjectPath("/org/chromium/SecondObject")); |
| + WaitForObject(); |
| + |
| + dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy( |
| + dbus::ObjectPath("/org/chromium/SecondObject")); |
| + EXPECT_TRUE(object_proxy != NULL); |
| + |
| + Properties* properties = static_cast<Properties*>( |
| + object_manager_->GetProperties( |
| + dbus::ObjectPath("/org/chromium/SecondObject"), |
| + "org.chromium.TestInterface")); |
| + EXPECT_TRUE(properties != NULL); |
| + |
| + std::vector<dbus::ObjectPath> object_paths = object_manager_->GetObjects(); |
|
satorux1
2013/03/21 05:45:43
ASSERT_EQ(2U, object_paths.size()) ?
keybuk
2013/03/21 17:50:00
Done.
|
| + for (std::vector<dbus::ObjectPath>::iterator iter = object_paths.begin(); |
| + iter != object_paths.end(); ++iter) |
| + EXPECT_TRUE(*iter == dbus::ObjectPath("/org/chromium/TestObject") || |
| + *iter == dbus::ObjectPath("/org/chromium/SecondObject")); |
|
satorux1
2013/03/21 05:45:43
What about making object paths sortable and do:
s
keybuk
2013/03/21 17:50:00
Done.
|
| + |
| + object_paths = |
| + object_manager_->GetObjectsWithInterface("org.chromium.TestInterface"); |
| + ASSERT_EQ(2U, object_paths.size()); |
| + for (std::vector<dbus::ObjectPath>::iterator iter = object_paths.begin(); |
| + iter != object_paths.end(); ++iter) |
| + EXPECT_TRUE(*iter == dbus::ObjectPath("/org/chromium/TestObject") || |
| + *iter == dbus::ObjectPath("/org/chromium/SecondObject")); |
|
satorux1
2013/03/21 05:45:43
ditto.
keybuk
2013/03/21 17:50:00
Done.
|
| +} |
| + |
| +TEST_F(ObjectManagerTest, RemoveSecondObject) { |
| + PerformAction("AddObject", dbus::ObjectPath("/org/chromium/SecondObject")); |
| + WaitForObject(); |
| + |
| + std::vector<dbus::ObjectPath> object_paths = object_manager_->GetObjects(); |
| + ASSERT_EQ(2U, object_paths.size()); |
| + |
| + PerformAction("RemoveObject", dbus::ObjectPath("/org/chromium/SecondObject")); |
| + WaitForRemoveObject(); |
| + |
| + dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy( |
| + dbus::ObjectPath("/org/chromium/SecondObject")); |
| + EXPECT_TRUE(object_proxy == NULL); |
| + |
| + Properties* properties = static_cast<Properties*>( |
| + object_manager_->GetProperties( |
| + dbus::ObjectPath("/org/chromium/SecondObject"), |
| + "org.chromium.TestInterface")); |
| + EXPECT_TRUE(properties == NULL); |
| + |
| + object_paths = object_manager_->GetObjects(); |
| + ASSERT_EQ(1U, object_paths.size()); |
| + EXPECT_EQ(dbus::ObjectPath("/org/chromium/TestObject"), object_paths[0]); |
| + |
| + object_paths = |
| + object_manager_->GetObjectsWithInterface("org.chromium.TestInterface"); |
| + ASSERT_EQ(1U, object_paths.size()); |
| + EXPECT_EQ(dbus::ObjectPath("/org/chromium/TestObject"), object_paths[0]); |
| +} |