Optimize MetricsDetails classes to avoid a lot of redundant work.
[chromium-blink-merge.git] / dbus / object_manager_unittest.cc
blob76ddb85fa8f1f80864cf7a38c77cc42cb36b65e0
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 PropertySet* CreateProperties(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);
61 void SetUp() override {
62 // Make the main thread not to allow IO.
63 base::ThreadRestrictions::SetIOAllowed(false);
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));
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());
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());
87 object_manager_ = bus_->GetObjectManager(
88 "org.chromium.TestService",
89 ObjectPath("/org/chromium/TestService"));
90 object_manager_->RegisterInterface("org.chromium.TestInterface", this);
92 WaitForObject();
95 void TearDown() override {
96 bus_->ShutdownOnDBusThreadAndBlock();
98 // Shut down the service.
99 test_service_->ShutdownAndBlock();
101 // Reset to the default.
102 base::ThreadRestrictions::SetIOAllowed(true);
104 // Stopping a thread is considered an IO operation, so do this after
105 // allowing IO.
106 test_service_->Stop();
108 base::RunLoop().RunUntilIdle();
111 void MethodCallback(Response* response) {
112 method_callback_called_ = true;
113 run_loop_->Quit();
116 // Called from the PropertiesChangedAsObjectsReceived test case. The test will
117 // not run the message loop if it receives the expected PropertiesChanged
118 // signal before the timeout. This method immediately fails the test.
119 void PropertiesChangedTestTimeout() {
120 timeout_expired_ = true;
121 run_loop_->Quit();
123 FAIL() << "Never received PropertiesChanged";
126 protected:
127 // Called when an object is added.
128 void ObjectAdded(const ObjectPath& object_path,
129 const std::string& interface_name) override {
130 added_objects_.push_back(std::make_pair(object_path, interface_name));
131 run_loop_->Quit();
134 // Called when an object is removed.
135 void ObjectRemoved(const ObjectPath& object_path,
136 const std::string& interface_name) override {
137 removed_objects_.push_back(std::make_pair(object_path, interface_name));
138 run_loop_->Quit();
141 // Called when a property value is updated.
142 void OnPropertyChanged(const ObjectPath& object_path,
143 const std::string& name) {
144 // Store the value of the "Name" property if that's the one that
145 // changed.
146 Properties* properties = static_cast<Properties*>(
147 object_manager_->GetProperties(
148 object_path,
149 "org.chromium.TestInterface"));
150 if (name == properties->name.name())
151 last_name_value_ = properties->name.value();
153 // Store the updated property.
154 updated_properties_.push_back(name);
155 run_loop_->Quit();
158 static const size_t kExpectedObjects = 1;
159 static const size_t kExpectedProperties = 4;
161 void WaitForObject() {
162 while (added_objects_.size() < kExpectedObjects ||
163 updated_properties_.size() < kExpectedProperties) {
164 run_loop_.reset(new base::RunLoop);
165 run_loop_->Run();
167 for (size_t i = 0; i < kExpectedObjects; ++i)
168 added_objects_.erase(added_objects_.begin());
169 for (size_t i = 0; i < kExpectedProperties; ++i)
170 updated_properties_.erase(updated_properties_.begin());
173 void WaitForRemoveObject() {
174 while (removed_objects_.size() < kExpectedObjects) {
175 run_loop_.reset(new base::RunLoop);
176 run_loop_->Run();
178 for (size_t i = 0; i < kExpectedObjects; ++i)
179 removed_objects_.erase(removed_objects_.begin());
182 void WaitForMethodCallback() {
183 run_loop_.reset(new base::RunLoop);
184 run_loop_->Run();
185 method_callback_called_ = false;
188 void PerformAction(const std::string& action, const ObjectPath& object_path) {
189 ObjectProxy* object_proxy = bus_->GetObjectProxy(
190 "org.chromium.TestService",
191 ObjectPath("/org/chromium/TestObject"));
193 MethodCall method_call("org.chromium.TestInterface", "PerformAction");
194 MessageWriter writer(&method_call);
195 writer.AppendString(action);
196 writer.AppendObjectPath(object_path);
198 object_proxy->CallMethod(&method_call,
199 ObjectProxy::TIMEOUT_USE_DEFAULT,
200 base::Bind(&ObjectManagerTest::MethodCallback,
201 base::Unretained(this)));
202 WaitForMethodCallback();
205 base::MessageLoop message_loop_;
206 scoped_ptr<base::RunLoop> run_loop_;
207 scoped_ptr<base::Thread> dbus_thread_;
208 scoped_refptr<Bus> bus_;
209 ObjectManager* object_manager_;
210 scoped_ptr<TestService> test_service_;
212 std::string last_name_value_;
213 bool timeout_expired_;
215 std::vector<std::pair<ObjectPath, std::string> > added_objects_;
216 std::vector<std::pair<ObjectPath, std::string> > removed_objects_;
217 std::vector<std::string> updated_properties_;
219 bool method_callback_called_;
223 TEST_F(ObjectManagerTest, InitialObject) {
224 ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
225 ObjectPath("/org/chromium/TestObject"));
226 EXPECT_TRUE(object_proxy != NULL);
228 Properties* properties = static_cast<Properties*>(
229 object_manager_->GetProperties(ObjectPath("/org/chromium/TestObject"),
230 "org.chromium.TestInterface"));
231 EXPECT_TRUE(properties != NULL);
233 EXPECT_EQ("TestService", properties->name.value());
234 EXPECT_EQ(10, properties->version.value());
236 std::vector<std::string> methods = properties->methods.value();
237 ASSERT_EQ(4U, methods.size());
238 EXPECT_EQ("Echo", methods[0]);
239 EXPECT_EQ("SlowEcho", methods[1]);
240 EXPECT_EQ("AsyncEcho", methods[2]);
241 EXPECT_EQ("BrokenMethod", methods[3]);
243 std::vector<ObjectPath> objects = properties->objects.value();
244 ASSERT_EQ(1U, objects.size());
245 EXPECT_EQ(ObjectPath("/TestObjectPath"), objects[0]);
248 TEST_F(ObjectManagerTest, UnknownObjectProxy) {
249 ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
250 ObjectPath("/org/chromium/UnknownObject"));
251 EXPECT_TRUE(object_proxy == NULL);
254 TEST_F(ObjectManagerTest, UnknownObjectProperties) {
255 Properties* properties = static_cast<Properties*>(
256 object_manager_->GetProperties(ObjectPath("/org/chromium/UnknownObject"),
257 "org.chromium.TestInterface"));
258 EXPECT_TRUE(properties == NULL);
261 TEST_F(ObjectManagerTest, UnknownInterfaceProperties) {
262 Properties* properties = static_cast<Properties*>(
263 object_manager_->GetProperties(ObjectPath("/org/chromium/TestObject"),
264 "org.chromium.UnknownService"));
265 EXPECT_TRUE(properties == NULL);
268 TEST_F(ObjectManagerTest, GetObjects) {
269 std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
270 ASSERT_EQ(1U, object_paths.size());
271 EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
274 TEST_F(ObjectManagerTest, GetObjectsWithInterface) {
275 std::vector<ObjectPath> object_paths =
276 object_manager_->GetObjectsWithInterface("org.chromium.TestInterface");
277 ASSERT_EQ(1U, object_paths.size());
278 EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
281 TEST_F(ObjectManagerTest, GetObjectsWithUnknownInterface) {
282 std::vector<ObjectPath> object_paths =
283 object_manager_->GetObjectsWithInterface("org.chromium.UnknownService");
284 EXPECT_EQ(0U, object_paths.size());
287 TEST_F(ObjectManagerTest, SameObject) {
288 ObjectManager* object_manager = bus_->GetObjectManager(
289 "org.chromium.TestService",
290 ObjectPath("/org/chromium/TestService"));
291 EXPECT_EQ(object_manager_, object_manager);
294 TEST_F(ObjectManagerTest, DifferentObjectForService) {
295 ObjectManager* object_manager = bus_->GetObjectManager(
296 "org.chromium.DifferentService",
297 ObjectPath("/org/chromium/TestService"));
298 EXPECT_NE(object_manager_, object_manager);
301 TEST_F(ObjectManagerTest, DifferentObjectForPath) {
302 ObjectManager* object_manager = bus_->GetObjectManager(
303 "org.chromium.TestService",
304 ObjectPath("/org/chromium/DifferentService"));
305 EXPECT_NE(object_manager_, object_manager);
308 TEST_F(ObjectManagerTest, SecondObject) {
309 PerformAction("AddObject", ObjectPath("/org/chromium/SecondObject"));
310 WaitForObject();
312 ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
313 ObjectPath("/org/chromium/SecondObject"));
314 EXPECT_TRUE(object_proxy != NULL);
316 Properties* properties = static_cast<Properties*>(
317 object_manager_->GetProperties(ObjectPath("/org/chromium/SecondObject"),
318 "org.chromium.TestInterface"));
319 EXPECT_TRUE(properties != NULL);
321 std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
322 ASSERT_EQ(2U, object_paths.size());
324 std::sort(object_paths.begin(), object_paths.end());
325 EXPECT_EQ(ObjectPath("/org/chromium/SecondObject"), object_paths[0]);
326 EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[1]);
328 object_paths =
329 object_manager_->GetObjectsWithInterface("org.chromium.TestInterface");
330 ASSERT_EQ(2U, object_paths.size());
332 std::sort(object_paths.begin(), object_paths.end());
333 EXPECT_EQ(ObjectPath("/org/chromium/SecondObject"), object_paths[0]);
334 EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[1]);
337 TEST_F(ObjectManagerTest, RemoveSecondObject) {
338 PerformAction("AddObject", ObjectPath("/org/chromium/SecondObject"));
339 WaitForObject();
341 std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
342 ASSERT_EQ(2U, object_paths.size());
344 PerformAction("RemoveObject", ObjectPath("/org/chromium/SecondObject"));
345 WaitForRemoveObject();
347 ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
348 ObjectPath("/org/chromium/SecondObject"));
349 EXPECT_TRUE(object_proxy == NULL);
351 Properties* properties = static_cast<Properties*>(
352 object_manager_->GetProperties(ObjectPath("/org/chromium/SecondObject"),
353 "org.chromium.TestInterface"));
354 EXPECT_TRUE(properties == NULL);
356 object_paths = object_manager_->GetObjects();
357 ASSERT_EQ(1U, object_paths.size());
358 EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
360 object_paths =
361 object_manager_->GetObjectsWithInterface("org.chromium.TestInterface");
362 ASSERT_EQ(1U, object_paths.size());
363 EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
366 TEST_F(ObjectManagerTest, OwnershipLost) {
367 PerformAction("ReleaseOwnership", ObjectPath("/org/chromium/TestService"));
368 WaitForRemoveObject();
370 std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
371 ASSERT_EQ(0U, object_paths.size());
374 TEST_F(ObjectManagerTest, OwnershipLostAndRegained) {
375 PerformAction("Ownership", ObjectPath("/org/chromium/TestService"));
376 WaitForRemoveObject();
377 WaitForObject();
379 std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
380 ASSERT_EQ(1U, object_paths.size());
383 TEST_F(ObjectManagerTest, PropertiesChangedAsObjectsReceived) {
384 // Remove the existing object manager.
385 object_manager_->UnregisterInterface("org.chromium.TestInterface");
386 run_loop_.reset(new base::RunLoop);
387 EXPECT_TRUE(bus_->RemoveObjectManager(
388 "org.chromium.TestService",
389 ObjectPath("/org/chromium/TestService"),
390 run_loop_->QuitClosure()));
391 run_loop_->Run();
393 PerformAction("SetSendImmediatePropertiesChanged",
394 ObjectPath("/org/chromium/TestService"));
396 object_manager_ = bus_->GetObjectManager(
397 "org.chromium.TestService",
398 ObjectPath("/org/chromium/TestService"));
399 object_manager_->RegisterInterface("org.chromium.TestInterface", this);
401 // The newly created object manager should call GetManagedObjects immediately
402 // after setting up the match rule for PropertiesChanged. We should process
403 // the PropertiesChanged event right after that. If we don't receive it within
404 // 2 seconds, then fail the test.
405 message_loop_.PostDelayedTask(
406 FROM_HERE,
407 base::Bind(&ObjectManagerTest::PropertiesChangedTestTimeout,
408 base::Unretained(this)),
409 base::TimeDelta::FromSeconds(2));
411 while (last_name_value_ != "ChangedTestServiceName" && !timeout_expired_) {
412 run_loop_.reset(new base::RunLoop);
413 run_loop_->Run();
417 } // namespace dbus