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/macros.h"
8 #include "base/message_loop/message_loop.h"
9 #include "mojo/application_manager/application_loader.h"
10 #include "mojo/application_manager/application_manager.h"
11 #include "mojo/application_manager/background_shell_application_loader.h"
12 #include "mojo/application_manager/test.mojom.h"
13 #include "mojo/public/cpp/application/application_connection.h"
14 #include "mojo/public/cpp/application/application_delegate.h"
15 #include "mojo/public/cpp/application/application_impl.h"
16 #include "mojo/public/cpp/application/interface_factory.h"
17 #include "mojo/public/interfaces/application/service_provider.mojom.h"
18 #include "testing/gtest/include/gtest/gtest.h"
23 const char kTestURLString
[] = "test:testService";
24 const char kTestAURLString
[] = "test:TestA";
25 const char kTestBURLString
[] = "test:TestB";
28 TestContext() : num_impls(0), num_loader_deletes(0) {}
29 std::string last_test_string
;
31 int num_loader_deletes
;
34 class QuitMessageLoopErrorHandler
: public ErrorHandler
{
36 QuitMessageLoopErrorHandler() {}
37 virtual ~QuitMessageLoopErrorHandler() {}
39 // |ErrorHandler| implementation:
40 virtual void OnConnectionError() override
{
41 base::MessageLoop::current()->QuitWhenIdle();
45 DISALLOW_COPY_AND_ASSIGN(QuitMessageLoopErrorHandler
);
48 class TestServiceImpl
: public InterfaceImpl
<TestService
> {
50 explicit TestServiceImpl(TestContext
* context
) : context_(context
) {
51 ++context_
->num_impls
;
54 virtual ~TestServiceImpl() { --context_
->num_impls
; }
56 virtual void OnConnectionError() override
{
57 if (!base::MessageLoop::current()->is_running())
59 base::MessageLoop::current()->Quit();
62 // TestService implementation:
63 virtual void Test(const String
& test_string
) override
{
64 context_
->last_test_string
= test_string
;
69 TestContext
* context_
;
72 class TestClientImpl
: public TestClient
{
74 explicit TestClientImpl(TestServicePtr service
)
75 : service_(service
.Pass()), quit_after_ack_(false) {
76 service_
.set_client(this);
79 virtual ~TestClientImpl() { service_
.reset(); }
81 virtual void AckTest() override
{
83 base::MessageLoop::current()->Quit();
86 void Test(std::string test_string
) {
87 quit_after_ack_
= true;
88 service_
->Test(test_string
);
92 TestServicePtr service_
;
94 DISALLOW_COPY_AND_ASSIGN(TestClientImpl
);
97 class TestApplicationLoader
: public ApplicationLoader
,
98 public ApplicationDelegate
,
99 public InterfaceFactory
<TestService
> {
101 TestApplicationLoader() : context_(NULL
), num_loads_(0) {}
103 virtual ~TestApplicationLoader() {
105 ++context_
->num_loader_deletes
;
106 test_app_
.reset(NULL
);
109 void set_context(TestContext
* context
) { context_
= context
; }
110 int num_loads() const { return num_loads_
; }
111 const std::vector
<std::string
>& GetArgs() { return test_app_
->args(); }
114 // ApplicationLoader implementation.
115 virtual void Load(ApplicationManager
* manager
,
117 scoped_refptr
<LoadCallbacks
> callbacks
) override
{
120 new ApplicationImpl(this, callbacks
->RegisterApplication().Pass()));
123 virtual void OnApplicationError(ApplicationManager
* manager
,
124 const GURL
& url
) override
{}
126 // ApplicationDelegate implementation.
127 virtual bool ConfigureIncomingConnection(
128 ApplicationConnection
* connection
) override
{
129 connection
->AddService(this);
133 // InterfaceFactory implementation.
134 virtual void Create(ApplicationConnection
* connection
,
135 InterfaceRequest
<TestService
> request
) override
{
136 BindToRequest(new TestServiceImpl(context_
), &request
);
139 scoped_ptr
<ApplicationImpl
> test_app_
;
140 TestContext
* context_
;
142 DISALLOW_COPY_AND_ASSIGN(TestApplicationLoader
);
145 class TesterContext
{
147 explicit TesterContext(base::MessageLoop
* loop
)
153 tester_called_quit_(false),
154 a_called_quit_(false),
157 void IncrementNumBCalls() {
158 base::AutoLock
lock(lock_
);
162 void IncrementNumCCalls() {
163 base::AutoLock
lock(lock_
);
167 void IncrementNumADeletes() {
168 base::AutoLock
lock(lock_
);
172 void IncrementNumBDeletes() {
173 base::AutoLock
lock(lock_
);
177 void IncrementNumCDeletes() {
178 base::AutoLock
lock(lock_
);
182 void set_tester_called_quit() {
183 base::AutoLock
lock(lock_
);
184 tester_called_quit_
= true;
187 void set_a_called_quit() {
188 base::AutoLock
lock(lock_
);
189 a_called_quit_
= true;
193 base::AutoLock
lock(lock_
);
197 base::AutoLock
lock(lock_
);
200 int num_a_deletes() {
201 base::AutoLock
lock(lock_
);
202 return num_a_deletes_
;
204 int num_b_deletes() {
205 base::AutoLock
lock(lock_
);
206 return num_b_deletes_
;
208 int num_c_deletes() {
209 base::AutoLock
lock(lock_
);
210 return num_c_deletes_
;
212 bool tester_called_quit() {
213 base::AutoLock
lock(lock_
);
214 return tester_called_quit_
;
216 bool a_called_quit() {
217 base::AutoLock
lock(lock_
);
218 return a_called_quit_
;
222 loop_
->PostTask(FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
226 // lock_ protects all members except for loop_ which must be unchanged for the
227 // lifetime of this class.
234 bool tester_called_quit_
;
237 base::MessageLoop
* loop_
;
240 // Used to test that the requestor url will be correctly passed.
241 class TestAImpl
: public InterfaceImpl
<TestA
> {
243 TestAImpl(ApplicationConnection
* connection
, TesterContext
* test_context
)
244 : test_context_(test_context
) {
245 connection
->ConnectToApplication(kTestBURLString
)->ConnectToService(&b_
);
247 virtual ~TestAImpl() {
248 test_context_
->IncrementNumADeletes();
249 if (base::MessageLoop::current()->is_running())
254 virtual void CallB() override
{
255 b_
->B(base::Bind(&TestAImpl::Quit
, base::Unretained(this)));
258 virtual void CallCFromB() override
{
259 b_
->CallC(base::Bind(&TestAImpl::Quit
, base::Unretained(this)));
263 base::MessageLoop::current()->Quit();
264 test_context_
->set_a_called_quit();
265 test_context_
->QuitSoon();
268 TesterContext
* test_context_
;
272 class TestBImpl
: public InterfaceImpl
<TestB
> {
274 TestBImpl(ApplicationConnection
* connection
, TesterContext
* test_context
)
275 : test_context_(test_context
) {
276 connection
->ConnectToService(&c_
);
279 virtual ~TestBImpl() {
280 test_context_
->IncrementNumBDeletes();
281 if (base::MessageLoop::current()->is_running())
282 base::MessageLoop::current()->Quit();
283 test_context_
->QuitSoon();
287 virtual void B(const mojo::Callback
<void()>& callback
) override
{
288 test_context_
->IncrementNumBCalls();
292 virtual void CallC(const mojo::Callback
<void()>& callback
) override
{
293 test_context_
->IncrementNumBCalls();
297 TesterContext
* test_context_
;
301 class TestCImpl
: public InterfaceImpl
<TestC
> {
303 TestCImpl(ApplicationConnection
* connection
, TesterContext
* test_context
)
304 : test_context_(test_context
) {}
306 virtual ~TestCImpl() { test_context_
->IncrementNumCDeletes(); }
309 virtual void C(const mojo::Callback
<void()>& callback
) override
{
310 test_context_
->IncrementNumCCalls();
313 TesterContext
* test_context_
;
316 class Tester
: public ApplicationDelegate
,
317 public ApplicationLoader
,
318 public InterfaceFactory
<TestA
>,
319 public InterfaceFactory
<TestB
>,
320 public InterfaceFactory
<TestC
> {
322 Tester(TesterContext
* context
, const std::string
& requestor_url
)
323 : context_(context
), requestor_url_(requestor_url
) {}
327 virtual void Load(ApplicationManager
* manager
,
329 scoped_refptr
<LoadCallbacks
> callbacks
) override
{
331 new ApplicationImpl(this, callbacks
->RegisterApplication().Pass()));
334 virtual void OnApplicationError(ApplicationManager
* manager
,
335 const GURL
& url
) override
{}
337 virtual bool ConfigureIncomingConnection(
338 ApplicationConnection
* connection
) override
{
339 if (!requestor_url_
.empty() &&
340 requestor_url_
!= connection
->GetRemoteApplicationURL()) {
341 context_
->set_tester_called_quit();
342 context_
->QuitSoon();
343 base::MessageLoop::current()->Quit();
346 // If we're coming from A, then add B, otherwise A.
347 if (connection
->GetRemoteApplicationURL() == kTestAURLString
)
348 connection
->AddService
<TestB
>(this);
350 connection
->AddService
<TestA
>(this);
354 virtual bool ConfigureOutgoingConnection(
355 ApplicationConnection
* connection
) override
{
356 // If we're connecting to B, then add C.
357 if (connection
->GetRemoteApplicationURL() == kTestBURLString
)
358 connection
->AddService
<TestC
>(this);
362 virtual void Create(ApplicationConnection
* connection
,
363 InterfaceRequest
<TestA
> request
) override
{
364 BindToRequest(new TestAImpl(connection
, context_
), &request
);
367 virtual void Create(ApplicationConnection
* connection
,
368 InterfaceRequest
<TestB
> request
) override
{
369 BindToRequest(new TestBImpl(connection
, context_
), &request
);
372 virtual void Create(ApplicationConnection
* connection
,
373 InterfaceRequest
<TestC
> request
) override
{
374 BindToRequest(new TestCImpl(connection
, context_
), &request
);
377 TesterContext
* context_
;
378 scoped_ptr
<ApplicationImpl
> app_
;
379 std::string requestor_url_
;
382 class TestServiceInterceptor
: public ApplicationManager::Interceptor
{
384 TestServiceInterceptor() : call_count_(0) {}
386 virtual ServiceProviderPtr
OnConnectToClient(
388 ServiceProviderPtr service_provider
) override
{
391 return service_provider
.Pass();
394 std::string
url_spec() const {
395 if (!url_
.is_valid())
396 return "invalid url";
400 int call_count() const { return call_count_
; }
405 DISALLOW_COPY_AND_ASSIGN(TestServiceInterceptor
);
410 class ApplicationManagerTest
: public testing::Test
{
412 ApplicationManagerTest() : tester_context_(&loop_
) {}
414 virtual ~ApplicationManagerTest() {}
416 virtual void SetUp() override
{
417 application_manager_
.reset(new ApplicationManager
);
418 TestApplicationLoader
* default_loader
= new TestApplicationLoader
;
419 default_loader
->set_context(&context_
);
420 application_manager_
->set_default_loader(
421 scoped_ptr
<ApplicationLoader
>(default_loader
));
423 TestServicePtr service_proxy
;
424 application_manager_
->ConnectToService(GURL(kTestURLString
),
426 test_client_
.reset(new TestClientImpl(service_proxy
.Pass()));
429 virtual void TearDown() override
{
430 test_client_
.reset(NULL
);
431 application_manager_
.reset(NULL
);
434 scoped_ptr
<BackgroundShellApplicationLoader
> MakeLoader(
435 const std::string
& requestor_url
) {
436 scoped_ptr
<ApplicationLoader
> real_loader(
437 new Tester(&tester_context_
, requestor_url
));
438 scoped_ptr
<BackgroundShellApplicationLoader
> loader(
439 new BackgroundShellApplicationLoader(real_loader
.Pass(),
441 base::MessageLoop::TYPE_DEFAULT
));
442 return loader
.Pass();
445 void AddLoaderForURL(const GURL
& url
, const std::string
& requestor_url
) {
446 application_manager_
->SetLoaderForURL(MakeLoader(requestor_url
), url
);
449 bool HasFactoryForTestURL() {
450 ApplicationManager::TestAPI
manager_test_api(application_manager_
.get());
451 return manager_test_api
.HasFactoryForURL(GURL(kTestURLString
));
455 base::ShadowingAtExitManager at_exit_
;
456 TesterContext tester_context_
;
457 TestContext context_
;
458 base::MessageLoop loop_
;
459 scoped_ptr
<TestClientImpl
> test_client_
;
460 scoped_ptr
<ApplicationManager
> application_manager_
;
461 DISALLOW_COPY_AND_ASSIGN(ApplicationManagerTest
);
464 TEST_F(ApplicationManagerTest
, Basic
) {
465 test_client_
->Test("test");
467 EXPECT_EQ(std::string("test"), context_
.last_test_string
);
470 // Confirm that no arguments are sent to an application by default.
471 TEST_F(ApplicationManagerTest
, NoArgs
) {
472 ApplicationManager am
;
473 GURL
test_url("test:test");
475 TestApplicationLoader
* loader
= new TestApplicationLoader
;
476 loader
->set_context(&context
);
477 am
.SetLoaderForURL(scoped_ptr
<ApplicationLoader
>(loader
), test_url
);
478 TestServicePtr test_service
;
479 am
.ConnectToService(test_url
, &test_service
);
480 TestClientImpl
test_client(test_service
.Pass());
481 test_client
.Test("test");
483 std::vector
<std::string
> app_args
= loader
->GetArgs();
484 EXPECT_EQ(0U, app_args
.size());
487 // Confirm that arguments are sent to an application.
488 TEST_F(ApplicationManagerTest
, Args
) {
489 ApplicationManager am
;
490 GURL
test_url("test:test");
491 std::vector
<std::string
> args
;
492 args
.push_back("test_arg1");
493 args
.push_back("test_arg2");
494 am
.SetArgsForURL(args
, test_url
);
496 TestApplicationLoader
* loader
= new TestApplicationLoader
;
497 loader
->set_context(&context
);
498 am
.SetLoaderForURL(scoped_ptr
<ApplicationLoader
>(loader
), test_url
);
499 TestServicePtr test_service
;
500 am
.ConnectToService(test_url
, &test_service
);
501 TestClientImpl
test_client(test_service
.Pass());
502 test_client
.Test("test");
504 std::vector
<std::string
> app_args
= loader
->GetArgs();
505 ASSERT_EQ(args
.size(), app_args
.size());
506 EXPECT_EQ(args
[0], app_args
[0]);
507 EXPECT_EQ(args
[1], app_args
[1]);
510 TEST_F(ApplicationManagerTest
, ClientError
) {
511 test_client_
->Test("test");
512 EXPECT_TRUE(HasFactoryForTestURL());
514 EXPECT_EQ(1, context_
.num_impls
);
515 test_client_
.reset(NULL
);
517 EXPECT_EQ(0, context_
.num_impls
);
518 EXPECT_TRUE(HasFactoryForTestURL());
521 TEST_F(ApplicationManagerTest
, Deletes
) {
523 ApplicationManager am
;
524 TestApplicationLoader
* default_loader
= new TestApplicationLoader
;
525 default_loader
->set_context(&context_
);
526 TestApplicationLoader
* url_loader1
= new TestApplicationLoader
;
527 TestApplicationLoader
* url_loader2
= new TestApplicationLoader
;
528 url_loader1
->set_context(&context_
);
529 url_loader2
->set_context(&context_
);
530 TestApplicationLoader
* scheme_loader1
= new TestApplicationLoader
;
531 TestApplicationLoader
* scheme_loader2
= new TestApplicationLoader
;
532 scheme_loader1
->set_context(&context_
);
533 scheme_loader2
->set_context(&context_
);
534 am
.set_default_loader(scoped_ptr
<ApplicationLoader
>(default_loader
));
535 am
.SetLoaderForURL(scoped_ptr
<ApplicationLoader
>(url_loader1
),
537 am
.SetLoaderForURL(scoped_ptr
<ApplicationLoader
>(url_loader2
),
539 am
.SetLoaderForScheme(scoped_ptr
<ApplicationLoader
>(scheme_loader1
),
541 am
.SetLoaderForScheme(scoped_ptr
<ApplicationLoader
>(scheme_loader2
),
544 EXPECT_EQ(5, context_
.num_loader_deletes
);
547 // Confirm that both urls and schemes can have their loaders explicitly set.
548 TEST_F(ApplicationManagerTest
, SetLoaders
) {
549 TestApplicationLoader
* default_loader
= new TestApplicationLoader
;
550 TestApplicationLoader
* url_loader
= new TestApplicationLoader
;
551 TestApplicationLoader
* scheme_loader
= new TestApplicationLoader
;
552 application_manager_
->set_default_loader(
553 scoped_ptr
<ApplicationLoader
>(default_loader
));
554 application_manager_
->SetLoaderForURL(
555 scoped_ptr
<ApplicationLoader
>(url_loader
), GURL("test:test1"));
556 application_manager_
->SetLoaderForScheme(
557 scoped_ptr
<ApplicationLoader
>(scheme_loader
), "test");
559 // test::test1 should go to url_loader.
560 TestServicePtr test_service
;
561 application_manager_
->ConnectToService(GURL("test:test1"), &test_service
);
562 EXPECT_EQ(1, url_loader
->num_loads());
563 EXPECT_EQ(0, scheme_loader
->num_loads());
564 EXPECT_EQ(0, default_loader
->num_loads());
566 // test::test2 should go to scheme loader.
567 application_manager_
->ConnectToService(GURL("test:test2"), &test_service
);
568 EXPECT_EQ(1, url_loader
->num_loads());
569 EXPECT_EQ(1, scheme_loader
->num_loads());
570 EXPECT_EQ(0, default_loader
->num_loads());
572 // http::test1 should go to default loader.
573 application_manager_
->ConnectToService(GURL("http:test1"), &test_service
);
574 EXPECT_EQ(1, url_loader
->num_loads());
575 EXPECT_EQ(1, scheme_loader
->num_loads());
576 EXPECT_EQ(1, default_loader
->num_loads());
579 // Confirm that the url of a service is correctly passed to another service that
581 TEST_F(ApplicationManagerTest
, ACallB
) {
582 // Any url can load a.
583 AddLoaderForURL(GURL(kTestAURLString
), std::string());
585 // Only a can load b.
586 AddLoaderForURL(GURL(kTestBURLString
), kTestAURLString
);
589 application_manager_
->ConnectToService(GURL(kTestAURLString
), &a
);
592 EXPECT_EQ(1, tester_context_
.num_b_calls());
593 EXPECT_TRUE(tester_context_
.a_called_quit());
596 // A calls B which calls C.
597 TEST_F(ApplicationManagerTest
, BCallC
) {
598 // Any url can load a.
599 AddLoaderForURL(GURL(kTestAURLString
), std::string());
601 // Only a can load b.
602 AddLoaderForURL(GURL(kTestBURLString
), kTestAURLString
);
605 application_manager_
->ConnectToService(GURL(kTestAURLString
), &a
);
609 EXPECT_EQ(1, tester_context_
.num_b_calls());
610 EXPECT_EQ(1, tester_context_
.num_c_calls());
611 EXPECT_TRUE(tester_context_
.a_called_quit());
614 // Confirm that a service impl will be deleted if the app that connected to
616 TEST_F(ApplicationManagerTest
, BDeleted
) {
617 AddLoaderForURL(GURL(kTestAURLString
), std::string());
618 AddLoaderForURL(GURL(kTestBURLString
), std::string());
621 application_manager_
->ConnectToService(GURL(kTestAURLString
), &a
);
627 application_manager_
->SetLoaderForURL(scoped_ptr
<ApplicationLoader
>(),
628 GURL(kTestAURLString
));
631 EXPECT_EQ(1, tester_context_
.num_b_deletes());
634 // Confirm that the url of a service is correctly passed to another service that
635 // it loads, and that it can be rejected.
636 TEST_F(ApplicationManagerTest
, ANoLoadB
) {
637 // Any url can load a.
638 AddLoaderForURL(GURL(kTestAURLString
), std::string());
640 // Only c can load b, so this will fail.
641 AddLoaderForURL(GURL(kTestBURLString
), "test:TestC");
644 application_manager_
->ConnectToService(GURL(kTestAURLString
), &a
);
647 EXPECT_EQ(0, tester_context_
.num_b_calls());
649 EXPECT_FALSE(tester_context_
.a_called_quit());
650 EXPECT_TRUE(tester_context_
.tester_called_quit());
653 TEST_F(ApplicationManagerTest
, NoServiceNoLoad
) {
654 AddLoaderForURL(GURL(kTestAURLString
), std::string());
656 // There is no TestC service implementation registered with
657 // ApplicationManager, so this cannot succeed (but also shouldn't crash).
659 application_manager_
->ConnectToService(GURL(kTestAURLString
), &c
);
660 QuitMessageLoopErrorHandler quitter
;
661 c
.set_error_handler(&quitter
);
664 EXPECT_TRUE(c
.encountered_error());
667 TEST_F(ApplicationManagerTest
, Interceptor
) {
668 TestServiceInterceptor interceptor
;
669 TestApplicationLoader
* default_loader
= new TestApplicationLoader
;
670 application_manager_
->set_default_loader(
671 scoped_ptr
<ApplicationLoader
>(default_loader
));
672 application_manager_
->SetInterceptor(&interceptor
);
674 std::string
url("test:test3");
675 TestServicePtr test_service
;
676 application_manager_
->ConnectToService(GURL(url
), &test_service
);
678 EXPECT_EQ(1, interceptor
.call_count());
679 EXPECT_EQ(url
, interceptor
.url_spec());
680 EXPECT_EQ(1, default_loader
->num_loads());