1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
|
// Copyright (c) 2011 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.
//
// This test is relatively complicated. Here's the summary of what it does:
//
// - Set up mock D-Bus related objects to mock out D-Bus calls.
// - Set up a mock proxy resolver to mock out the proxy resolution.
// - Create ProxyResolutionServiceProvider by injecting the mocks
// - Start the service provider.
// - Request ProxyResolutionServiceProvider to resolve proxy for kSourceURL.
// - ProxyResolutionServiceProvider will return the result as a signal.
// - Confirm that we receive the signal and check the contents of the signal.
#include "chrome/browser/chromeos/dbus/proxy_resolution_service_provider.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop.h"
#include "dbus/message.h"
#include "dbus/mock_bus.h"
#include "dbus/mock_exported_object.h"
#include "dbus/mock_object_proxy.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
using ::testing::_;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::Unused;
namespace chromeos {
// We want to know about the proxy info for the URL.
const char kSourceURL[] = "http://www.gmail.com/";
// ProxyResolutionServiceProvider will return the proxy info as a D-Bus
// signal, to the following signal interface and the signal name.
const char kReturnSignalInterface[] = "org.chromium.TestInterface";
const char kReturnSignalName[] = "TestSignal";
// The returned proxy info.
const char kReturnProxyInfo[] = "PROXY cache.example.com:12345";
// The error message is empty if proxy resolution is successful.
const char kReturnEmptyErrorMessage[] = "";
// Mock for ProxyResolverInterface. We'll inject this to
// ProxyResolutionServiceProvider to mock out the proxy resolution.
class MockProxyResolver : public ProxyResolverInterface {
public:
MOCK_METHOD4(ResolveProxy,
void(const std::string& source_url,
const std::string& signal_interface,
const std::string& signal_name,
scoped_refptr<dbus::ExportedObject> exported_object));
};
class ProxyResolutionServiceProviderTest : public testing::Test {
public:
ProxyResolutionServiceProviderTest()
: signal_received_successfully_(false),
mock_resolver_(NULL),
response_received_(false) {
}
virtual void SetUp() {
// Create a mock bus.
dbus::Bus::Options options;
options.bus_type = dbus::Bus::SYSTEM;
mock_bus_ = new dbus::MockBus(options);
// ShutdownAndBlock() will be called in TearDown().
EXPECT_CALL(*mock_bus_, ShutdownAndBlock()).WillOnce(Return());
// Create a mock exported object that behaves as
// org.chromium.CrosDBusService.
mock_exported_object_ =
new dbus::MockExportedObject(mock_bus_.get(),
kLibCrosServiceName,
kLibCrosServicePath);
// |mock_exported_object_|'s ExportMethod() will use
// |MockExportedObject().
EXPECT_CALL(
*mock_exported_object_,
ExportMethod(_, _, _, _)).WillOnce(
Invoke(this,
&ProxyResolutionServiceProviderTest::MockExportMethod));
// |mock_exported_object_|'s SendSignal() will use
// |MockSendSignal().
EXPECT_CALL(
*mock_exported_object_,
SendSignal(_)).WillOnce(
Invoke(this,
&ProxyResolutionServiceProviderTest::MockSendSignal));
// Create a mock object proxy, with which we call a method of
// |mock_exported_object_|.
mock_object_proxy_ =
new dbus::MockObjectProxy(mock_bus_.get(),
kLibCrosServiceName,
kLibCrosServicePath);
// |mock_object_proxy_|'s CallMethodAndBlock() will use
// MockCallMethodAndBlock() to return responses.
EXPECT_CALL(*mock_object_proxy_,
CallMethodAndBlock(_, _))
.WillOnce(Invoke(
this,
&ProxyResolutionServiceProviderTest::MockCallMethodAndBlock));
// |mock_object_proxy_|'s ConnectToSignal will use
// MockConnectToSignal().
EXPECT_CALL(*mock_object_proxy_,
ConnectToSignal(kReturnSignalInterface,
kReturnSignalName,
_, _))
.WillOnce(Invoke(
this,
&ProxyResolutionServiceProviderTest::MockConnectToSignal));
// Create a mock proxy resolver. Will be owned by
// |proxy_resolution_service|.
mock_resolver_ = new MockProxyResolver;
// |mock_resolver_|'s ResolveProxy() will use MockResolveProxy().
EXPECT_CALL(*mock_resolver_, ResolveProxy(kSourceURL,
kReturnSignalInterface,
kReturnSignalName,
_))
.WillOnce(Invoke(
this,
&ProxyResolutionServiceProviderTest::MockResolveProxy));
// Create the proxy resolution service with the mock bus and the mock
// resolver injected.
proxy_resolution_service_.reset(
ProxyResolutionServiceProvider::CreateForTesting(mock_resolver_));
// Finally, start the service.
proxy_resolution_service_->Start(mock_exported_object_);
}
virtual void TearDown() {
mock_bus_->ShutdownAndBlock();
}
// Called when a signal is received.
void OnSignalReceived(dbus::Signal* signal) {
ASSERT_EQ(kReturnSignalInterface, signal->GetInterface());
ASSERT_EQ(kReturnSignalName, signal->GetMember());
std::string source_url;
std::string proxy_info;
std::string error_message;
// The signal should contain three strings.
dbus::MessageReader reader(signal);
ASSERT_TRUE(reader.PopString(&source_url));
ASSERT_TRUE(reader.PopString(&proxy_info));
ASSERT_TRUE(reader.PopString(&error_message));
// Check the signal conetnts.
EXPECT_EQ(kSourceURL, source_url);
EXPECT_EQ(kReturnProxyInfo, proxy_info);
EXPECT_EQ(kReturnEmptyErrorMessage, error_message);
// Mark that the signal is received successfully.
signal_received_successfully_ = true;
}
// Called when connected to a signal.
void OnConnectedToSignal(const std::string& signal_interface,
const std::string& signal_name,
bool success){
ASSERT_EQ(kReturnSignalInterface, signal_interface);
ASSERT_EQ(kReturnSignalName, signal_name);
ASSERT_TRUE(success);
}
protected:
bool signal_received_successfully_;
MockProxyResolver* mock_resolver_;
scoped_refptr<dbus::MockBus> mock_bus_;
scoped_refptr<dbus::MockExportedObject> mock_exported_object_;
scoped_refptr<dbus::MockObjectProxy> mock_object_proxy_;
scoped_ptr<ProxyResolutionServiceProvider> proxy_resolution_service_;
dbus::ExportedObject::MethodCallCallback resolve_network_proxy_;
dbus::ObjectProxy::SignalCallback on_signal_callback_;
MessageLoop message_loop_;
bool response_received_;
scoped_ptr<dbus::Response> response_;
private:
// Behaves as |mock_exported_object_|'s ExportMethod().
void MockExportMethod(
const std::string& interface_name,
const std::string& method_name,
dbus::ExportedObject::MethodCallCallback method_callback,
dbus::ExportedObject::OnExportedCallback on_exported_callback) {
if (interface_name == kLibCrosServiceInterface &&
method_name == kResolveNetworkProxy) {
// Tell the call back that the method is exported successfully.
on_exported_callback.Run(interface_name, method_name, true);
// Capture the callback, so we can run this at a later time.
resolve_network_proxy_ = method_callback;
return;
}
LOG(ERROR) << "Unexpected method exported: " << interface_name
<< method_name;
}
// Behaves as |mock_exported_object_|'s SendSignal().
void MockSendSignal(dbus::Signal* signal) {
ASSERT_EQ(kReturnSignalInterface, signal->GetInterface());
ASSERT_EQ(kReturnSignalName, signal->GetMember());
// Run the callback captured in MockConnectToSignal(). This will call
// OnSignalReceived().
on_signal_callback_.Run(signal);
}
// Behaves as |mock_resolver_|'s ResolveProxy().
void MockResolveProxy(const std::string& source_url,
const std::string& signal_interface,
const std::string& signal_name,
scoped_refptr<dbus::ExportedObject> exported_object) {
if (source_url == kSourceURL) {
dbus::Signal signal(signal_interface,
signal_name);
dbus::MessageWriter writer(&signal);
writer.AppendString(kSourceURL);
writer.AppendString(kReturnProxyInfo);
writer.AppendString(kReturnEmptyErrorMessage);
// Send the signal back to the requested signal interface and the
// signal name.
exported_object->SendSignal(&signal);
return;
}
LOG(ERROR) << "Unexpected source URL: " << source_url;
}
// Calls exported method and waits for a response for |mock_object_proxy_|.
dbus::Response* MockCallMethodAndBlock(
dbus::MethodCall* method_call,
Unused) {
if (method_call->GetInterface() != kLibCrosServiceInterface ||
method_call->GetMember() != kResolveNetworkProxy) {
LOG(ERROR) << "Unexpected method call: " << method_call->ToString();
return NULL;
}
// Set the serial number to non-zero, so
// dbus_message_new_method_return() won't emit a warning.
method_call->SetSerial(1);
// Run the callback captured in MockExportMethod(). In addition to returning
// a response that the caller will ignore, this will send a signal, which
// will be received by |on_signal_callback_|.
resolve_network_proxy_.Run(
method_call,
base::Bind(&ProxyResolutionServiceProviderTest::OnResponse,
base::Unretained(this)));
// Check for a response.
if (!response_received_)
message_loop_.Run();
// Return response.
return response_.release();
}
// Receives a response and makes it available to MockCallMethodAndBlock().
void OnResponse(dbus::Response* response) {
response_.reset(response);
response_received_ = true;
if (message_loop_.is_running())
message_loop_.Quit();
}
// Behaves as |mock_object_proxy_|'s ConnectToSignal().
void MockConnectToSignal(
const std::string& interface_name,
const std::string& signal_name,
dbus::ObjectProxy::SignalCallback signal_callback,
dbus::ObjectProxy::OnConnectedCallback connected_callback) {
// Tell the callback that the object proxy is connected to the signal.
connected_callback.Run(interface_name, signal_name, true);
// Capture the callback, so we can run this at a later time.
on_signal_callback_ = signal_callback;
}
};
TEST_F(ProxyResolutionServiceProviderTest, ResolveProxy) {
// Connect to the signal that will be sent to kReturnSignalInterface and
// kReturnSignalName. ResolveNetworkProxy() will send the result as a
// signal. OnSignalReceived() will be called upon the delivery.
mock_object_proxy_->ConnectToSignal(
kReturnSignalInterface,
kReturnSignalName,
base::Bind(&ProxyResolutionServiceProviderTest::OnSignalReceived,
base::Unretained(this)),
base::Bind(&ProxyResolutionServiceProviderTest::OnConnectedToSignal,
base::Unretained(this)));
// The signal is not yet received.
ASSERT_FALSE(signal_received_successfully_);
// Create a method call to resolve proxy config for kSourceURL.
dbus::MethodCall method_call(kLibCrosServiceInterface,
kResolveNetworkProxy);
dbus::MessageWriter writer(&method_call);
writer.AppendString(kSourceURL);
writer.AppendString(kReturnSignalInterface);
writer.AppendString(kReturnSignalName);
// Call the ResolveNetworkProxy method.
scoped_ptr<dbus::Response> response(
mock_object_proxy_->CallMethodAndBlock(
&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
// An empty response should be returned.
ASSERT_TRUE(response.get());
dbus::MessageReader reader(response.get());
ASSERT_FALSE(reader.HasMoreData());
// Confirm that the signal is received successfully.
// The contents of the signal are checked in OnSignalReceived().
ASSERT_TRUE(signal_received_successfully_);
}
} // namespace chromeos
|