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_; }
110 std::vector<std::string> GetArgs() {
111 return test_app_->args().To<std::vector<std::string> >();
115 // ApplicationLoader implementation.
116 virtual void Load(ApplicationManager* manager,
118 scoped_refptr<LoadCallbacks> callbacks) OVERRIDE {
121 new ApplicationImpl(this, callbacks->RegisterApplication().Pass()));
124 virtual void OnApplicationError(ApplicationManager* manager,
125 const GURL& url) OVERRIDE {}
127 // ApplicationDelegate implementation.
128 virtual bool ConfigureIncomingConnection(
129 ApplicationConnection* connection) OVERRIDE {
130 connection->AddService(this);
134 // InterfaceFactory implementation.
135 virtual void Create(ApplicationConnection* connection,
136 InterfaceRequest<TestService> request) OVERRIDE {
137 BindToRequest(new TestServiceImpl(context_), &request);
140 scoped_ptr<ApplicationImpl> test_app_;
141 TestContext* context_;
143 DISALLOW_COPY_AND_ASSIGN(TestApplicationLoader);
146 class TesterContext {
148 explicit TesterContext(base::MessageLoop* loop)
154 tester_called_quit_(false),
155 a_called_quit_(false),
158 void IncrementNumBCalls() {
159 base::AutoLock lock(lock_);
163 void IncrementNumCCalls() {
164 base::AutoLock lock(lock_);
168 void IncrementNumADeletes() {
169 base::AutoLock lock(lock_);
173 void IncrementNumBDeletes() {
174 base::AutoLock lock(lock_);
178 void IncrementNumCDeletes() {
179 base::AutoLock lock(lock_);
183 void set_tester_called_quit() {
184 base::AutoLock lock(lock_);
185 tester_called_quit_ = true;
188 void set_a_called_quit() {
189 base::AutoLock lock(lock_);
190 a_called_quit_ = true;
194 base::AutoLock lock(lock_);
198 base::AutoLock lock(lock_);
201 int num_a_deletes() {
202 base::AutoLock lock(lock_);
203 return num_a_deletes_;
205 int num_b_deletes() {
206 base::AutoLock lock(lock_);
207 return num_b_deletes_;
209 int num_c_deletes() {
210 base::AutoLock lock(lock_);
211 return num_c_deletes_;
213 bool tester_called_quit() {
214 base::AutoLock lock(lock_);
215 return tester_called_quit_;
217 bool a_called_quit() {
218 base::AutoLock lock(lock_);
219 return a_called_quit_;
223 loop_->PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
227 // lock_ protects all members except for loop_ which must be unchanged for the
228 // lifetime of this class.
235 bool tester_called_quit_;
238 base::MessageLoop* loop_;
241 // Used to test that the requestor url will be correctly passed.
242 class TestAImpl : public InterfaceImpl<TestA> {
244 TestAImpl(ApplicationConnection* connection, TesterContext* test_context)
245 : test_context_(test_context) {
246 connection->ConnectToApplication(kTestBURLString)->ConnectToService(&b_);
248 virtual ~TestAImpl() {
249 test_context_->IncrementNumADeletes();
250 if (base::MessageLoop::current()->is_running())
255 virtual void CallB() OVERRIDE {
256 b_->B(base::Bind(&TestAImpl::Quit, base::Unretained(this)));
259 virtual void CallCFromB() OVERRIDE {
260 b_->CallC(base::Bind(&TestAImpl::Quit, base::Unretained(this)));
264 base::MessageLoop::current()->Quit();
265 test_context_->set_a_called_quit();
266 test_context_->QuitSoon();
269 TesterContext* test_context_;
273 class TestBImpl : public InterfaceImpl<TestB> {
275 TestBImpl(ApplicationConnection* connection, TesterContext* test_context)
276 : test_context_(test_context) {
277 connection->ConnectToService(&c_);
280 virtual ~TestBImpl() {
281 test_context_->IncrementNumBDeletes();
282 if (base::MessageLoop::current()->is_running())
283 base::MessageLoop::current()->Quit();
284 test_context_->QuitSoon();
288 virtual void B(const mojo::Callback<void()>& callback) OVERRIDE {
289 test_context_->IncrementNumBCalls();
293 virtual void CallC(const mojo::Callback<void()>& callback) OVERRIDE {
294 test_context_->IncrementNumBCalls();
298 TesterContext* test_context_;
302 class TestCImpl : public InterfaceImpl<TestC> {
304 TestCImpl(ApplicationConnection* connection, TesterContext* test_context)
305 : test_context_(test_context) {}
307 virtual ~TestCImpl() { test_context_->IncrementNumCDeletes(); }
310 virtual void C(const mojo::Callback<void()>& callback) OVERRIDE {
311 test_context_->IncrementNumCCalls();
314 TesterContext* test_context_;
317 class Tester : public ApplicationDelegate,
318 public ApplicationLoader,
319 public InterfaceFactory<TestA>,
320 public InterfaceFactory<TestB>,
321 public InterfaceFactory<TestC> {
323 Tester(TesterContext* context, const std::string& requestor_url)
324 : context_(context), requestor_url_(requestor_url) {}
328 virtual void Load(ApplicationManager* manager,
330 scoped_refptr<LoadCallbacks> callbacks) OVERRIDE {
332 new ApplicationImpl(this, callbacks->RegisterApplication().Pass()));
335 virtual void OnApplicationError(ApplicationManager* manager,
336 const GURL& url) OVERRIDE {}
338 virtual bool ConfigureIncomingConnection(
339 ApplicationConnection* connection) OVERRIDE {
340 if (!requestor_url_.empty() &&
341 requestor_url_ != connection->GetRemoteApplicationURL()) {
342 context_->set_tester_called_quit();
343 context_->QuitSoon();
344 base::MessageLoop::current()->Quit();
347 // If we're coming from A, then add B, otherwise A.
348 if (connection->GetRemoteApplicationURL() == kTestAURLString)
349 connection->AddService<TestB>(this);
351 connection->AddService<TestA>(this);
355 virtual bool ConfigureOutgoingConnection(
356 ApplicationConnection* connection) OVERRIDE {
357 // If we're connecting to B, then add C.
358 if (connection->GetRemoteApplicationURL() == kTestBURLString)
359 connection->AddService<TestC>(this);
363 virtual void Create(ApplicationConnection* connection,
364 InterfaceRequest<TestA> request) OVERRIDE {
365 BindToRequest(new TestAImpl(connection, context_), &request);
368 virtual void Create(ApplicationConnection* connection,
369 InterfaceRequest<TestB> request) OVERRIDE {
370 BindToRequest(new TestBImpl(connection, context_), &request);
373 virtual void Create(ApplicationConnection* connection,
374 InterfaceRequest<TestC> request) OVERRIDE {
375 BindToRequest(new TestCImpl(connection, context_), &request);
378 TesterContext* context_;
379 scoped_ptr<ApplicationImpl> app_;
380 std::string requestor_url_;
383 class TestServiceInterceptor : public ApplicationManager::Interceptor {
385 TestServiceInterceptor() : call_count_(0) {}
387 virtual ServiceProviderPtr OnConnectToClient(
389 ServiceProviderPtr service_provider) OVERRIDE {
392 return service_provider.Pass();
395 std::string url_spec() const {
396 if (!url_.is_valid())
397 return "invalid url";
401 int call_count() const { return call_count_; }
406 DISALLOW_COPY_AND_ASSIGN(TestServiceInterceptor);
411 class ApplicationManagerTest : public testing::Test {
413 ApplicationManagerTest() : tester_context_(&loop_) {}
415 virtual ~ApplicationManagerTest() {}
417 virtual void SetUp() OVERRIDE {
418 application_manager_.reset(new ApplicationManager);
419 TestApplicationLoader* default_loader = new TestApplicationLoader;
420 default_loader->set_context(&context_);
421 application_manager_->set_default_loader(
422 scoped_ptr<ApplicationLoader>(default_loader));
424 TestServicePtr service_proxy;
425 application_manager_->ConnectToService(GURL(kTestURLString),
427 test_client_.reset(new TestClientImpl(service_proxy.Pass()));
430 virtual void TearDown() OVERRIDE {
431 test_client_.reset(NULL);
432 application_manager_.reset(NULL);
435 scoped_ptr<BackgroundShellApplicationLoader> MakeLoader(
436 const std::string& requestor_url) {
437 scoped_ptr<ApplicationLoader> real_loader(
438 new Tester(&tester_context_, requestor_url));
439 scoped_ptr<BackgroundShellApplicationLoader> loader(
440 new BackgroundShellApplicationLoader(real_loader.Pass(),
442 base::MessageLoop::TYPE_DEFAULT));
443 return loader.Pass();
446 void AddLoaderForURL(const GURL& url, const std::string& requestor_url) {
447 application_manager_->SetLoaderForURL(
448 MakeLoader(requestor_url).PassAs<ApplicationLoader>(), url);
451 bool HasFactoryForTestURL() {
452 ApplicationManager::TestAPI manager_test_api(application_manager_.get());
453 return manager_test_api.HasFactoryForURL(GURL(kTestURLString));
457 base::ShadowingAtExitManager at_exit_;
458 TesterContext tester_context_;
459 TestContext context_;
460 base::MessageLoop loop_;
461 scoped_ptr<TestClientImpl> 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;
475 GURL test_url("test:test");
477 TestApplicationLoader* loader = new TestApplicationLoader;
478 loader->set_context(&context);
479 am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(loader), test_url);
480 TestServicePtr test_service;
481 am.ConnectToService(test_url, &test_service);
482 TestClientImpl test_client(test_service.Pass());
483 test_client.Test("test");
485 std::vector<std::string> app_args = loader->GetArgs();
486 EXPECT_EQ(0U, app_args.size());
489 // Confirm that arguments are sent to an application.
490 TEST_F(ApplicationManagerTest, Args) {
491 ApplicationManager am;
492 GURL test_url("test:test");
493 std::vector<std::string> args;
494 args.push_back("test_arg1");
495 args.push_back("test_arg2");
496 am.SetArgsForURL(args, test_url);
498 TestApplicationLoader* loader = new TestApplicationLoader;
499 loader->set_context(&context);
500 am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(loader), test_url);
501 TestServicePtr test_service;
502 am.ConnectToService(test_url, &test_service);
503 TestClientImpl test_client(test_service.Pass());
504 test_client.Test("test");
506 std::vector<std::string> app_args = loader->GetArgs();
507 ASSERT_EQ(args.size(), app_args.size());
508 EXPECT_EQ(args[0], app_args[0]);
509 EXPECT_EQ(args[1], app_args[1]);
512 TEST_F(ApplicationManagerTest, ClientError) {
513 test_client_->Test("test");
514 EXPECT_TRUE(HasFactoryForTestURL());
516 EXPECT_EQ(1, context_.num_impls);
517 test_client_.reset(NULL);
519 EXPECT_EQ(0, context_.num_impls);
520 EXPECT_TRUE(HasFactoryForTestURL());
523 TEST_F(ApplicationManagerTest, Deletes) {
525 ApplicationManager am;
526 TestApplicationLoader* default_loader = new TestApplicationLoader;
527 default_loader->set_context(&context_);
528 TestApplicationLoader* url_loader1 = new TestApplicationLoader;
529 TestApplicationLoader* url_loader2 = new TestApplicationLoader;
530 url_loader1->set_context(&context_);
531 url_loader2->set_context(&context_);
532 TestApplicationLoader* scheme_loader1 = new TestApplicationLoader;
533 TestApplicationLoader* scheme_loader2 = new TestApplicationLoader;
534 scheme_loader1->set_context(&context_);
535 scheme_loader2->set_context(&context_);
536 am.set_default_loader(scoped_ptr<ApplicationLoader>(default_loader));
537 am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(url_loader1),
539 am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(url_loader2),
541 am.SetLoaderForScheme(scoped_ptr<ApplicationLoader>(scheme_loader1),
543 am.SetLoaderForScheme(scoped_ptr<ApplicationLoader>(scheme_loader2),
546 EXPECT_EQ(5, context_.num_loader_deletes);
549 // Confirm that both urls and schemes can have their loaders explicitly set.
550 TEST_F(ApplicationManagerTest, SetLoaders) {
551 TestApplicationLoader* default_loader = new TestApplicationLoader;
552 TestApplicationLoader* url_loader = new TestApplicationLoader;
553 TestApplicationLoader* scheme_loader = new TestApplicationLoader;
554 application_manager_->set_default_loader(
555 scoped_ptr<ApplicationLoader>(default_loader));
556 application_manager_->SetLoaderForURL(
557 scoped_ptr<ApplicationLoader>(url_loader), GURL("test:test1"));
558 application_manager_->SetLoaderForScheme(
559 scoped_ptr<ApplicationLoader>(scheme_loader), "test");
561 // test::test1 should go to url_loader.
562 TestServicePtr test_service;
563 application_manager_->ConnectToService(GURL("test:test1"), &test_service);
564 EXPECT_EQ(1, url_loader->num_loads());
565 EXPECT_EQ(0, scheme_loader->num_loads());
566 EXPECT_EQ(0, default_loader->num_loads());
568 // test::test2 should go to scheme loader.
569 application_manager_->ConnectToService(GURL("test:test2"), &test_service);
570 EXPECT_EQ(1, url_loader->num_loads());
571 EXPECT_EQ(1, scheme_loader->num_loads());
572 EXPECT_EQ(0, default_loader->num_loads());
574 // http::test1 should go to default loader.
575 application_manager_->ConnectToService(GURL("http:test1"), &test_service);
576 EXPECT_EQ(1, url_loader->num_loads());
577 EXPECT_EQ(1, scheme_loader->num_loads());
578 EXPECT_EQ(1, default_loader->num_loads());
581 // Confirm that the url of a service is correctly passed to another service that
583 TEST_F(ApplicationManagerTest, ACallB) {
584 // Any url can load a.
585 AddLoaderForURL(GURL(kTestAURLString), std::string());
587 // Only a can load b.
588 AddLoaderForURL(GURL(kTestBURLString), kTestAURLString);
591 application_manager_->ConnectToService(GURL(kTestAURLString), &a);
594 EXPECT_EQ(1, tester_context_.num_b_calls());
595 EXPECT_TRUE(tester_context_.a_called_quit());
598 // A calls B which calls C.
599 TEST_F(ApplicationManagerTest, BCallC) {
600 // Any url can load a.
601 AddLoaderForURL(GURL(kTestAURLString), std::string());
603 // Only a can load b.
604 AddLoaderForURL(GURL(kTestBURLString), kTestAURLString);
607 application_manager_->ConnectToService(GURL(kTestAURLString), &a);
611 EXPECT_EQ(1, tester_context_.num_b_calls());
612 EXPECT_EQ(1, tester_context_.num_c_calls());
613 EXPECT_TRUE(tester_context_.a_called_quit());
616 // Confirm that a service impl will be deleted if the app that connected to
618 TEST_F(ApplicationManagerTest, BDeleted) {
619 AddLoaderForURL(GURL(kTestAURLString), std::string());
620 AddLoaderForURL(GURL(kTestBURLString), std::string());
623 application_manager_->ConnectToService(GURL(kTestAURLString), &a);
629 application_manager_->SetLoaderForURL(scoped_ptr<ApplicationLoader>(),
630 GURL(kTestAURLString));
633 EXPECT_EQ(1, tester_context_.num_b_deletes());
636 // Confirm that the url of a service is correctly passed to another service that
637 // it loads, and that it can be rejected.
638 TEST_F(ApplicationManagerTest, ANoLoadB) {
639 // Any url can load a.
640 AddLoaderForURL(GURL(kTestAURLString), std::string());
642 // Only c can load b, so this will fail.
643 AddLoaderForURL(GURL(kTestBURLString), "test:TestC");
646 application_manager_->ConnectToService(GURL(kTestAURLString), &a);
649 EXPECT_EQ(0, tester_context_.num_b_calls());
651 EXPECT_FALSE(tester_context_.a_called_quit());
652 EXPECT_TRUE(tester_context_.tester_called_quit());
655 TEST_F(ApplicationManagerTest, NoServiceNoLoad) {
656 AddLoaderForURL(GURL(kTestAURLString), std::string());
658 // There is no TestC service implementation registered with
659 // ApplicationManager, so this cannot succeed (but also shouldn't crash).
661 application_manager_->ConnectToService(GURL(kTestAURLString), &c);
662 QuitMessageLoopErrorHandler quitter;
663 c.set_error_handler(&quitter);
666 EXPECT_TRUE(c.encountered_error());
669 TEST_F(ApplicationManagerTest, Interceptor) {
670 TestServiceInterceptor interceptor;
671 TestApplicationLoader* default_loader = new TestApplicationLoader;
672 application_manager_->set_default_loader(
673 scoped_ptr<ApplicationLoader>(default_loader));
674 application_manager_->SetInterceptor(&interceptor);
676 std::string url("test:test3");
677 TestServicePtr test_service;
678 application_manager_->ConnectToService(GURL(url), &test_service);
680 EXPECT_EQ(1, interceptor.call_count());
681 EXPECT_EQ(url, interceptor.url_spec());
682 EXPECT_EQ(1, default_loader->num_loads());