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.
5 #include "base/at_exit.h"
7 #include "base/message_loop/message_loop.h"
8 #include "mojo/application_manager/application_loader.h"
9 #include "mojo/application_manager/application_manager.h"
10 #include "mojo/application_manager/background_shell_application_loader.h"
11 #include "mojo/application_manager/test.mojom.h"
12 #include "mojo/public/cpp/application/application_connection.h"
13 #include "mojo/public/cpp/application/application_delegate.h"
14 #include "mojo/public/cpp/application/application_impl.h"
15 #include "mojo/public/cpp/application/interface_factory.h"
16 #include "mojo/public/interfaces/application/service_provider.mojom.h"
17 #include "testing/gtest/include/gtest/gtest.h"
22 const char kTestURLString
[] = "test:testService";
23 const char kTestAURLString
[] = "test:TestA";
24 const char kTestBURLString
[] = "test:TestB";
27 TestContext() : num_impls(0), num_loader_deletes(0) {}
28 std::string last_test_string
;
30 int num_loader_deletes
;
33 class QuitMessageLoopErrorHandler
: public ErrorHandler
{
35 QuitMessageLoopErrorHandler() {}
36 virtual ~QuitMessageLoopErrorHandler() {}
38 // |ErrorHandler| implementation:
39 virtual void OnConnectionError() OVERRIDE
{
40 base::MessageLoop::current()->QuitWhenIdle();
44 DISALLOW_COPY_AND_ASSIGN(QuitMessageLoopErrorHandler
);
47 class TestServiceImpl
: public InterfaceImpl
<TestService
> {
49 explicit TestServiceImpl(TestContext
* context
) : context_(context
) {
50 ++context_
->num_impls
;
53 virtual ~TestServiceImpl() { --context_
->num_impls
; }
55 virtual void OnConnectionError() OVERRIDE
{
56 if (!base::MessageLoop::current()->is_running())
58 base::MessageLoop::current()->Quit();
61 // TestService implementation:
62 virtual void Test(const String
& test_string
) OVERRIDE
{
63 context_
->last_test_string
= test_string
;
68 TestContext
* context_
;
71 class TestClientImpl
: public TestClient
{
73 explicit TestClientImpl(TestServicePtr service
)
74 : service_(service
.Pass()), quit_after_ack_(false) {
75 service_
.set_client(this);
78 virtual ~TestClientImpl() { service_
.reset(); }
80 virtual void AckTest() OVERRIDE
{
82 base::MessageLoop::current()->Quit();
85 void Test(std::string test_string
) {
86 quit_after_ack_
= true;
87 service_
->Test(test_string
);
91 TestServicePtr service_
;
93 DISALLOW_COPY_AND_ASSIGN(TestClientImpl
);
96 class TestApplicationLoader
: public ApplicationLoader
,
97 public ApplicationDelegate
,
98 public InterfaceFactory
<TestService
> {
100 TestApplicationLoader() : context_(NULL
), num_loads_(0) {}
102 virtual ~TestApplicationLoader() {
104 ++context_
->num_loader_deletes
;
105 test_app_
.reset(NULL
);
108 void set_context(TestContext
* context
) { context_
= context
; }
109 int num_loads() const { return num_loads_
; }
112 // ApplicationLoader implementation.
113 virtual void Load(ApplicationManager
* manager
,
115 scoped_refptr
<LoadCallbacks
> callbacks
) OVERRIDE
{
118 new ApplicationImpl(this, callbacks
->RegisterApplication().Pass()));
121 virtual void OnApplicationError(ApplicationManager
* manager
,
122 const GURL
& url
) OVERRIDE
{}
124 // ApplicationDelegate implementation.
125 virtual bool ConfigureIncomingConnection(
126 ApplicationConnection
* connection
) OVERRIDE
{
127 connection
->AddService(this);
131 // InterfaceFactory implementation.
132 virtual void Create(ApplicationConnection
* connection
,
133 InterfaceRequest
<TestService
> request
) OVERRIDE
{
134 BindToRequest(new TestServiceImpl(context_
), &request
);
137 scoped_ptr
<ApplicationImpl
> test_app_
;
138 TestContext
* context_
;
140 DISALLOW_COPY_AND_ASSIGN(TestApplicationLoader
);
143 class TesterContext
{
145 explicit TesterContext(base::MessageLoop
* loop
)
151 tester_called_quit_(false),
152 a_called_quit_(false),
155 void IncrementNumBCalls() {
156 base::AutoLock
lock(lock_
);
160 void IncrementNumCCalls() {
161 base::AutoLock
lock(lock_
);
165 void IncrementNumADeletes() {
166 base::AutoLock
lock(lock_
);
170 void IncrementNumBDeletes() {
171 base::AutoLock
lock(lock_
);
175 void IncrementNumCDeletes() {
176 base::AutoLock
lock(lock_
);
180 void set_tester_called_quit() {
181 base::AutoLock
lock(lock_
);
182 tester_called_quit_
= true;
185 void set_a_called_quit() {
186 base::AutoLock
lock(lock_
);
187 a_called_quit_
= true;
191 base::AutoLock
lock(lock_
);
195 base::AutoLock
lock(lock_
);
198 int num_a_deletes() {
199 base::AutoLock
lock(lock_
);
200 return num_a_deletes_
;
202 int num_b_deletes() {
203 base::AutoLock
lock(lock_
);
204 return num_b_deletes_
;
206 int num_c_deletes() {
207 base::AutoLock
lock(lock_
);
208 return num_c_deletes_
;
210 bool tester_called_quit() {
211 base::AutoLock
lock(lock_
);
212 return tester_called_quit_
;
214 bool a_called_quit() {
215 base::AutoLock
lock(lock_
);
216 return a_called_quit_
;
220 loop_
->PostTask(FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
224 // lock_ protects all members except for loop_ which must be unchanged for the
225 // lifetime of this class.
232 bool tester_called_quit_
;
235 base::MessageLoop
* loop_
;
238 // Used to test that the requestor url will be correctly passed.
239 class TestAImpl
: public InterfaceImpl
<TestA
> {
241 TestAImpl(ApplicationConnection
* connection
, TesterContext
* test_context
)
242 : test_context_(test_context
) {
243 connection
->ConnectToApplication(kTestBURLString
)->ConnectToService(&b_
);
245 virtual ~TestAImpl() {
246 test_context_
->IncrementNumADeletes();
247 if (base::MessageLoop::current()->is_running())
252 virtual void CallB() OVERRIDE
{
253 b_
->B(base::Bind(&TestAImpl::Quit
, base::Unretained(this)));
256 virtual void CallCFromB() OVERRIDE
{
257 b_
->CallC(base::Bind(&TestAImpl::Quit
, base::Unretained(this)));
261 base::MessageLoop::current()->Quit();
262 test_context_
->set_a_called_quit();
263 test_context_
->QuitSoon();
266 TesterContext
* test_context_
;
270 class TestBImpl
: public InterfaceImpl
<TestB
> {
272 TestBImpl(ApplicationConnection
* connection
, TesterContext
* test_context
)
273 : test_context_(test_context
) {
274 connection
->ConnectToService(&c_
);
277 virtual ~TestBImpl() {
278 test_context_
->IncrementNumBDeletes();
279 if (base::MessageLoop::current()->is_running())
280 base::MessageLoop::current()->Quit();
281 test_context_
->QuitSoon();
285 virtual void B(const mojo::Callback
<void()>& callback
) OVERRIDE
{
286 test_context_
->IncrementNumBCalls();
290 virtual void CallC(const mojo::Callback
<void()>& callback
) OVERRIDE
{
291 test_context_
->IncrementNumBCalls();
295 TesterContext
* test_context_
;
299 class TestCImpl
: public InterfaceImpl
<TestC
> {
301 TestCImpl(ApplicationConnection
* connection
, TesterContext
* test_context
)
302 : test_context_(test_context
) {}
304 virtual ~TestCImpl() { test_context_
->IncrementNumCDeletes(); }
307 virtual void C(const mojo::Callback
<void()>& callback
) OVERRIDE
{
308 test_context_
->IncrementNumCCalls();
311 TesterContext
* test_context_
;
314 class Tester
: public ApplicationDelegate
,
315 public ApplicationLoader
,
316 public InterfaceFactory
<TestA
>,
317 public InterfaceFactory
<TestB
>,
318 public InterfaceFactory
<TestC
> {
320 Tester(TesterContext
* context
, const std::string
& requestor_url
)
321 : context_(context
), requestor_url_(requestor_url
) {}
325 virtual void Load(ApplicationManager
* manager
,
327 scoped_refptr
<LoadCallbacks
> callbacks
) OVERRIDE
{
329 new ApplicationImpl(this, callbacks
->RegisterApplication().Pass()));
332 virtual void OnApplicationError(ApplicationManager
* manager
,
333 const GURL
& url
) OVERRIDE
{}
335 virtual bool ConfigureIncomingConnection(
336 ApplicationConnection
* connection
) OVERRIDE
{
337 if (!requestor_url_
.empty() &&
338 requestor_url_
!= connection
->GetRemoteApplicationURL()) {
339 context_
->set_tester_called_quit();
340 context_
->QuitSoon();
341 base::MessageLoop::current()->Quit();
344 // If we're coming from A, then add B, otherwise A.
345 if (connection
->GetRemoteApplicationURL() == kTestAURLString
)
346 connection
->AddService
<TestB
>(this);
348 connection
->AddService
<TestA
>(this);
352 virtual bool ConfigureOutgoingConnection(
353 ApplicationConnection
* connection
) OVERRIDE
{
354 // If we're connecting to B, then add C.
355 if (connection
->GetRemoteApplicationURL() == kTestBURLString
)
356 connection
->AddService
<TestC
>(this);
360 virtual void Create(ApplicationConnection
* connection
,
361 InterfaceRequest
<TestA
> request
) OVERRIDE
{
362 BindToRequest(new TestAImpl(connection
, context_
), &request
);
365 virtual void Create(ApplicationConnection
* connection
,
366 InterfaceRequest
<TestB
> request
) OVERRIDE
{
367 BindToRequest(new TestBImpl(connection
, context_
), &request
);
370 virtual void Create(ApplicationConnection
* connection
,
371 InterfaceRequest
<TestC
> request
) OVERRIDE
{
372 BindToRequest(new TestCImpl(connection
, context_
), &request
);
375 TesterContext
* context_
;
376 scoped_ptr
<ApplicationImpl
> app_
;
377 std::string requestor_url_
;
380 class TestServiceInterceptor
: public ApplicationManager::Interceptor
{
382 TestServiceInterceptor() : call_count_(0) {}
384 virtual ServiceProviderPtr
OnConnectToClient(
386 ServiceProviderPtr service_provider
) OVERRIDE
{
389 return service_provider
.Pass();
392 std::string
url_spec() const {
393 if (!url_
.is_valid())
394 return "invalid url";
398 int call_count() const { return call_count_
; }
403 DISALLOW_COPY_AND_ASSIGN(TestServiceInterceptor
);
408 class ApplicationManagerTest
: public testing::Test
{
410 ApplicationManagerTest() : tester_context_(&loop_
) {}
412 virtual ~ApplicationManagerTest() {}
414 virtual void SetUp() OVERRIDE
{
415 application_manager_
.reset(new ApplicationManager
);
416 TestApplicationLoader
* default_loader
= new TestApplicationLoader
;
417 default_loader
->set_context(&context_
);
418 application_manager_
->set_default_loader(
419 scoped_ptr
<ApplicationLoader
>(default_loader
));
421 TestServicePtr service_proxy
;
422 application_manager_
->ConnectToService(GURL(kTestURLString
),
424 test_client_
.reset(new TestClientImpl(service_proxy
.Pass()));
427 virtual void TearDown() OVERRIDE
{
428 test_client_
.reset(NULL
);
429 application_manager_
.reset(NULL
);
432 scoped_ptr
<BackgroundShellApplicationLoader
> MakeLoader(
433 const std::string
& requestor_url
) {
434 scoped_ptr
<ApplicationLoader
> real_loader(
435 new Tester(&tester_context_
, requestor_url
));
436 scoped_ptr
<BackgroundShellApplicationLoader
> loader(
437 new BackgroundShellApplicationLoader(real_loader
.Pass(),
439 base::MessageLoop::TYPE_DEFAULT
));
440 return loader
.Pass();
443 void AddLoaderForURL(const GURL
& url
, const std::string
& requestor_url
) {
444 application_manager_
->SetLoaderForURL(
445 MakeLoader(requestor_url
).PassAs
<ApplicationLoader
>(), url
);
448 bool HasFactoryForTestURL() {
449 ApplicationManager::TestAPI
manager_test_api(application_manager_
.get());
450 return manager_test_api
.HasFactoryForURL(GURL(kTestURLString
));
454 base::ShadowingAtExitManager at_exit_
;
455 TesterContext tester_context_
;
456 TestContext context_
;
457 base::MessageLoop loop_
;
458 scoped_ptr
<TestClientImpl
> test_client_
;
459 scoped_ptr
<ApplicationManager
> application_manager_
;
460 DISALLOW_COPY_AND_ASSIGN(ApplicationManagerTest
);
463 TEST_F(ApplicationManagerTest
, Basic
) {
464 test_client_
->Test("test");
466 EXPECT_EQ(std::string("test"), context_
.last_test_string
);
469 TEST_F(ApplicationManagerTest
, ClientError
) {
470 test_client_
->Test("test");
471 EXPECT_TRUE(HasFactoryForTestURL());
473 EXPECT_EQ(1, context_
.num_impls
);
474 test_client_
.reset(NULL
);
476 EXPECT_EQ(0, context_
.num_impls
);
477 EXPECT_TRUE(HasFactoryForTestURL());
480 TEST_F(ApplicationManagerTest
, Deletes
) {
482 ApplicationManager sm
;
483 TestApplicationLoader
* default_loader
= new TestApplicationLoader
;
484 default_loader
->set_context(&context_
);
485 TestApplicationLoader
* url_loader1
= new TestApplicationLoader
;
486 TestApplicationLoader
* url_loader2
= new TestApplicationLoader
;
487 url_loader1
->set_context(&context_
);
488 url_loader2
->set_context(&context_
);
489 TestApplicationLoader
* scheme_loader1
= new TestApplicationLoader
;
490 TestApplicationLoader
* scheme_loader2
= new TestApplicationLoader
;
491 scheme_loader1
->set_context(&context_
);
492 scheme_loader2
->set_context(&context_
);
493 sm
.set_default_loader(scoped_ptr
<ApplicationLoader
>(default_loader
));
494 sm
.SetLoaderForURL(scoped_ptr
<ApplicationLoader
>(url_loader1
),
496 sm
.SetLoaderForURL(scoped_ptr
<ApplicationLoader
>(url_loader2
),
498 sm
.SetLoaderForScheme(scoped_ptr
<ApplicationLoader
>(scheme_loader1
),
500 sm
.SetLoaderForScheme(scoped_ptr
<ApplicationLoader
>(scheme_loader2
),
503 EXPECT_EQ(5, context_
.num_loader_deletes
);
506 // Confirm that both urls and schemes can have their loaders explicitly set.
507 TEST_F(ApplicationManagerTest
, SetLoaders
) {
508 ApplicationManager sm
;
509 TestApplicationLoader
* default_loader
= new TestApplicationLoader
;
510 TestApplicationLoader
* url_loader
= new TestApplicationLoader
;
511 TestApplicationLoader
* scheme_loader
= new TestApplicationLoader
;
512 application_manager_
->set_default_loader(
513 scoped_ptr
<ApplicationLoader
>(default_loader
));
514 application_manager_
->SetLoaderForURL(
515 scoped_ptr
<ApplicationLoader
>(url_loader
), GURL("test:test1"));
516 application_manager_
->SetLoaderForScheme(
517 scoped_ptr
<ApplicationLoader
>(scheme_loader
), "test");
519 // test::test1 should go to url_loader.
520 TestServicePtr test_service
;
521 application_manager_
->ConnectToService(GURL("test:test1"), &test_service
);
522 EXPECT_EQ(1, url_loader
->num_loads());
523 EXPECT_EQ(0, scheme_loader
->num_loads());
524 EXPECT_EQ(0, default_loader
->num_loads());
526 // test::test2 should go to scheme loader.
527 application_manager_
->ConnectToService(GURL("test:test2"), &test_service
);
528 EXPECT_EQ(1, url_loader
->num_loads());
529 EXPECT_EQ(1, scheme_loader
->num_loads());
530 EXPECT_EQ(0, default_loader
->num_loads());
532 // http::test1 should go to default loader.
533 application_manager_
->ConnectToService(GURL("http:test1"), &test_service
);
534 EXPECT_EQ(1, url_loader
->num_loads());
535 EXPECT_EQ(1, scheme_loader
->num_loads());
536 EXPECT_EQ(1, default_loader
->num_loads());
539 // Confirm that the url of a service is correctly passed to another service that
541 TEST_F(ApplicationManagerTest
, ACallB
) {
542 // Any url can load a.
543 AddLoaderForURL(GURL(kTestAURLString
), std::string());
545 // Only a can load b.
546 AddLoaderForURL(GURL(kTestBURLString
), kTestAURLString
);
549 application_manager_
->ConnectToService(GURL(kTestAURLString
), &a
);
552 EXPECT_EQ(1, tester_context_
.num_b_calls());
553 EXPECT_TRUE(tester_context_
.a_called_quit());
556 // A calls B which calls C.
557 TEST_F(ApplicationManagerTest
, BCallC
) {
558 // Any url can load a.
559 AddLoaderForURL(GURL(kTestAURLString
), std::string());
561 // Only a can load b.
562 AddLoaderForURL(GURL(kTestBURLString
), kTestAURLString
);
565 application_manager_
->ConnectToService(GURL(kTestAURLString
), &a
);
569 EXPECT_EQ(1, tester_context_
.num_b_calls());
570 EXPECT_EQ(1, tester_context_
.num_c_calls());
571 EXPECT_TRUE(tester_context_
.a_called_quit());
574 // Confirm that a service impl will be deleted if the app that connected to
576 TEST_F(ApplicationManagerTest
, BDeleted
) {
577 AddLoaderForURL(GURL(kTestAURLString
), std::string());
578 AddLoaderForURL(GURL(kTestBURLString
), std::string());
581 application_manager_
->ConnectToService(GURL(kTestAURLString
), &a
);
587 application_manager_
->SetLoaderForURL(scoped_ptr
<ApplicationLoader
>(),
588 GURL(kTestAURLString
));
591 EXPECT_EQ(1, tester_context_
.num_b_deletes());
594 // Confirm that the url of a service is correctly passed to another service that
595 // it loads, and that it can be rejected.
596 TEST_F(ApplicationManagerTest
, ANoLoadB
) {
597 // Any url can load a.
598 AddLoaderForURL(GURL(kTestAURLString
), std::string());
600 // Only c can load b, so this will fail.
601 AddLoaderForURL(GURL(kTestBURLString
), "test:TestC");
604 application_manager_
->ConnectToService(GURL(kTestAURLString
), &a
);
607 EXPECT_EQ(0, tester_context_
.num_b_calls());
609 EXPECT_FALSE(tester_context_
.a_called_quit());
610 EXPECT_TRUE(tester_context_
.tester_called_quit());
613 TEST_F(ApplicationManagerTest
, NoServiceNoLoad
) {
614 AddLoaderForURL(GURL(kTestAURLString
), std::string());
616 // There is no TestC service implementation registered with
617 // ApplicationManager, so this cannot succeed (but also shouldn't crash).
619 application_manager_
->ConnectToService(GURL(kTestAURLString
), &c
);
620 QuitMessageLoopErrorHandler quitter
;
621 c
.set_error_handler(&quitter
);
624 EXPECT_TRUE(c
.encountered_error());
627 TEST_F(ApplicationManagerTest
, Interceptor
) {
628 TestServiceInterceptor interceptor
;
629 TestApplicationLoader
* default_loader
= new TestApplicationLoader
;
630 application_manager_
->set_default_loader(
631 scoped_ptr
<ApplicationLoader
>(default_loader
));
632 application_manager_
->SetInterceptor(&interceptor
);
634 std::string
url("test:test3");
635 TestServicePtr test_service
;
636 application_manager_
->ConnectToService(GURL(url
), &test_service
);
638 EXPECT_EQ(1, interceptor
.call_count());
639 EXPECT_EQ(url
, interceptor
.url_spec());
640 EXPECT_EQ(1, default_loader
->num_loads());