1 // Copyright 2014 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 "base/at_exit.h"
6 #include "base/message_loop/message_loop.h"
7 #include "mojo/public/cpp/application/application.h"
8 #include "mojo/public/interfaces/service_provider/service_provider.mojom.h"
9 #include "mojo/service_manager/service_loader.h"
10 #include "mojo/service_manager/service_manager.h"
11 #include "mojo/service_manager/test.mojom.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace mojo {
15 namespace {
16
17 const char kTestURLString[] = "test:testService";
18 const char kTestAURLString[] = "test:TestA";
19 const char kTestBURLString[] = "test:TestB";
20
21 struct TestContext {
TestContextmojo::__anone689828b0111::TestContext22 TestContext() : num_impls(0), num_loader_deletes(0) {}
23 std::string last_test_string;
24 int num_impls;
25 int num_loader_deletes;
26 };
27
28 class QuitMessageLoopErrorHandler : public ErrorHandler {
29 public:
QuitMessageLoopErrorHandler()30 QuitMessageLoopErrorHandler() {}
~QuitMessageLoopErrorHandler()31 virtual ~QuitMessageLoopErrorHandler() {}
32
33 // |ErrorHandler| implementation:
OnConnectionError()34 virtual void OnConnectionError() OVERRIDE {
35 base::MessageLoop::current()->QuitWhenIdle();
36 }
37
38 private:
39 DISALLOW_COPY_AND_ASSIGN(QuitMessageLoopErrorHandler);
40 };
41
42 class TestServiceImpl : public InterfaceImpl<TestService> {
43 public:
TestServiceImpl(TestContext * context)44 explicit TestServiceImpl(TestContext* context) : context_(context) {
45 ++context_->num_impls;
46 }
47
~TestServiceImpl()48 virtual ~TestServiceImpl() {
49 --context_->num_impls;
50 }
51
OnConnectionError()52 virtual void OnConnectionError() OVERRIDE {
53 base::MessageLoop::current()->Quit();
54 }
55
56 // TestService implementation:
Test(const String & test_string)57 virtual void Test(const String& test_string) OVERRIDE {
58 context_->last_test_string = test_string;
59 client()->AckTest();
60 }
61
62 private:
63 TestContext* context_;
64 };
65
66 class TestClientImpl : public TestClient {
67 public:
TestClientImpl(TestServicePtr service)68 explicit TestClientImpl(TestServicePtr service)
69 : service_(service.Pass()),
70 quit_after_ack_(false) {
71 service_.set_client(this);
72 }
73
~TestClientImpl()74 virtual ~TestClientImpl() {}
75
AckTest()76 virtual void AckTest() OVERRIDE {
77 if (quit_after_ack_)
78 base::MessageLoop::current()->Quit();
79 }
80
Test(std::string test_string)81 void Test(std::string test_string) {
82 quit_after_ack_ = true;
83 service_->Test(test_string);
84 }
85
86 private:
87 TestServicePtr service_;
88 bool quit_after_ack_;
89 DISALLOW_COPY_AND_ASSIGN(TestClientImpl);
90 };
91
92 class TestServiceLoader : public ServiceLoader {
93 public:
TestServiceLoader()94 TestServiceLoader()
95 : context_(NULL),
96 num_loads_(0) {
97 }
98
~TestServiceLoader()99 virtual ~TestServiceLoader() {
100 if (context_)
101 ++context_->num_loader_deletes;
102 test_app_.reset(NULL);
103 }
104
set_context(TestContext * context)105 void set_context(TestContext* context) { context_ = context; }
num_loads() const106 int num_loads() const { return num_loads_; }
107
108 private:
LoadService(ServiceManager * manager,const GURL & url,ScopedMessagePipeHandle service_provider_handle)109 virtual void LoadService(
110 ServiceManager* manager,
111 const GURL& url,
112 ScopedMessagePipeHandle service_provider_handle) OVERRIDE {
113 ++num_loads_;
114 test_app_.reset(new Application(service_provider_handle.Pass()));
115 test_app_->AddService<TestServiceImpl>(context_);
116 }
117
OnServiceError(ServiceManager * manager,const GURL & url)118 virtual void OnServiceError(ServiceManager* manager,
119 const GURL& url) OVERRIDE {
120 }
121
122 scoped_ptr<Application> test_app_;
123 TestContext* context_;
124 int num_loads_;
125 DISALLOW_COPY_AND_ASSIGN(TestServiceLoader);
126 };
127
128 // Used to test that the requestor url will be correctly passed.
129 class TestAImpl : public InterfaceImpl<TestA> {
130 public:
TestAImpl(Application * app)131 explicit TestAImpl(Application* app) : app_(app) {}
132
LoadB()133 virtual void LoadB() OVERRIDE {
134 TestBPtr b;
135 app_->ConnectTo(kTestBURLString, &b);
136 b->Test();
137 }
138
139 private:
140 Application* app_;
141 };
142
143 class TestBImpl : public InterfaceImpl<TestB> {
144 public:
Test()145 virtual void Test() OVERRIDE {
146 base::MessageLoop::current()->Quit();
147 }
148 };
149
150 class TestApp : public Application, public ServiceLoader {
151 public:
TestApp(std::string requestor_url)152 explicit TestApp(std::string requestor_url)
153 : requestor_url_(requestor_url),
154 num_connects_(0) {
155 }
156
num_connects() const157 int num_connects() const { return num_connects_; }
158
159 private:
LoadService(ServiceManager * manager,const GURL & url,ScopedMessagePipeHandle service_provider_handle)160 virtual void LoadService(
161 ServiceManager* manager,
162 const GURL& url,
163 ScopedMessagePipeHandle service_provider_handle) OVERRIDE {
164 BindServiceProvider(service_provider_handle.Pass());
165 }
166
AllowIncomingConnection(const mojo::String & service_name,const mojo::String & requestor_url)167 virtual bool AllowIncomingConnection(const mojo::String& service_name,
168 const mojo::String& requestor_url)
169 MOJO_OVERRIDE {
170 if (requestor_url_.empty() || requestor_url_ == requestor_url) {
171 ++num_connects_;
172 return true;
173 } else {
174 base::MessageLoop::current()->Quit();
175 return false;
176 }
177 }
178
OnServiceError(ServiceManager * manager,const GURL & url)179 virtual void OnServiceError(ServiceManager* manager,
180 const GURL& url) OVERRIDE {}
181 std::string requestor_url_;
182 int num_connects_;
183 };
184
185 class TestServiceInterceptor : public ServiceManager::Interceptor {
186 public:
TestServiceInterceptor()187 TestServiceInterceptor() : call_count_(0) {}
188
OnConnectToClient(const GURL & url,ScopedMessagePipeHandle handle)189 virtual ScopedMessagePipeHandle OnConnectToClient(
190 const GURL& url, ScopedMessagePipeHandle handle) OVERRIDE {
191 ++call_count_;
192 url_ = url;
193 return handle.Pass();
194 }
195
url_spec() const196 std::string url_spec() const {
197 if (!url_.is_valid())
198 return "invalid url";
199 return url_.spec();
200 }
201
call_count() const202 int call_count() const {
203 return call_count_;
204 }
205
206 private:
207 int call_count_;
208 GURL url_;
209 DISALLOW_COPY_AND_ASSIGN(TestServiceInterceptor);
210 };
211
212 } // namespace
213
214 class ServiceManagerTest : public testing::Test {
215 public:
ServiceManagerTest()216 ServiceManagerTest() {}
217
~ServiceManagerTest()218 virtual ~ServiceManagerTest() {}
219
SetUp()220 virtual void SetUp() OVERRIDE {
221 GURL test_url(kTestURLString);
222 service_manager_.reset(new ServiceManager);
223
224 MessagePipe pipe;
225 TestServicePtr service_proxy = MakeProxy<TestService>(pipe.handle0.Pass());
226 test_client_.reset(new TestClientImpl(service_proxy.Pass()));
227
228 TestServiceLoader* default_loader = new TestServiceLoader;
229 default_loader->set_context(&context_);
230 service_manager_->set_default_loader(
231 scoped_ptr<ServiceLoader>(default_loader));
232
233 service_manager_->ConnectToService(
234 test_url, TestService::Name_, pipe.handle1.Pass(), GURL());
235 }
236
TearDown()237 virtual void TearDown() OVERRIDE {
238 test_client_.reset(NULL);
239 service_manager_.reset(NULL);
240 }
241
HasFactoryForTestURL()242 bool HasFactoryForTestURL() {
243 ServiceManager::TestAPI manager_test_api(service_manager_.get());
244 return manager_test_api.HasFactoryForURL(GURL(kTestURLString));
245 }
246
247 protected:
248 base::ShadowingAtExitManager at_exit_;
249 base::MessageLoop loop_;
250 TestContext context_;
251 scoped_ptr<TestClientImpl> test_client_;
252 scoped_ptr<ServiceManager> service_manager_;
253 DISALLOW_COPY_AND_ASSIGN(ServiceManagerTest);
254 };
255
TEST_F(ServiceManagerTest,Basic)256 TEST_F(ServiceManagerTest, Basic) {
257 test_client_->Test("test");
258 loop_.Run();
259 EXPECT_EQ(std::string("test"), context_.last_test_string);
260 }
261
TEST_F(ServiceManagerTest,ClientError)262 TEST_F(ServiceManagerTest, ClientError) {
263 test_client_->Test("test");
264 EXPECT_TRUE(HasFactoryForTestURL());
265 loop_.Run();
266 EXPECT_EQ(1, context_.num_impls);
267 test_client_.reset(NULL);
268 loop_.Run();
269 EXPECT_EQ(0, context_.num_impls);
270 EXPECT_TRUE(HasFactoryForTestURL());
271 }
272
TEST_F(ServiceManagerTest,Deletes)273 TEST_F(ServiceManagerTest, Deletes) {
274 {
275 ServiceManager sm;
276 TestServiceLoader* default_loader = new TestServiceLoader;
277 default_loader->set_context(&context_);
278 TestServiceLoader* url_loader1 = new TestServiceLoader;
279 TestServiceLoader* url_loader2 = new TestServiceLoader;
280 url_loader1->set_context(&context_);
281 url_loader2->set_context(&context_);
282 TestServiceLoader* scheme_loader1 = new TestServiceLoader;
283 TestServiceLoader* scheme_loader2 = new TestServiceLoader;
284 scheme_loader1->set_context(&context_);
285 scheme_loader2->set_context(&context_);
286 sm.set_default_loader(scoped_ptr<ServiceLoader>(default_loader));
287 sm.SetLoaderForURL(scoped_ptr<ServiceLoader>(url_loader1),
288 GURL("test:test1"));
289 sm.SetLoaderForURL(scoped_ptr<ServiceLoader>(url_loader2),
290 GURL("test:test1"));
291 sm.SetLoaderForScheme(scoped_ptr<ServiceLoader>(scheme_loader1), "test");
292 sm.SetLoaderForScheme(scoped_ptr<ServiceLoader>(scheme_loader2), "test");
293 }
294 EXPECT_EQ(5, context_.num_loader_deletes);
295 }
296
297 // Confirm that both urls and schemes can have their loaders explicitly set.
TEST_F(ServiceManagerTest,SetLoaders)298 TEST_F(ServiceManagerTest, SetLoaders) {
299 ServiceManager sm;
300 TestServiceLoader* default_loader = new TestServiceLoader;
301 TestServiceLoader* url_loader = new TestServiceLoader;
302 TestServiceLoader* scheme_loader = new TestServiceLoader;
303 sm.set_default_loader(scoped_ptr<ServiceLoader>(default_loader));
304 sm.SetLoaderForURL(scoped_ptr<ServiceLoader>(url_loader), GURL("test:test1"));
305 sm.SetLoaderForScheme(scoped_ptr<ServiceLoader>(scheme_loader), "test");
306
307 // test::test1 should go to url_loader.
308 TestServicePtr test_service;
309 sm.ConnectTo(GURL("test:test1"), &test_service, GURL());
310 EXPECT_EQ(1, url_loader->num_loads());
311 EXPECT_EQ(0, scheme_loader->num_loads());
312 EXPECT_EQ(0, default_loader->num_loads());
313
314 // test::test2 should go to scheme loader.
315 sm.ConnectTo(GURL("test:test2"), &test_service, GURL());
316 EXPECT_EQ(1, url_loader->num_loads());
317 EXPECT_EQ(1, scheme_loader->num_loads());
318 EXPECT_EQ(0, default_loader->num_loads());
319
320 // http::test1 should go to default loader.
321 sm.ConnectTo(GURL("http:test1"), &test_service, GURL());
322 EXPECT_EQ(1, url_loader->num_loads());
323 EXPECT_EQ(1, scheme_loader->num_loads());
324 EXPECT_EQ(1, default_loader->num_loads());
325 }
326
327 // Confirm that the url of a service is correctly passed to another service that
328 // it loads.
TEST_F(ServiceManagerTest,ALoadB)329 TEST_F(ServiceManagerTest, ALoadB) {
330 ServiceManager sm;
331
332 // Any url can load a.
333 TestApp* a_app = new TestApp(std::string());
334 a_app->AddService<TestAImpl>(a_app);
335 sm.SetLoaderForURL(scoped_ptr<ServiceLoader>(a_app), GURL(kTestAURLString));
336
337 // Only a can load b.
338 TestApp* b_app = new TestApp(kTestAURLString);
339 b_app->AddService<TestBImpl>();
340 sm.SetLoaderForURL(scoped_ptr<ServiceLoader>(b_app), GURL(kTestBURLString));
341
342 TestAPtr a;
343 sm.ConnectTo(GURL(kTestAURLString), &a, GURL());
344 a->LoadB();
345 loop_.Run();
346 EXPECT_EQ(1, b_app->num_connects());
347 }
348
349 // Confirm that the url of a service is correctly passed to another service that
350 // it loads, and that it can be rejected.
TEST_F(ServiceManagerTest,ANoLoadB)351 TEST_F(ServiceManagerTest, ANoLoadB) {
352 ServiceManager sm;
353
354 // Any url can load a.
355 TestApp* a_app = new TestApp(std::string());
356 a_app->AddService<TestAImpl>(a_app);
357 sm.SetLoaderForURL(scoped_ptr<ServiceLoader>(a_app), GURL(kTestAURLString));
358
359 // Only c can load b, so this will fail.
360 TestApp* b_app = new TestApp("test:TestC");
361 b_app->AddService<TestBImpl>();
362 sm.SetLoaderForURL(scoped_ptr<ServiceLoader>(b_app), GURL(kTestBURLString));
363
364 TestAPtr a;
365 sm.ConnectTo(GURL(kTestAURLString), &a, GURL());
366 a->LoadB();
367 loop_.Run();
368 EXPECT_EQ(0, b_app->num_connects());
369 }
370
TEST_F(ServiceManagerTest,NoServiceNoLoad)371 TEST_F(ServiceManagerTest, NoServiceNoLoad) {
372 ServiceManager sm;
373
374 TestApp* b_app = new TestApp(std::string());
375 b_app->AddService<TestBImpl>();
376 sm.SetLoaderForURL(scoped_ptr<ServiceLoader>(b_app), GURL(kTestBURLString));
377
378 // There is no TestA service implementation registered with ServiceManager,
379 // so this cannot succeed (but also shouldn't crash).
380 TestAPtr a;
381 sm.ConnectTo(GURL(kTestBURLString), &a, GURL());
382 QuitMessageLoopErrorHandler quitter;
383 a.set_error_handler(&quitter);
384 a->LoadB();
385
386 loop_.Run();
387 EXPECT_TRUE(a.encountered_error());
388 EXPECT_EQ(0, b_app->num_connects());
389 }
390
TEST_F(ServiceManagerTest,Interceptor)391 TEST_F(ServiceManagerTest, Interceptor) {
392 ServiceManager sm;
393 TestServiceInterceptor interceptor;
394 TestServiceLoader* default_loader = new TestServiceLoader;
395 sm.set_default_loader(scoped_ptr<ServiceLoader>(default_loader));
396 sm.SetInterceptor(&interceptor);
397
398 std::string url("test:test3");
399 TestServicePtr test_service;
400 sm.ConnectTo(GURL(url), &test_service, GURL());
401 EXPECT_EQ(1, interceptor.call_count());
402 EXPECT_EQ(url, interceptor.url_spec());
403 EXPECT_EQ(1, default_loader->num_loads());
404 }
405
406 } // namespace mojo
407