<As promised in a previous CL.>
[chromium-blink-merge.git] / dbus / object_manager_unittest.cc
blobcd02c5e13c16ac96a2753900cbfeaf948e507145
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.
5 #include "dbus/object_manager.h"
7 #include <string>
8 #include <vector>
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h"
14 #include "base/threading/thread.h"
15 #include "base/threading/thread_restrictions.h"
16 #include "dbus/bus.h"
17 #include "dbus/object_path.h"
18 #include "dbus/object_proxy.h"
19 #include "dbus/property.h"
20 #include "dbus/test_service.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 namespace dbus {
25 // The object manager test exercises the asynchronous APIs in ObjectManager,
26 // and by extension PropertySet and Property<>.
27 class ObjectManagerTest
28 : public testing::Test,
29 public ObjectManager::Interface {
30 public:
31 ObjectManagerTest() : timeout_expired_(false) {
34 struct Properties : public PropertySet {
35 Property<std::string> name;
36 Property<int16> version;
37 Property<std::vector<std::string> > methods;
38 Property<std::vector<ObjectPath> > objects;
40 Properties(ObjectProxy* object_proxy,
41 const std::string& interface_name,
42 PropertyChangedCallback property_changed_callback)
43 : PropertySet(object_proxy, interface_name, property_changed_callback) {
44 RegisterProperty("Name", &name);
45 RegisterProperty("Version", &version);
46 RegisterProperty("Methods", &methods);
47 RegisterProperty("Objects", &objects);
51 virtual PropertySet* CreateProperties(
52 ObjectProxy* object_proxy,
53 const ObjectPath& object_path,
54 const std::string& interface_name) override {
55 Properties* properties = new Properties(
56 object_proxy, interface_name,
57 base::Bind(&ObjectManagerTest::OnPropertyChanged,
58 base::Unretained(this), object_path));
59 return static_cast<PropertySet*>(properties);
62 virtual void SetUp() {
63 // Make the main thread not to allow IO.
64 base::ThreadRestrictions::SetIOAllowed(false);
66 // Start the D-Bus thread.
67 dbus_thread_.reset(new base::Thread("D-Bus Thread"));
68 base::Thread::Options thread_options;
69 thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
70 ASSERT_TRUE(dbus_thread_->StartWithOptions(thread_options));
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());
80 // Create the client, using the D-Bus thread.
81 Bus::Options bus_options;
82 bus_options.bus_type = Bus::SESSION;
83 bus_options.connection_type = Bus::PRIVATE;
84 bus_options.dbus_task_runner = dbus_thread_->message_loop_proxy();
85 bus_ = new Bus(bus_options);
86 ASSERT_TRUE(bus_->HasDBusThread());
88 object_manager_ = bus_->GetObjectManager(
89 "org.chromium.TestService",
90 ObjectPath("/org/chromium/TestService"));
91 object_manager_->RegisterInterface("org.chromium.TestInterface", this);
93 WaitForObject();
96 virtual void TearDown() {
97 bus_->ShutdownOnDBusThreadAndBlock();
99 // Shut down the service.
100 test_service_->ShutdownAndBlock();
102 // Reset to the default.
103 base::ThreadRestrictions::SetIOAllowed(true);
105 // Stopping a thread is considered an IO operation, so do this after
106 // allowing IO.
107 test_service_->Stop();
109 base::RunLoop().RunUntilIdle();
112 void MethodCallback(Response* response) {
113 method_callback_called_ = true;
114 run_loop_->Quit();
117 // Called from the PropertiesChangedAsObjectsReceived test case. The test will
118 // not run the message loop if it receives the expected PropertiesChanged
119 // signal before the timeout. This method immediately fails the test.
120 void PropertiesChangedTestTimeout() {
121 timeout_expired_ = true;
122 run_loop_->Quit();
124 FAIL() << "Never received PropertiesChanged";
127 protected:
128 // Called when an object is added.
129 virtual void ObjectAdded(const ObjectPath& object_path,
130 const std::string& interface_name) override {
131 added_objects_.push_back(std::make_pair(object_path, interface_name));
132 run_loop_->Quit();
135 // Called when an object is removed.
136 virtual void ObjectRemoved(const ObjectPath& object_path,
137 const std::string& interface_name) override {
138 removed_objects_.push_back(std::make_pair(object_path, interface_name));
139 run_loop_->Quit();
142 // Called when a property value is updated.
143 void OnPropertyChanged(const ObjectPath& object_path,
144 const std::string& name) {
145 // Store the value of the "Name" property if that's the one that
146 // changed.
147 Properties* properties = static_cast<Properties*>(
148 object_manager_->GetProperties(
149 object_path,
150 "org.chromium.TestInterface"));
151 if (name == properties->name.name())
152 last_name_value_ = properties->name.value();
154 // Store the updated property.
155 updated_properties_.push_back(name);
156 run_loop_->Quit();
159 static const size_t kExpectedObjects = 1;
160 static const size_t kExpectedProperties = 4;
162 void WaitForObject() {
163 while (added_objects_.size() < kExpectedObjects ||
164 updated_properties_.size() < kExpectedProperties) {
165 run_loop_.reset(new base::RunLoop);
166 run_loop_->Run();
168 for (size_t i = 0; i < kExpectedObjects; ++i)
169 added_objects_.erase(added_objects_.begin());
170 for (size_t i = 0; i < kExpectedProperties; ++i)
171 updated_properties_.erase(updated_properties_.begin());
174 void WaitForRemoveObject() {
175 while (removed_objects_.size() < kExpectedObjects) {
176 run_loop_.reset(new base::RunLoop);
177 run_loop_->Run();
179 for (size_t i = 0; i < kExpectedObjects; ++i)
180 removed_objects_.erase(removed_objects_.begin());
183 void WaitForMethodCallback() {
184 run_loop_.reset(new base::RunLoop);
185 run_loop_->Run();
186 method_callback_called_ = false;
189 void PerformAction(const std::string& action, const ObjectPath& object_path) {
190 ObjectProxy* object_proxy = bus_->GetObjectProxy(
191 "org.chromium.TestService",
192 ObjectPath("/org/chromium/TestObject"));
194 MethodCall method_call("org.chromium.TestInterface", "PerformAction");
195 MessageWriter writer(&method_call);
196 writer.AppendString(action);
197 writer.AppendObjectPath(object_path);
199 object_proxy->CallMethod(&method_call,
200 ObjectProxy::TIMEOUT_USE_DEFAULT,
201 base::Bind(&ObjectManagerTest::MethodCallback,
202 base::Unretained(this)));
203 WaitForMethodCallback();
206 base::MessageLoop message_loop_;
207 scoped_ptr<base::RunLoop> run_loop_;
208 scoped_ptr<base::Thread> dbus_thread_;
209 scoped_refptr<Bus> bus_;
210 ObjectManager* object_manager_;
211 scoped_ptr<TestService> test_service_;
213 std::string last_name_value_;
214 bool timeout_expired_;
216 std::vector<std::pair<ObjectPath, std::string> > added_objects_;
217 std::vector<std::pair<ObjectPath, std::string> > removed_objects_;
218 std::vector<std::string> updated_properties_;
220 bool method_callback_called_;
224 TEST_F(ObjectManagerTest, InitialObject) {
225 ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
226 ObjectPath("/org/chromium/TestObject"));
227 EXPECT_TRUE(object_proxy != NULL);
229 Properties* properties = static_cast<Properties*>(
230 object_manager_->GetProperties(ObjectPath("/org/chromium/TestObject"),
231 "org.chromium.TestInterface"));
232 EXPECT_TRUE(properties != NULL);
234 EXPECT_EQ("TestService", properties->name.value());
235 EXPECT_EQ(10, properties->version.value());
237 std::vector<std::string> methods = properties->methods.value();
238 ASSERT_EQ(4U, methods.size());
239 EXPECT_EQ("Echo", methods[0]);
240 EXPECT_EQ("SlowEcho", methods[1]);
241 EXPECT_EQ("AsyncEcho", methods[2]);
242 EXPECT_EQ("BrokenMethod", methods[3]);
244 std::vector<ObjectPath> objects = properties->objects.value();
245 ASSERT_EQ(1U, objects.size());
246 EXPECT_EQ(ObjectPath("/TestObjectPath"), objects[0]);
249 TEST_F(ObjectManagerTest, UnknownObjectProxy) {
250 ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
251 ObjectPath("/org/chromium/UnknownObject"));
252 EXPECT_TRUE(object_proxy == NULL);
255 TEST_F(ObjectManagerTest, UnknownObjectProperties) {
256 Properties* properties = static_cast<Properties*>(
257 object_manager_->GetProperties(ObjectPath("/org/chromium/UnknownObject"),
258 "org.chromium.TestInterface"));
259 EXPECT_TRUE(properties == NULL);
262 TEST_F(ObjectManagerTest, UnknownInterfaceProperties) {
263 Properties* properties = static_cast<Properties*>(
264 object_manager_->GetProperties(ObjectPath("/org/chromium/TestObject"),
265 "org.chromium.UnknownService"));
266 EXPECT_TRUE(properties == NULL);
269 TEST_F(ObjectManagerTest, GetObjects) {
270 std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
271 ASSERT_EQ(1U, object_paths.size());
272 EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
275 TEST_F(ObjectManagerTest, GetObjectsWithInterface) {
276 std::vector<ObjectPath> object_paths =
277 object_manager_->GetObjectsWithInterface("org.chromium.TestInterface");
278 ASSERT_EQ(1U, object_paths.size());
279 EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
282 TEST_F(ObjectManagerTest, GetObjectsWithUnknownInterface) {
283 std::vector<ObjectPath> object_paths =
284 object_manager_->GetObjectsWithInterface("org.chromium.UnknownService");
285 EXPECT_EQ(0U, object_paths.size());
288 TEST_F(ObjectManagerTest, SameObject) {
289 ObjectManager* object_manager = bus_->GetObjectManager(
290 "org.chromium.TestService",
291 ObjectPath("/org/chromium/TestService"));
292 EXPECT_EQ(object_manager_, object_manager);
295 TEST_F(ObjectManagerTest, DifferentObjectForService) {
296 ObjectManager* object_manager = bus_->GetObjectManager(
297 "org.chromium.DifferentService",
298 ObjectPath("/org/chromium/TestService"));
299 EXPECT_NE(object_manager_, object_manager);
302 TEST_F(ObjectManagerTest, DifferentObjectForPath) {
303 ObjectManager* object_manager = bus_->GetObjectManager(
304 "org.chromium.TestService",
305 ObjectPath("/org/chromium/DifferentService"));
306 EXPECT_NE(object_manager_, object_manager);
309 TEST_F(ObjectManagerTest, SecondObject) {
310 PerformAction("AddObject", ObjectPath("/org/chromium/SecondObject"));
311 WaitForObject();
313 ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
314 ObjectPath("/org/chromium/SecondObject"));
315 EXPECT_TRUE(object_proxy != NULL);
317 Properties* properties = static_cast<Properties*>(
318 object_manager_->GetProperties(ObjectPath("/org/chromium/SecondObject"),
319 "org.chromium.TestInterface"));
320 EXPECT_TRUE(properties != NULL);
322 std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
323 ASSERT_EQ(2U, object_paths.size());
325 std::sort(object_paths.begin(), object_paths.end());
326 EXPECT_EQ(ObjectPath("/org/chromium/SecondObject"), object_paths[0]);
327 EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[1]);
329 object_paths =
330 object_manager_->GetObjectsWithInterface("org.chromium.TestInterface");
331 ASSERT_EQ(2U, object_paths.size());
333 std::sort(object_paths.begin(), object_paths.end());
334 EXPECT_EQ(ObjectPath("/org/chromium/SecondObject"), object_paths[0]);
335 EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[1]);
338 TEST_F(ObjectManagerTest, RemoveSecondObject) {
339 PerformAction("AddObject", ObjectPath("/org/chromium/SecondObject"));
340 WaitForObject();
342 std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
343 ASSERT_EQ(2U, object_paths.size());
345 PerformAction("RemoveObject", ObjectPath("/org/chromium/SecondObject"));
346 WaitForRemoveObject();
348 ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
349 ObjectPath("/org/chromium/SecondObject"));
350 EXPECT_TRUE(object_proxy == NULL);
352 Properties* properties = static_cast<Properties*>(
353 object_manager_->GetProperties(ObjectPath("/org/chromium/SecondObject"),
354 "org.chromium.TestInterface"));
355 EXPECT_TRUE(properties == NULL);
357 object_paths = object_manager_->GetObjects();
358 ASSERT_EQ(1U, object_paths.size());
359 EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
361 object_paths =
362 object_manager_->GetObjectsWithInterface("org.chromium.TestInterface");
363 ASSERT_EQ(1U, object_paths.size());
364 EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
367 TEST_F(ObjectManagerTest, OwnershipLost) {
368 PerformAction("ReleaseOwnership", ObjectPath("/org/chromium/TestService"));
369 WaitForRemoveObject();
371 std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
372 ASSERT_EQ(0U, object_paths.size());
375 TEST_F(ObjectManagerTest, OwnershipLostAndRegained) {
376 PerformAction("Ownership", ObjectPath("/org/chromium/TestService"));
377 WaitForRemoveObject();
378 WaitForObject();
380 std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
381 ASSERT_EQ(1U, object_paths.size());
384 TEST_F(ObjectManagerTest, PropertiesChangedAsObjectsReceived) {
385 // Remove the existing object manager.
386 object_manager_->UnregisterInterface("org.chromium.TestInterface");
387 run_loop_.reset(new base::RunLoop);
388 EXPECT_TRUE(bus_->RemoveObjectManager(
389 "org.chromium.TestService",
390 ObjectPath("/org/chromium/TestService"),
391 run_loop_->QuitClosure()));
392 run_loop_->Run();
394 PerformAction("SetSendImmediatePropertiesChanged",
395 ObjectPath("/org/chromium/TestService"));
397 object_manager_ = bus_->GetObjectManager(
398 "org.chromium.TestService",
399 ObjectPath("/org/chromium/TestService"));
400 object_manager_->RegisterInterface("org.chromium.TestInterface", this);
402 // The newly created object manager should call GetManagedObjects immediately
403 // after setting up the match rule for PropertiesChanged. We should process
404 // the PropertiesChanged event right after that. If we don't receive it within
405 // 2 seconds, then fail the test.
406 message_loop_.PostDelayedTask(
407 FROM_HERE,
408 base::Bind(&ObjectManagerTest::PropertiesChangedTestTimeout,
409 base::Unretained(this)),
410 base::TimeDelta::FromSeconds(2));
412 while (last_name_value_ != "ChangedTestServiceName" && !timeout_expired_) {
413 run_loop_.reset(new base::RunLoop);
414 run_loop_->Run();
418 } // namespace dbus