Home | History | Annotate | Download | only in dbus
      1 // Copyright (c) 2013 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.
      4 
      5 #include "dbus/object_manager.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/bind.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/threading/thread.h"
     14 #include "base/threading/thread_restrictions.h"
     15 #include "dbus/bus.h"
     16 #include "dbus/object_path.h"
     17 #include "dbus/object_proxy.h"
     18 #include "dbus/property.h"
     19 #include "dbus/test_service.h"
     20 #include "testing/gtest/include/gtest/gtest.h"
     21 
     22 namespace dbus {
     23 
     24 // The object manager test exercises the asynchronous APIs in ObjectManager,
     25 // and by extension PropertySet and Property<>.
     26 class ObjectManagerTest
     27     : public testing::Test,
     28       public ObjectManager::Interface {
     29  public:
     30   ObjectManagerTest() {
     31   }
     32 
     33   struct Properties : public PropertySet {
     34     Property<std::string> name;
     35     Property<int16> version;
     36     Property<std::vector<std::string> > methods;
     37     Property<std::vector<ObjectPath> > objects;
     38 
     39     Properties(ObjectProxy* object_proxy,
     40                const std::string& interface_name,
     41                PropertyChangedCallback property_changed_callback)
     42         : PropertySet(object_proxy, interface_name, property_changed_callback) {
     43       RegisterProperty("Name", &name);
     44       RegisterProperty("Version", &version);
     45       RegisterProperty("Methods", &methods);
     46       RegisterProperty("Objects", &objects);
     47     }
     48   };
     49 
     50   virtual PropertySet* CreateProperties(
     51       ObjectProxy* object_proxy,
     52       const ObjectPath& object_path,
     53       const std::string& interface_name) OVERRIDE {
     54     Properties* properties = new Properties(
     55         object_proxy, interface_name,
     56         base::Bind(&ObjectManagerTest::OnPropertyChanged,
     57                    base::Unretained(this), object_path));
     58     return static_cast<PropertySet*>(properties);
     59   }
     60 
     61   virtual void SetUp() {
     62     // Make the main thread not to allow IO.
     63     base::ThreadRestrictions::SetIOAllowed(false);
     64 
     65     // Start the D-Bus thread.
     66     dbus_thread_.reset(new base::Thread("D-Bus Thread"));
     67     base::Thread::Options thread_options;
     68     thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
     69     ASSERT_TRUE(dbus_thread_->StartWithOptions(thread_options));
     70 
     71     // Start the test service, using the D-Bus thread.
     72     TestService::Options options;
     73     options.dbus_task_runner = dbus_thread_->message_loop_proxy();
     74     test_service_.reset(new TestService(options));
     75     ASSERT_TRUE(test_service_->StartService());
     76     ASSERT_TRUE(test_service_->WaitUntilServiceIsStarted());
     77     ASSERT_TRUE(test_service_->HasDBusThread());
     78 
     79     // Create the client, using the D-Bus thread.
     80     Bus::Options bus_options;
     81     bus_options.bus_type = Bus::SESSION;
     82     bus_options.connection_type = Bus::PRIVATE;
     83     bus_options.dbus_task_runner = dbus_thread_->message_loop_proxy();
     84     bus_ = new Bus(bus_options);
     85     ASSERT_TRUE(bus_->HasDBusThread());
     86 
     87     object_manager_ = bus_->GetObjectManager(
     88         "org.chromium.TestService",
     89         ObjectPath("/org/chromium/TestService"));
     90     object_manager_->RegisterInterface("org.chromium.TestInterface", this);
     91 
     92     object_manager_->GetManagedObjects();
     93     WaitForObject();
     94   }
     95 
     96   virtual void TearDown() {
     97     bus_->ShutdownOnDBusThreadAndBlock();
     98 
     99     // Shut down the service.
    100     test_service_->ShutdownAndBlock();
    101 
    102     // Reset to the default.
    103     base::ThreadRestrictions::SetIOAllowed(true);
    104 
    105     // Stopping a thread is considered an IO operation, so do this after
    106     // allowing IO.
    107     test_service_->Stop();
    108   }
    109 
    110   void MethodCallback(Response* response) {
    111     method_callback_called_ = true;
    112     message_loop_.Quit();
    113   }
    114 
    115  protected:
    116   // Called when an object is added.
    117   virtual void ObjectAdded(const ObjectPath& object_path,
    118                            const std::string& interface_name) OVERRIDE {
    119     added_objects_.push_back(std::make_pair(object_path, interface_name));
    120     message_loop_.Quit();
    121   }
    122 
    123   // Called when an object is removed.
    124   virtual void ObjectRemoved(const ObjectPath& object_path,
    125                              const std::string& interface_name) OVERRIDE {
    126     removed_objects_.push_back(std::make_pair(object_path, interface_name));
    127     message_loop_.Quit();
    128   }
    129 
    130   // Called when a property value is updated.
    131   void OnPropertyChanged(const ObjectPath& object_path,
    132                          const std::string& name) {
    133     updated_properties_.push_back(name);
    134     message_loop_.Quit();
    135   }
    136 
    137   static const size_t kExpectedObjects = 1;
    138   static const size_t kExpectedProperties = 4;
    139 
    140   void WaitForObject() {
    141     while (added_objects_.size() < kExpectedObjects ||
    142            updated_properties_.size() < kExpectedProperties)
    143       message_loop_.Run();
    144     for (size_t i = 0; i < kExpectedObjects; ++i)
    145       added_objects_.erase(added_objects_.begin());
    146     for (size_t i = 0; i < kExpectedProperties; ++i)
    147       updated_properties_.erase(updated_properties_.begin());
    148   }
    149 
    150   void WaitForRemoveObject() {
    151     while (removed_objects_.size() < kExpectedObjects)
    152       message_loop_.Run();
    153     for (size_t i = 0; i < kExpectedObjects; ++i)
    154       removed_objects_.erase(removed_objects_.begin());
    155   }
    156 
    157   void WaitForMethodCallback() {
    158     message_loop_.Run();
    159     method_callback_called_ = false;
    160   }
    161 
    162   void PerformAction(const std::string& action, const ObjectPath& object_path) {
    163     ObjectProxy* object_proxy = bus_->GetObjectProxy(
    164         "org.chromium.TestService",
    165         ObjectPath("/org/chromium/TestObject"));
    166 
    167     MethodCall method_call("org.chromium.TestInterface", "PerformAction");
    168     MessageWriter writer(&method_call);
    169     writer.AppendString(action);
    170     writer.AppendObjectPath(object_path);
    171 
    172     object_proxy->CallMethod(&method_call,
    173                              ObjectProxy::TIMEOUT_USE_DEFAULT,
    174                              base::Bind(&ObjectManagerTest::MethodCallback,
    175                                         base::Unretained(this)));
    176     WaitForMethodCallback();
    177   }
    178 
    179   base::MessageLoop message_loop_;
    180   scoped_ptr<base::Thread> dbus_thread_;
    181   scoped_refptr<Bus> bus_;
    182   ObjectManager* object_manager_;
    183   scoped_ptr<TestService> test_service_;
    184 
    185   std::vector<std::pair<ObjectPath, std::string> > added_objects_;
    186   std::vector<std::pair<ObjectPath, std::string> > removed_objects_;
    187   std::vector<std::string> updated_properties_;
    188 
    189   bool method_callback_called_;
    190 };
    191 
    192 
    193 TEST_F(ObjectManagerTest, InitialObject) {
    194   ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
    195       ObjectPath("/org/chromium/TestObject"));
    196   EXPECT_TRUE(object_proxy != NULL);
    197 
    198   Properties* properties = static_cast<Properties*>(
    199       object_manager_->GetProperties(ObjectPath("/org/chromium/TestObject"),
    200                                      "org.chromium.TestInterface"));
    201   EXPECT_TRUE(properties != NULL);
    202 
    203   EXPECT_EQ("TestService", properties->name.value());
    204   EXPECT_EQ(10, properties->version.value());
    205 
    206   std::vector<std::string> methods = properties->methods.value();
    207   ASSERT_EQ(4U, methods.size());
    208   EXPECT_EQ("Echo", methods[0]);
    209   EXPECT_EQ("SlowEcho", methods[1]);
    210   EXPECT_EQ("AsyncEcho", methods[2]);
    211   EXPECT_EQ("BrokenMethod", methods[3]);
    212 
    213   std::vector<ObjectPath> objects = properties->objects.value();
    214   ASSERT_EQ(1U, objects.size());
    215   EXPECT_EQ(ObjectPath("/TestObjectPath"), objects[0]);
    216 }
    217 
    218 TEST_F(ObjectManagerTest, UnknownObjectProxy) {
    219   ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
    220       ObjectPath("/org/chromium/UnknownObject"));
    221   EXPECT_TRUE(object_proxy == NULL);
    222 }
    223 
    224 TEST_F(ObjectManagerTest, UnknownObjectProperties) {
    225   Properties* properties = static_cast<Properties*>(
    226       object_manager_->GetProperties(ObjectPath("/org/chromium/UnknownObject"),
    227                                      "org.chromium.TestInterface"));
    228   EXPECT_TRUE(properties == NULL);
    229 }
    230 
    231 TEST_F(ObjectManagerTest, UnknownInterfaceProperties) {
    232   Properties* properties = static_cast<Properties*>(
    233       object_manager_->GetProperties(ObjectPath("/org/chromium/TestObject"),
    234                                      "org.chromium.UnknownService"));
    235   EXPECT_TRUE(properties == NULL);
    236 }
    237 
    238 TEST_F(ObjectManagerTest, GetObjects) {
    239   std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
    240   ASSERT_EQ(1U, object_paths.size());
    241   EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
    242 }
    243 
    244 TEST_F(ObjectManagerTest, GetObjectsWithInterface) {
    245   std::vector<ObjectPath> object_paths =
    246       object_manager_->GetObjectsWithInterface("org.chromium.TestInterface");
    247   ASSERT_EQ(1U, object_paths.size());
    248   EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
    249 }
    250 
    251 TEST_F(ObjectManagerTest, GetObjectsWithUnknownInterface) {
    252   std::vector<ObjectPath> object_paths =
    253       object_manager_->GetObjectsWithInterface("org.chromium.UnknownService");
    254   EXPECT_EQ(0U, object_paths.size());
    255 }
    256 
    257 TEST_F(ObjectManagerTest, SameObject) {
    258   ObjectManager* object_manager = bus_->GetObjectManager(
    259       "org.chromium.TestService",
    260       ObjectPath("/org/chromium/TestService"));
    261   EXPECT_EQ(object_manager_, object_manager);
    262 }
    263 
    264 TEST_F(ObjectManagerTest, DifferentObjectForService) {
    265   ObjectManager* object_manager = bus_->GetObjectManager(
    266       "org.chromium.DifferentService",
    267       ObjectPath("/org/chromium/TestService"));
    268   EXPECT_NE(object_manager_, object_manager);
    269 }
    270 
    271 TEST_F(ObjectManagerTest, DifferentObjectForPath) {
    272   ObjectManager* object_manager = bus_->GetObjectManager(
    273       "org.chromium.TestService",
    274       ObjectPath("/org/chromium/DifferentService"));
    275   EXPECT_NE(object_manager_, object_manager);
    276 }
    277 
    278 TEST_F(ObjectManagerTest, SecondObject) {
    279   PerformAction("AddObject", ObjectPath("/org/chromium/SecondObject"));
    280   WaitForObject();
    281 
    282   ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
    283       ObjectPath("/org/chromium/SecondObject"));
    284   EXPECT_TRUE(object_proxy != NULL);
    285 
    286   Properties* properties = static_cast<Properties*>(
    287       object_manager_->GetProperties(ObjectPath("/org/chromium/SecondObject"),
    288                                      "org.chromium.TestInterface"));
    289   EXPECT_TRUE(properties != NULL);
    290 
    291   std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
    292   ASSERT_EQ(2U, object_paths.size());
    293 
    294   std::sort(object_paths.begin(), object_paths.end());
    295   EXPECT_EQ(ObjectPath("/org/chromium/SecondObject"), object_paths[0]);
    296   EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[1]);
    297 
    298   object_paths =
    299       object_manager_->GetObjectsWithInterface("org.chromium.TestInterface");
    300   ASSERT_EQ(2U, object_paths.size());
    301 
    302   std::sort(object_paths.begin(), object_paths.end());
    303   EXPECT_EQ(ObjectPath("/org/chromium/SecondObject"), object_paths[0]);
    304   EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[1]);
    305 }
    306 
    307 TEST_F(ObjectManagerTest, RemoveSecondObject) {
    308   PerformAction("AddObject", ObjectPath("/org/chromium/SecondObject"));
    309   WaitForObject();
    310 
    311   std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
    312   ASSERT_EQ(2U, object_paths.size());
    313 
    314   PerformAction("RemoveObject", ObjectPath("/org/chromium/SecondObject"));
    315   WaitForRemoveObject();
    316 
    317   ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
    318       ObjectPath("/org/chromium/SecondObject"));
    319   EXPECT_TRUE(object_proxy == NULL);
    320 
    321   Properties* properties = static_cast<Properties*>(
    322       object_manager_->GetProperties(ObjectPath("/org/chromium/SecondObject"),
    323                                      "org.chromium.TestInterface"));
    324   EXPECT_TRUE(properties == NULL);
    325 
    326   object_paths = object_manager_->GetObjects();
    327   ASSERT_EQ(1U, object_paths.size());
    328   EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
    329 
    330   object_paths =
    331       object_manager_->GetObjectsWithInterface("org.chromium.TestInterface");
    332   ASSERT_EQ(1U, object_paths.size());
    333   EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
    334 }
    335 
    336 }  // namespace dbus
    337