• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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