blob: 71ce5335485b78e6708b9c3ede6955908a6f0647 [file] [log] [blame]
keybuk@chromium.org7e0c4932012-02-15 13:21:08 +09001// Copyright (c) 2012 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/property.h"
6
7#include <string>
8#include <vector>
9
10#include "base/basictypes.h"
11#include "base/bind.h"
12#include "base/logging.h"
13#include "base/message_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"
22
23// The property test exerises the asynchronous APIs in PropertySet and
24// Property<>.
25class PropertyTest : public testing::Test {
26 public:
27 PropertyTest() {
28 }
29
30 struct Properties : public dbus::PropertySet {
31 dbus::Property<std::string> name;
32 dbus::Property<int16> version;
33 dbus::Property<std::vector<std::string> > methods;
34 dbus::Property<std::vector<dbus::ObjectPath> > objects;
35
36 Properties(dbus::ObjectProxy* object_proxy,
37 PropertyChangedCallback property_changed_callback)
38 : dbus::PropertySet(object_proxy,
39 "org.chromium.TestService",
40 property_changed_callback) {
41 RegisterProperty("Name", &name);
42 RegisterProperty("Version", &version);
43 RegisterProperty("Methods", &methods);
44 RegisterProperty("Objects", &objects);
45 }
46 };
47
48 virtual void SetUp() {
49 // Make the main thread not to allow IO.
50 base::ThreadRestrictions::SetIOAllowed(false);
51
52 // Start the D-Bus thread.
53 dbus_thread_.reset(new base::Thread("D-Bus Thread"));
54 base::Thread::Options thread_options;
55 thread_options.message_loop_type = MessageLoop::TYPE_IO;
56 ASSERT_TRUE(dbus_thread_->StartWithOptions(thread_options));
57
58 // Start the test service, using the D-Bus thread.
59 dbus::TestService::Options options;
60 options.dbus_thread_message_loop_proxy = dbus_thread_->message_loop_proxy();
61 test_service_.reset(new dbus::TestService(options));
62 ASSERT_TRUE(test_service_->StartService());
63 ASSERT_TRUE(test_service_->WaitUntilServiceIsStarted());
64 ASSERT_TRUE(test_service_->HasDBusThread());
65
66 // Create the client, using the D-Bus thread.
67 dbus::Bus::Options bus_options;
68 bus_options.bus_type = dbus::Bus::SESSION;
69 bus_options.connection_type = dbus::Bus::PRIVATE;
70 bus_options.dbus_thread_message_loop_proxy =
71 dbus_thread_->message_loop_proxy();
72 bus_ = new dbus::Bus(bus_options);
73 object_proxy_ = bus_->GetObjectProxy(
74 "org.chromium.TestService",
75 dbus::ObjectPath("/org/chromium/TestObject"));
76 ASSERT_TRUE(bus_->HasDBusThread());
77
78 // Create the properties structure
79 properties_ = new Properties(object_proxy_,
80 base::Bind(&PropertyTest::OnPropertyChanged,
81 base::Unretained(this)));
82 properties_->ConnectSignals();
83 properties_->GetAll();
84 }
85
86 virtual void TearDown() {
87 bus_->ShutdownOnDBusThreadAndBlock();
88
89 // Shut down the service.
90 test_service_->ShutdownAndBlock();
91
92 // Reset to the default.
93 base::ThreadRestrictions::SetIOAllowed(true);
94
95 // Stopping a thread is considered an IO operation, so do this after
96 // allowing IO.
97 test_service_->Stop();
98 }
99
100 // Generic callback, bind with a string |id| for passing to
101 // WaitForCallback() to ensure the callback for the right method is
102 // waited for.
103 void PropertyCallback(const std::string& id, bool success) {
104 last_callback_ = id;
105 message_loop_.Quit();
106 }
107
108 protected:
109 // Called when a property value is updated.
110 void OnPropertyChanged(const std::string& name) {
111 updated_properties_.push_back(name);
112 message_loop_.Quit();
113 }
114
115 // Wait for the given number of updates.
116 void WaitForUpdates(size_t num_updates) {
117 while (updated_properties_.size() < num_updates)
118 message_loop_.Run();
119 for (size_t i = 0; i < num_updates; ++i)
120 updated_properties_.erase(updated_properties_.begin());
121 }
122
123 // Name, Version, Methods, Objects
124 static const int kExpectedSignalUpdates = 4;
125
126 // Wait for initial values to be set.
127 void WaitForGetAll() {
128 WaitForUpdates(kExpectedSignalUpdates);
129 }
130
131 // Wait for the callback. |id| is the string bound to the callback when
132 // the method call is made that identifies it and distinguishes from any
133 // other; you can set this to whatever you wish.
134 void WaitForCallback(const std::string& id) {
135 while (last_callback_ != id) {
136 message_loop_.Run();
137 }
138 }
139
140 MessageLoop message_loop_;
141 scoped_ptr<base::Thread> dbus_thread_;
142 scoped_refptr<dbus::Bus> bus_;
143 dbus::ObjectProxy* object_proxy_;
144 Properties* properties_;
145 scoped_ptr<dbus::TestService> test_service_;
146 // Properties updated.
147 std::vector<std::string> updated_properties_;
148 // Last callback received.
149 std::string last_callback_;
150};
151
152TEST_F(PropertyTest, InitialValues) {
153 WaitForGetAll();
154
155 EXPECT_EQ(properties_->name.value(), "TestService");
156 EXPECT_EQ(properties_->version.value(), 10);
157
158 std::vector<std::string> methods = properties_->methods.value();
159 ASSERT_EQ(4U, methods.size());
160 EXPECT_EQ("Echo", methods[0]);
161 EXPECT_EQ("SlowEcho", methods[1]);
162 EXPECT_EQ("AsyncEcho", methods[2]);
163 EXPECT_EQ("BrokenMethod", methods[3]);
164
165 std::vector<dbus::ObjectPath> objects = properties_->objects.value();
166 ASSERT_EQ(1U, objects.size());
167 EXPECT_EQ(dbus::ObjectPath("/TestObjectPath"), objects[0]);
168}
169
keybuk@google.comf056b962012-03-22 08:43:45 +0900170TEST_F(PropertyTest, UpdatedValues) {
171 WaitForGetAll();
172
173 // Update the value of the "Name" property, this value should not change.
174 properties_->name.Get(base::Bind(&PropertyTest::PropertyCallback,
175 base::Unretained(this),
176 "Name"));
177 WaitForCallback("Name");
178 WaitForUpdates(1);
179
180 EXPECT_EQ(properties_->name.value(), "TestService");
181
182 // Update the value of the "Version" property, this value should be changed.
183 properties_->version.Get(base::Bind(&PropertyTest::PropertyCallback,
184 base::Unretained(this),
185 "Version"));
186 WaitForCallback("Version");
187 WaitForUpdates(1);
188
189 EXPECT_EQ(properties_->version.value(), 20);
190
191 // Update the value of the "Methods" property, this value should not change
192 // and should not grow to contain duplicate entries.
193 properties_->methods.Get(base::Bind(&PropertyTest::PropertyCallback,
194 base::Unretained(this),
195 "Methods"));
196 WaitForCallback("Methods");
197 WaitForUpdates(1);
198
199 std::vector<std::string> methods = properties_->methods.value();
200 ASSERT_EQ(4U, methods.size());
201 EXPECT_EQ("Echo", methods[0]);
202 EXPECT_EQ("SlowEcho", methods[1]);
203 EXPECT_EQ("AsyncEcho", methods[2]);
204 EXPECT_EQ("BrokenMethod", methods[3]);
205
206 // Update the value of the "Objects" property, this value should not change
207 // and should not grow to contain duplicate entries.
208 properties_->objects.Get(base::Bind(&PropertyTest::PropertyCallback,
209 base::Unretained(this),
210 "Objects"));
211 WaitForCallback("Objects");
212 WaitForUpdates(1);
213
214 std::vector<dbus::ObjectPath> objects = properties_->objects.value();
215 ASSERT_EQ(1U, objects.size());
216 EXPECT_EQ(dbus::ObjectPath("/TestObjectPath"), objects[0]);
217}
218
keybuk@chromium.org7e0c4932012-02-15 13:21:08 +0900219TEST_F(PropertyTest, Get) {
220 WaitForGetAll();
221
222 // Ask for the new Version property.
223 properties_->version.Get(base::Bind(&PropertyTest::PropertyCallback,
224 base::Unretained(this),
225 "Get"));
226 WaitForCallback("Get");
227
228 // Make sure we got a property update too.
229 WaitForUpdates(1);
230
231 EXPECT_EQ(properties_->version.value(), 20);
232}
233
234TEST_F(PropertyTest, Set) {
235 WaitForGetAll();
236
237 // Set a new name.
238 properties_->name.Set("NewService",
239 base::Bind(&PropertyTest::PropertyCallback,
240 base::Unretained(this),
241 "Set"));
242 WaitForCallback("Set");
243
244 // TestService sends a property update.
245 WaitForUpdates(1);
246
247 EXPECT_EQ(properties_->name.value(), "NewService");
248}