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/memory/scoped_vector.h"
9 #include "base/message_loop/message_loop.h"
10 #include "mojo/public/cpp/application/application_connection.h"
11 #include "mojo/public/cpp/application/application_delegate.h"
12 #include "mojo/public/cpp/application/application_impl.h"
13 #include "mojo/public/cpp/application/interface_factory.h"
14 #include "mojo/public/cpp/bindings/strong_binding.h"
15 #include "mojo/public/interfaces/application/service_provider.mojom.h"
16 #include "mojo/shell/application_loader.h"
17 #include "mojo/shell/application_manager.h"
18 #include "mojo/shell/test.mojom.h"
19 #include "testing/gtest/include/gtest/gtest.h"
25 const char kTestURLString
[] = "test:testService";
26 const char kTestAURLString
[] = "test:TestA";
27 const char kTestBURLString
[] = "test:TestB";
30 TestContext() : num_impls(0), num_loader_deletes(0) {}
31 std::string last_test_string
;
33 int num_loader_deletes
;
36 void QuitClosure(bool* value
) {
38 base::MessageLoop::current()->QuitWhenIdle();
41 class QuitMessageLoopErrorHandler
: public ErrorHandler
{
43 QuitMessageLoopErrorHandler() {}
44 ~QuitMessageLoopErrorHandler() override
{}
46 // |ErrorHandler| implementation:
47 void OnConnectionError() override
{
48 base::MessageLoop::current()->QuitWhenIdle();
52 DISALLOW_COPY_AND_ASSIGN(QuitMessageLoopErrorHandler
);
55 class TestServiceImpl
: public TestService
{
57 TestServiceImpl(TestContext
* context
, InterfaceRequest
<TestService
> request
)
58 : context_(context
), binding_(this, request
.Pass()) {
59 ++context_
->num_impls
;
62 ~TestServiceImpl() override
{
63 --context_
->num_impls
;
64 if (!base::MessageLoop::current()->is_running())
66 base::MessageLoop::current()->Quit();
69 // TestService implementation:
70 void Test(const String
& test_string
,
71 const Callback
<void()>& callback
) override
{
72 context_
->last_test_string
= test_string
;
77 TestContext
* context_
;
78 StrongBinding
<TestService
> binding_
;
83 explicit TestClient(TestServicePtr service
)
84 : service_(service
.Pass()), quit_after_ack_(false) {}
88 base::MessageLoop::current()->Quit();
91 void Test(const std::string
& test_string
) {
92 quit_after_ack_
= true;
93 service_
->Test(test_string
,
94 base::Bind(&TestClient::AckTest
, base::Unretained(this)));
98 TestServicePtr service_
;
100 DISALLOW_COPY_AND_ASSIGN(TestClient
);
103 class TestApplicationLoader
: public ApplicationLoader
,
104 public ApplicationDelegate
,
105 public InterfaceFactory
<TestService
> {
107 TestApplicationLoader() : context_(nullptr), num_loads_(0) {}
109 ~TestApplicationLoader() override
{
111 ++context_
->num_loader_deletes
;
115 void set_context(TestContext
* context
) { context_
= context
; }
116 int num_loads() const { return num_loads_
; }
117 const std::vector
<std::string
>& GetArgs() const { return test_app_
->args(); }
120 // ApplicationLoader implementation.
121 void Load(const GURL
& url
,
122 InterfaceRequest
<Application
> application_request
) override
{
124 test_app_
.reset(new ApplicationImpl(this, application_request
.Pass()));
127 // ApplicationDelegate implementation.
128 bool ConfigureIncomingConnection(ApplicationConnection
* connection
) override
{
129 connection
->AddService(this);
133 // InterfaceFactory implementation.
134 void Create(ApplicationConnection
* connection
,
135 InterfaceRequest
<TestService
> request
) override
{
136 new TestServiceImpl(context_
, request
.Pass());
139 scoped_ptr
<ApplicationImpl
> test_app_
;
140 TestContext
* context_
;
142 DISALLOW_COPY_AND_ASSIGN(TestApplicationLoader
);
145 class ClosingApplicationLoader
: public ApplicationLoader
{
147 // ApplicationLoader implementation.
148 void Load(const GURL
& url
,
149 InterfaceRequest
<Application
> application_request
) override
{}
152 class TesterContext
{
154 explicit TesterContext(base::MessageLoop
* loop
)
160 tester_called_quit_(false),
161 a_called_quit_(false),
164 void IncrementNumBCalls() {
165 base::AutoLock
lock(lock_
);
169 void IncrementNumCCalls() {
170 base::AutoLock
lock(lock_
);
174 void IncrementNumADeletes() {
175 base::AutoLock
lock(lock_
);
179 void IncrementNumBDeletes() {
180 base::AutoLock
lock(lock_
);
184 void IncrementNumCDeletes() {
185 base::AutoLock
lock(lock_
);
189 void set_tester_called_quit() {
190 base::AutoLock
lock(lock_
);
191 tester_called_quit_
= true;
194 void set_a_called_quit() {
195 base::AutoLock
lock(lock_
);
196 a_called_quit_
= true;
200 base::AutoLock
lock(lock_
);
204 base::AutoLock
lock(lock_
);
207 int num_a_deletes() {
208 base::AutoLock
lock(lock_
);
209 return num_a_deletes_
;
211 int num_b_deletes() {
212 base::AutoLock
lock(lock_
);
213 return num_b_deletes_
;
215 int num_c_deletes() {
216 base::AutoLock
lock(lock_
);
217 return num_c_deletes_
;
219 bool tester_called_quit() {
220 base::AutoLock
lock(lock_
);
221 return tester_called_quit_
;
223 bool a_called_quit() {
224 base::AutoLock
lock(lock_
);
225 return a_called_quit_
;
229 loop_
->PostTask(FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
233 // lock_ protects all members except for loop_ which must be unchanged for the
234 // lifetime of this class.
241 bool tester_called_quit_
;
244 base::MessageLoop
* loop_
;
247 // Used to test that the requestor url will be correctly passed.
248 class TestAImpl
: public TestA
{
250 TestAImpl(ApplicationImpl
* app_impl
,
251 TesterContext
* test_context
,
252 InterfaceRequest
<TestA
> request
)
253 : test_context_(test_context
), binding_(this, request
.Pass()) {
254 app_impl
->ConnectToApplication(kTestBURLString
)->ConnectToService(&b_
);
257 ~TestAImpl() override
{
258 test_context_
->IncrementNumADeletes();
259 if (base::MessageLoop::current()->is_running())
264 void CallB() override
{
265 b_
->B(base::Bind(&TestAImpl::Quit
, base::Unretained(this)));
268 void CallCFromB() override
{
269 b_
->CallC(base::Bind(&TestAImpl::Quit
, base::Unretained(this)));
273 base::MessageLoop::current()->Quit();
274 test_context_
->set_a_called_quit();
275 test_context_
->QuitSoon();
278 TesterContext
* test_context_
;
280 StrongBinding
<TestA
> binding_
;
283 class TestBImpl
: public TestB
{
285 TestBImpl(ApplicationConnection
* connection
,
286 TesterContext
* test_context
,
287 InterfaceRequest
<TestB
> request
)
288 : test_context_(test_context
), binding_(this, request
.Pass()) {
289 connection
->ConnectToService(&c_
);
292 ~TestBImpl() override
{
293 test_context_
->IncrementNumBDeletes();
294 if (base::MessageLoop::current()->is_running())
295 base::MessageLoop::current()->Quit();
296 test_context_
->QuitSoon();
300 void B(const Callback
<void()>& callback
) override
{
301 test_context_
->IncrementNumBCalls();
305 void CallC(const Callback
<void()>& callback
) override
{
306 test_context_
->IncrementNumBCalls();
310 TesterContext
* test_context_
;
312 StrongBinding
<TestB
> binding_
;
315 class TestCImpl
: public TestC
{
317 TestCImpl(ApplicationConnection
* connection
,
318 TesterContext
* test_context
,
319 InterfaceRequest
<TestC
> request
)
320 : test_context_(test_context
), binding_(this, request
.Pass()) {}
322 ~TestCImpl() override
{ test_context_
->IncrementNumCDeletes(); }
325 void C(const Callback
<void()>& callback
) override
{
326 test_context_
->IncrementNumCCalls();
330 TesterContext
* test_context_
;
331 StrongBinding
<TestC
> binding_
;
334 class Tester
: public ApplicationDelegate
,
335 public ApplicationLoader
,
336 public InterfaceFactory
<TestA
>,
337 public InterfaceFactory
<TestB
>,
338 public InterfaceFactory
<TestC
> {
340 Tester(TesterContext
* context
, const std::string
& requestor_url
)
341 : context_(context
), requestor_url_(requestor_url
) {}
342 ~Tester() override
{}
345 void Load(const GURL
& url
,
346 InterfaceRequest
<Application
> application_request
) override
{
347 app_
.reset(new ApplicationImpl(this, application_request
.Pass()));
350 bool ConfigureIncomingConnection(ApplicationConnection
* connection
) override
{
351 if (!requestor_url_
.empty() &&
352 requestor_url_
!= connection
->GetRemoteApplicationURL()) {
353 context_
->set_tester_called_quit();
354 context_
->QuitSoon();
355 base::MessageLoop::current()->Quit();
358 // If we're coming from A, then add B, otherwise A.
359 if (connection
->GetRemoteApplicationURL() == kTestAURLString
)
360 connection
->AddService
<TestB
>(this);
362 connection
->AddService
<TestA
>(this);
366 bool ConfigureOutgoingConnection(ApplicationConnection
* connection
) override
{
367 // If we're connecting to B, then add C.
368 if (connection
->GetRemoteApplicationURL() == kTestBURLString
)
369 connection
->AddService
<TestC
>(this);
373 void Create(ApplicationConnection
* connection
,
374 InterfaceRequest
<TestA
> request
) override
{
375 a_bindings_
.push_back(new TestAImpl(app_
.get(), context_
, request
.Pass()));
378 void Create(ApplicationConnection
* connection
,
379 InterfaceRequest
<TestB
> request
) override
{
380 new TestBImpl(connection
, context_
, request
.Pass());
383 void Create(ApplicationConnection
* connection
,
384 InterfaceRequest
<TestC
> request
) override
{
385 new TestCImpl(connection
, context_
, request
.Pass());
388 TesterContext
* context_
;
389 scoped_ptr
<ApplicationImpl
> app_
;
390 std::string requestor_url_
;
391 ScopedVector
<TestAImpl
> a_bindings_
;
394 class TestDelegate
: public ApplicationManager::Delegate
{
396 void AddMapping(const GURL
& from
, const GURL
& to
) { mappings_
[from
] = to
; }
398 // ApplicationManager::Delegate
399 GURL
ResolveMappings(const GURL
& url
) override
{
400 auto it
= mappings_
.find(url
);
401 if (it
!= mappings_
.end())
405 GURL
ResolveMojoURL(const GURL
& url
) override
{
406 GURL mapped_url
= ResolveMappings(url
);
407 // The shell automatically map mojo URLs.
408 if (mapped_url
.scheme() == "mojo") {
409 url::Replacements
<char> replacements
;
410 replacements
.SetScheme("file", url::Component(0, 4));
411 mapped_url
= mapped_url
.ReplaceComponents(replacements
);
417 std::map
<GURL
, GURL
> mappings_
;
420 class ApplicationManagerTest
: public testing::Test
{
422 ApplicationManagerTest() : tester_context_(&loop_
) {}
424 ~ApplicationManagerTest() override
{}
426 void SetUp() override
{
427 application_manager_
.reset(new ApplicationManager(&test_delegate_
));
428 test_loader_
= new TestApplicationLoader
;
429 test_loader_
->set_context(&context_
);
430 application_manager_
->set_default_loader(
431 scoped_ptr
<ApplicationLoader
>(test_loader_
));
433 TestServicePtr service_proxy
;
434 application_manager_
->ConnectToService(GURL(kTestURLString
),
436 test_client_
.reset(new TestClient(service_proxy
.Pass()));
439 void TearDown() override
{
440 test_client_
.reset();
441 application_manager_
.reset();
444 void AddLoaderForURL(const GURL
& url
, const std::string
& requestor_url
) {
445 application_manager_
->SetLoaderForURL(
446 make_scoped_ptr(new Tester(&tester_context_
, requestor_url
)), url
);
449 bool HasFactoryForURL(const GURL
& url
) {
450 ApplicationManager::TestAPI
manager_test_api(application_manager_
.get());
451 return manager_test_api
.HasFactoryForURL(url
);
455 base::ShadowingAtExitManager at_exit_
;
456 TestDelegate test_delegate_
;
457 TestApplicationLoader
* test_loader_
;
458 TesterContext tester_context_
;
459 TestContext context_
;
460 base::MessageLoop loop_
;
461 scoped_ptr
<TestClient
> test_client_
;
462 scoped_ptr
<ApplicationManager
> application_manager_
;
463 DISALLOW_COPY_AND_ASSIGN(ApplicationManagerTest
);
466 TEST_F(ApplicationManagerTest
, Basic
) {
467 test_client_
->Test("test");
469 EXPECT_EQ(std::string("test"), context_
.last_test_string
);
472 // Confirm that no arguments are sent to an application by default.
473 TEST_F(ApplicationManagerTest
, NoArgs
) {
474 ApplicationManager
am(&test_delegate_
);
475 GURL
test_url("test:test");
476 TestApplicationLoader
* loader
= new TestApplicationLoader
;
477 loader
->set_context(&context_
);
478 am
.SetLoaderForURL(scoped_ptr
<ApplicationLoader
>(loader
), test_url
);
479 TestServicePtr test_service
;
480 am
.ConnectToService(test_url
, &test_service
);
481 TestClient
test_client(test_service
.Pass());
482 test_client
.Test("test");
484 std::vector
<std::string
> app_args
= loader
->GetArgs();
485 EXPECT_EQ(0U, app_args
.size());
488 // Confirm that url mappings are respected.
489 TEST_F(ApplicationManagerTest
, URLMapping
) {
490 ApplicationManager
am(&test_delegate_
);
491 GURL
test_url("test:test");
492 GURL
test_url2("test:test2");
493 test_delegate_
.AddMapping(test_url
, test_url2
);
494 TestApplicationLoader
* loader
= new TestApplicationLoader
;
495 loader
->set_context(&context_
);
496 am
.SetLoaderForURL(scoped_ptr
<ApplicationLoader
>(loader
), test_url2
);
498 // Connext to the mapped url
499 TestServicePtr test_service
;
500 am
.ConnectToService(test_url
, &test_service
);
501 TestClient
test_client(test_service
.Pass());
502 test_client
.Test("test");
506 // Connext to the target url
507 TestServicePtr test_service
;
508 am
.ConnectToService(test_url2
, &test_service
);
509 TestClient
test_client(test_service
.Pass());
510 test_client
.Test("test");
515 TEST_F(ApplicationManagerTest
, ClientError
) {
516 test_client_
->Test("test");
517 EXPECT_TRUE(HasFactoryForURL(GURL(kTestURLString
)));
519 EXPECT_EQ(1, context_
.num_impls
);
520 test_client_
.reset();
522 EXPECT_EQ(0, context_
.num_impls
);
523 EXPECT_TRUE(HasFactoryForURL(GURL(kTestURLString
)));
526 TEST_F(ApplicationManagerTest
, Deletes
) {
528 ApplicationManager
am(&test_delegate_
);
529 TestApplicationLoader
* default_loader
= new TestApplicationLoader
;
530 default_loader
->set_context(&context_
);
531 TestApplicationLoader
* url_loader1
= new TestApplicationLoader
;
532 TestApplicationLoader
* url_loader2
= new TestApplicationLoader
;
533 url_loader1
->set_context(&context_
);
534 url_loader2
->set_context(&context_
);
535 TestApplicationLoader
* scheme_loader1
= new TestApplicationLoader
;
536 TestApplicationLoader
* scheme_loader2
= new TestApplicationLoader
;
537 scheme_loader1
->set_context(&context_
);
538 scheme_loader2
->set_context(&context_
);
539 am
.set_default_loader(scoped_ptr
<ApplicationLoader
>(default_loader
));
540 am
.SetLoaderForURL(scoped_ptr
<ApplicationLoader
>(url_loader1
),
542 am
.SetLoaderForURL(scoped_ptr
<ApplicationLoader
>(url_loader2
),
544 am
.SetLoaderForScheme(scoped_ptr
<ApplicationLoader
>(scheme_loader1
),
546 am
.SetLoaderForScheme(scoped_ptr
<ApplicationLoader
>(scheme_loader2
),
549 EXPECT_EQ(5, context_
.num_loader_deletes
);
552 // Confirm that both urls and schemes can have their loaders explicitly set.
553 TEST_F(ApplicationManagerTest
, SetLoaders
) {
554 TestApplicationLoader
* default_loader
= new TestApplicationLoader
;
555 TestApplicationLoader
* url_loader
= new TestApplicationLoader
;
556 TestApplicationLoader
* scheme_loader
= new TestApplicationLoader
;
557 application_manager_
->set_default_loader(
558 scoped_ptr
<ApplicationLoader
>(default_loader
));
559 application_manager_
->SetLoaderForURL(
560 scoped_ptr
<ApplicationLoader
>(url_loader
), GURL("test:test1"));
561 application_manager_
->SetLoaderForScheme(
562 scoped_ptr
<ApplicationLoader
>(scheme_loader
), "test");
564 // test::test1 should go to url_loader.
565 TestServicePtr test_service
;
566 application_manager_
->ConnectToService(GURL("test:test1"), &test_service
);
567 EXPECT_EQ(1, url_loader
->num_loads());
568 EXPECT_EQ(0, scheme_loader
->num_loads());
569 EXPECT_EQ(0, default_loader
->num_loads());
571 // test::test2 should go to scheme loader.
572 application_manager_
->ConnectToService(GURL("test:test2"), &test_service
);
573 EXPECT_EQ(1, url_loader
->num_loads());
574 EXPECT_EQ(1, scheme_loader
->num_loads());
575 EXPECT_EQ(0, default_loader
->num_loads());
577 // http::test1 should go to default loader.
578 application_manager_
->ConnectToService(GURL("http:test1"), &test_service
);
579 EXPECT_EQ(1, url_loader
->num_loads());
580 EXPECT_EQ(1, scheme_loader
->num_loads());
581 EXPECT_EQ(1, default_loader
->num_loads());
584 // Confirm that the url of a service is correctly passed to another service that
586 TEST_F(ApplicationManagerTest
, ACallB
) {
587 // Any url can load a.
588 AddLoaderForURL(GURL(kTestAURLString
), std::string());
590 // Only a can load b.
591 AddLoaderForURL(GURL(kTestBURLString
), kTestAURLString
);
594 application_manager_
->ConnectToService(GURL(kTestAURLString
), &a
);
597 EXPECT_EQ(1, tester_context_
.num_b_calls());
598 EXPECT_TRUE(tester_context_
.a_called_quit());
601 // A calls B which calls C.
602 TEST_F(ApplicationManagerTest
, BCallC
) {
603 // Any url can load a.
604 AddLoaderForURL(GURL(kTestAURLString
), std::string());
606 // Only a can load b.
607 AddLoaderForURL(GURL(kTestBURLString
), kTestAURLString
);
610 application_manager_
->ConnectToService(GURL(kTestAURLString
), &a
);
614 EXPECT_EQ(1, tester_context_
.num_b_calls());
615 EXPECT_EQ(1, tester_context_
.num_c_calls());
616 EXPECT_TRUE(tester_context_
.a_called_quit());
619 // Confirm that a service impl will be deleted if the app that connected to
621 TEST_F(ApplicationManagerTest
, BDeleted
) {
622 AddLoaderForURL(GURL(kTestAURLString
), std::string());
623 AddLoaderForURL(GURL(kTestBURLString
), std::string());
626 application_manager_
->ConnectToService(GURL(kTestAURLString
), &a
);
632 application_manager_
->SetLoaderForURL(scoped_ptr
<ApplicationLoader
>(),
633 GURL(kTestAURLString
));
636 EXPECT_EQ(1, tester_context_
.num_b_deletes());
639 // Confirm that the url of a service is correctly passed to another service that
640 // it loads, and that it can be rejected.
641 TEST_F(ApplicationManagerTest
, ANoLoadB
) {
642 // Any url can load a.
643 AddLoaderForURL(GURL(kTestAURLString
), std::string());
645 // Only c can load b, so this will fail.
646 AddLoaderForURL(GURL(kTestBURLString
), "test:TestC");
649 application_manager_
->ConnectToService(GURL(kTestAURLString
), &a
);
652 EXPECT_EQ(0, tester_context_
.num_b_calls());
654 EXPECT_FALSE(tester_context_
.a_called_quit());
655 EXPECT_TRUE(tester_context_
.tester_called_quit());
658 TEST_F(ApplicationManagerTest
, NoServiceNoLoad
) {
659 AddLoaderForURL(GURL(kTestAURLString
), std::string());
661 // There is no TestC service implementation registered with
662 // ApplicationManager, so this cannot succeed (but also shouldn't crash).
664 application_manager_
->ConnectToService(GURL(kTestAURLString
), &c
);
665 QuitMessageLoopErrorHandler quitter
;
666 c
.set_error_handler(&quitter
);
669 EXPECT_TRUE(c
.encountered_error());
672 TEST_F(ApplicationManagerTest
, MappedURLsShouldNotCauseDuplicateLoad
) {
673 test_delegate_
.AddMapping(GURL("foo:foo2"), GURL("foo:foo"));
674 // 1 because ApplicationManagerTest connects once at startup.
675 EXPECT_EQ(1, test_loader_
->num_loads());
677 TestServicePtr test_service
;
678 application_manager_
->ConnectToService(GURL("foo:foo"), &test_service
);
679 EXPECT_EQ(2, test_loader_
->num_loads());
681 TestServicePtr test_service2
;
682 application_manager_
->ConnectToService(GURL("foo:foo2"), &test_service2
);
683 EXPECT_EQ(2, test_loader_
->num_loads());
685 TestServicePtr test_service3
;
686 application_manager_
->ConnectToService(GURL("bar:bar"), &test_service2
);
687 EXPECT_EQ(3, test_loader_
->num_loads());
690 TEST_F(ApplicationManagerTest
, MappedURLsShouldWorkWithLoaders
) {
691 TestApplicationLoader
* custom_loader
= new TestApplicationLoader
;
693 custom_loader
->set_context(&context
);
694 application_manager_
->SetLoaderForURL(make_scoped_ptr(custom_loader
),
696 test_delegate_
.AddMapping(GURL("mojo:foo2"), GURL("mojo:foo"));
698 TestServicePtr test_service
;
699 application_manager_
->ConnectToService(GURL("mojo:foo2"), &test_service
);
700 EXPECT_EQ(1, custom_loader
->num_loads());
701 custom_loader
->set_context(nullptr);
703 EXPECT_TRUE(HasFactoryForURL(GURL("mojo:foo2")));
704 EXPECT_FALSE(HasFactoryForURL(GURL("mojo:foo")));
707 TEST_F(ApplicationManagerTest
, TestQueryWithLoaders
) {
708 TestApplicationLoader
* url_loader
= new TestApplicationLoader
;
709 TestApplicationLoader
* scheme_loader
= new TestApplicationLoader
;
710 application_manager_
->SetLoaderForURL(
711 scoped_ptr
<ApplicationLoader
>(url_loader
), GURL("test:test1"));
712 application_manager_
->SetLoaderForScheme(
713 scoped_ptr
<ApplicationLoader
>(scheme_loader
), "test");
715 // test::test1 should go to url_loader.
716 TestServicePtr test_service
;
717 application_manager_
->ConnectToService(GURL("test:test1?foo=bar"),
719 EXPECT_EQ(1, url_loader
->num_loads());
720 EXPECT_EQ(0, scheme_loader
->num_loads());
722 // test::test2 should go to scheme loader.
723 application_manager_
->ConnectToService(GURL("test:test2?foo=bar"),
725 EXPECT_EQ(1, url_loader
->num_loads());
726 EXPECT_EQ(1, scheme_loader
->num_loads());
729 TEST_F(ApplicationManagerTest
, TestEndApplicationClosure
) {
730 ClosingApplicationLoader
* loader
= new ClosingApplicationLoader();
731 application_manager_
->SetLoaderForScheme(
732 scoped_ptr
<ApplicationLoader
>(loader
), "test");
735 application_manager_
->ConnectToApplication(
736 GURL("test:test"), GURL(), nullptr, nullptr,
737 base::Bind(&QuitClosure
, base::Unretained(&called
)));