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 OnServiceError(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 OnServiceError(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());