Index: mojo/shell/application_manager/application_manager_unittest.cc |
diff --git a/mojo/shell/application_manager/application_manager_unittest.cc b/mojo/shell/application_manager/application_manager_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ed16d151352500e17a46f3d05af744a5fb1ee13f |
--- /dev/null |
+++ b/mojo/shell/application_manager/application_manager_unittest.cc |
@@ -0,0 +1,829 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/at_exit.h" |
+#include "base/bind.h" |
+#include "base/macros.h" |
+#include "base/memory/scoped_vector.h" |
+#include "base/message_loop/message_loop.h" |
+#include "mojo/public/cpp/application/application_connection.h" |
+#include "mojo/public/cpp/application/application_delegate.h" |
+#include "mojo/public/cpp/application/application_impl.h" |
+#include "mojo/public/cpp/application/interface_factory.h" |
+#include "mojo/public/cpp/bindings/strong_binding.h" |
+#include "mojo/public/interfaces/application/service_provider.mojom.h" |
+#include "mojo/shell/application_manager/application_loader.h" |
+#include "mojo/shell/application_manager/application_manager.h" |
+#include "mojo/shell/application_manager/test.mojom.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace mojo { |
+namespace shell { |
+namespace { |
+ |
+const char kTestURLString[] = "test:testService"; |
+const char kTestAURLString[] = "test:TestA"; |
+const char kTestBURLString[] = "test:TestB"; |
+ |
+struct TestContext { |
+ TestContext() : num_impls(0), num_loader_deletes(0) {} |
+ std::string last_test_string; |
+ int num_impls; |
+ int num_loader_deletes; |
+}; |
+ |
+void QuitClosure(bool* value) { |
+ *value = true; |
+ base::MessageLoop::current()->QuitWhenIdle(); |
+} |
+ |
+class QuitMessageLoopErrorHandler : public ErrorHandler { |
+ public: |
+ QuitMessageLoopErrorHandler() {} |
+ ~QuitMessageLoopErrorHandler() override {} |
+ |
+ // |ErrorHandler| implementation: |
+ void OnConnectionError() override { |
+ base::MessageLoop::current()->QuitWhenIdle(); |
+ } |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(QuitMessageLoopErrorHandler); |
+}; |
+ |
+class TestServiceImpl : public TestService { |
+ public: |
+ TestServiceImpl(TestContext* context, InterfaceRequest<TestService> request) |
+ : context_(context), binding_(this, request.Pass()) { |
+ ++context_->num_impls; |
+ } |
+ |
+ ~TestServiceImpl() override { |
+ --context_->num_impls; |
+ if (!base::MessageLoop::current()->is_running()) |
+ return; |
+ base::MessageLoop::current()->Quit(); |
+ } |
+ |
+ // TestService implementation: |
+ void Test(const String& test_string, |
+ const Callback<void()>& callback) override { |
+ context_->last_test_string = test_string; |
+ callback.Run(); |
+ } |
+ |
+ private: |
+ TestContext* context_; |
+ StrongBinding<TestService> binding_; |
+}; |
+ |
+class TestClient { |
+ public: |
+ explicit TestClient(TestServicePtr service) |
+ : service_(service.Pass()), quit_after_ack_(false) {} |
+ |
+ void AckTest() { |
+ if (quit_after_ack_) |
+ base::MessageLoop::current()->Quit(); |
+ } |
+ |
+ void Test(const std::string& test_string) { |
+ quit_after_ack_ = true; |
+ service_->Test(test_string, |
+ base::Bind(&TestClient::AckTest, base::Unretained(this))); |
+ } |
+ |
+ private: |
+ TestServicePtr service_; |
+ bool quit_after_ack_; |
+ DISALLOW_COPY_AND_ASSIGN(TestClient); |
+}; |
+ |
+class TestApplicationLoader : public ApplicationLoader, |
+ public ApplicationDelegate, |
+ public InterfaceFactory<TestService> { |
+ public: |
+ TestApplicationLoader() : context_(nullptr), num_loads_(0) {} |
+ |
+ ~TestApplicationLoader() override { |
+ if (context_) |
+ ++context_->num_loader_deletes; |
+ test_app_.reset(); |
+ } |
+ |
+ void set_context(TestContext* context) { context_ = context; } |
+ int num_loads() const { return num_loads_; } |
+ const std::vector<std::string>& GetArgs() const { return test_app_->args(); } |
+ |
+ private: |
+ // ApplicationLoader implementation. |
+ void Load(const GURL& url, |
+ InterfaceRequest<Application> application_request) override { |
+ ++num_loads_; |
+ test_app_.reset(new ApplicationImpl(this, application_request.Pass())); |
+ } |
+ |
+ // ApplicationDelegate implementation. |
+ bool ConfigureIncomingConnection(ApplicationConnection* connection) override { |
+ connection->AddService(this); |
+ return true; |
+ } |
+ |
+ // InterfaceFactory implementation. |
+ void Create(ApplicationConnection* connection, |
+ InterfaceRequest<TestService> request) override { |
+ new TestServiceImpl(context_, request.Pass()); |
+ } |
+ |
+ scoped_ptr<ApplicationImpl> test_app_; |
+ TestContext* context_; |
+ int num_loads_; |
+ DISALLOW_COPY_AND_ASSIGN(TestApplicationLoader); |
+}; |
+ |
+class ClosingApplicationLoader : public ApplicationLoader { |
+ private: |
+ // ApplicationLoader implementation. |
+ void Load(const GURL& url, |
+ InterfaceRequest<Application> application_request) override {} |
+}; |
+ |
+class TesterContext { |
+ public: |
+ explicit TesterContext(base::MessageLoop* loop) |
+ : num_b_calls_(0), |
+ num_c_calls_(0), |
+ num_a_deletes_(0), |
+ num_b_deletes_(0), |
+ num_c_deletes_(0), |
+ tester_called_quit_(false), |
+ a_called_quit_(false), |
+ loop_(loop) {} |
+ |
+ void IncrementNumBCalls() { |
+ base::AutoLock lock(lock_); |
+ num_b_calls_++; |
+ } |
+ |
+ void IncrementNumCCalls() { |
+ base::AutoLock lock(lock_); |
+ num_c_calls_++; |
+ } |
+ |
+ void IncrementNumADeletes() { |
+ base::AutoLock lock(lock_); |
+ num_a_deletes_++; |
+ } |
+ |
+ void IncrementNumBDeletes() { |
+ base::AutoLock lock(lock_); |
+ num_b_deletes_++; |
+ } |
+ |
+ void IncrementNumCDeletes() { |
+ base::AutoLock lock(lock_); |
+ num_c_deletes_++; |
+ } |
+ |
+ void set_tester_called_quit() { |
+ base::AutoLock lock(lock_); |
+ tester_called_quit_ = true; |
+ } |
+ |
+ void set_a_called_quit() { |
+ base::AutoLock lock(lock_); |
+ a_called_quit_ = true; |
+ } |
+ |
+ int num_b_calls() { |
+ base::AutoLock lock(lock_); |
+ return num_b_calls_; |
+ } |
+ int num_c_calls() { |
+ base::AutoLock lock(lock_); |
+ return num_c_calls_; |
+ } |
+ int num_a_deletes() { |
+ base::AutoLock lock(lock_); |
+ return num_a_deletes_; |
+ } |
+ int num_b_deletes() { |
+ base::AutoLock lock(lock_); |
+ return num_b_deletes_; |
+ } |
+ int num_c_deletes() { |
+ base::AutoLock lock(lock_); |
+ return num_c_deletes_; |
+ } |
+ bool tester_called_quit() { |
+ base::AutoLock lock(lock_); |
+ return tester_called_quit_; |
+ } |
+ bool a_called_quit() { |
+ base::AutoLock lock(lock_); |
+ return a_called_quit_; |
+ } |
+ |
+ void QuitSoon() { |
+ loop_->PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); |
+ } |
+ |
+ private: |
+ // lock_ protects all members except for loop_ which must be unchanged for the |
+ // lifetime of this class. |
+ base::Lock lock_; |
+ int num_b_calls_; |
+ int num_c_calls_; |
+ int num_a_deletes_; |
+ int num_b_deletes_; |
+ int num_c_deletes_; |
+ bool tester_called_quit_; |
+ bool a_called_quit_; |
+ |
+ base::MessageLoop* loop_; |
+}; |
+ |
+// Used to test that the requestor url will be correctly passed. |
+class TestAImpl : public TestA { |
+ public: |
+ TestAImpl(ApplicationImpl* app_impl, |
+ TesterContext* test_context, |
+ InterfaceRequest<TestA> request) |
+ : test_context_(test_context), binding_(this, request.Pass()) { |
+ app_impl->ConnectToApplication(kTestBURLString)->ConnectToService(&b_); |
+ } |
+ |
+ ~TestAImpl() override { |
+ test_context_->IncrementNumADeletes(); |
+ if (base::MessageLoop::current()->is_running()) |
+ Quit(); |
+ } |
+ |
+ private: |
+ void CallB() override { |
+ b_->B(base::Bind(&TestAImpl::Quit, base::Unretained(this))); |
+ } |
+ |
+ void CallCFromB() override { |
+ b_->CallC(base::Bind(&TestAImpl::Quit, base::Unretained(this))); |
+ } |
+ |
+ void Quit() { |
+ base::MessageLoop::current()->Quit(); |
+ test_context_->set_a_called_quit(); |
+ test_context_->QuitSoon(); |
+ } |
+ |
+ TesterContext* test_context_; |
+ TestBPtr b_; |
+ StrongBinding<TestA> binding_; |
+}; |
+ |
+class TestBImpl : public TestB { |
+ public: |
+ TestBImpl(ApplicationConnection* connection, |
+ TesterContext* test_context, |
+ InterfaceRequest<TestB> request) |
+ : test_context_(test_context), binding_(this, request.Pass()) { |
+ connection->ConnectToService(&c_); |
+ } |
+ |
+ ~TestBImpl() override { |
+ test_context_->IncrementNumBDeletes(); |
+ if (base::MessageLoop::current()->is_running()) |
+ base::MessageLoop::current()->Quit(); |
+ test_context_->QuitSoon(); |
+ } |
+ |
+ private: |
+ void B(const Callback<void()>& callback) override { |
+ test_context_->IncrementNumBCalls(); |
+ callback.Run(); |
+ } |
+ |
+ void CallC(const Callback<void()>& callback) override { |
+ test_context_->IncrementNumBCalls(); |
+ c_->C(callback); |
+ } |
+ |
+ TesterContext* test_context_; |
+ TestCPtr c_; |
+ StrongBinding<TestB> binding_; |
+}; |
+ |
+class TestCImpl : public TestC { |
+ public: |
+ TestCImpl(ApplicationConnection* connection, |
+ TesterContext* test_context, |
+ InterfaceRequest<TestC> request) |
+ : test_context_(test_context), binding_(this, request.Pass()) {} |
+ |
+ ~TestCImpl() override { test_context_->IncrementNumCDeletes(); } |
+ |
+ private: |
+ void C(const Callback<void()>& callback) override { |
+ test_context_->IncrementNumCCalls(); |
+ callback.Run(); |
+ } |
+ |
+ TesterContext* test_context_; |
+ StrongBinding<TestC> binding_; |
+}; |
+ |
+class Tester : public ApplicationDelegate, |
+ public ApplicationLoader, |
+ public InterfaceFactory<TestA>, |
+ public InterfaceFactory<TestB>, |
+ public InterfaceFactory<TestC> { |
+ public: |
+ Tester(TesterContext* context, const std::string& requestor_url) |
+ : context_(context), requestor_url_(requestor_url) {} |
+ ~Tester() override {} |
+ |
+ private: |
+ void Load(const GURL& url, |
+ InterfaceRequest<Application> application_request) override { |
+ app_.reset(new ApplicationImpl(this, application_request.Pass())); |
+ } |
+ |
+ bool ConfigureIncomingConnection(ApplicationConnection* connection) override { |
+ if (!requestor_url_.empty() && |
+ requestor_url_ != connection->GetRemoteApplicationURL()) { |
+ context_->set_tester_called_quit(); |
+ context_->QuitSoon(); |
+ base::MessageLoop::current()->Quit(); |
+ return false; |
+ } |
+ // If we're coming from A, then add B, otherwise A. |
+ if (connection->GetRemoteApplicationURL() == kTestAURLString) |
+ connection->AddService<TestB>(this); |
+ else |
+ connection->AddService<TestA>(this); |
+ return true; |
+ } |
+ |
+ bool ConfigureOutgoingConnection(ApplicationConnection* connection) override { |
+ // If we're connecting to B, then add C. |
+ if (connection->GetRemoteApplicationURL() == kTestBURLString) |
+ connection->AddService<TestC>(this); |
+ return true; |
+ } |
+ |
+ void Create(ApplicationConnection* connection, |
+ InterfaceRequest<TestA> request) override { |
+ a_bindings_.push_back(new TestAImpl(app_.get(), context_, request.Pass())); |
+ } |
+ |
+ void Create(ApplicationConnection* connection, |
+ InterfaceRequest<TestB> request) override { |
+ new TestBImpl(connection, context_, request.Pass()); |
+ } |
+ |
+ void Create(ApplicationConnection* connection, |
+ InterfaceRequest<TestC> request) override { |
+ new TestCImpl(connection, context_, request.Pass()); |
+ } |
+ |
+ TesterContext* context_; |
+ scoped_ptr<ApplicationImpl> app_; |
+ std::string requestor_url_; |
+ ScopedVector<TestAImpl> a_bindings_; |
+}; |
+ |
+class TestDelegate : public ApplicationManager::Delegate { |
+ public: |
+ void AddMapping(const GURL& from, const GURL& to) { mappings_[from] = to; } |
+ |
+ // ApplicationManager::Delegate |
+ GURL ResolveMappings(const GURL& url) override { |
+ auto it = mappings_.find(url); |
+ if (it != mappings_.end()) |
+ return it->second; |
+ return url; |
+ } |
+ |
+ // ApplicationManager::Delegate |
+ GURL ResolveURL(const GURL& url) override { |
+ GURL mapped_url = ResolveMappings(url); |
+ // The shell automatically map mojo URLs. |
+ if (mapped_url.scheme() == "mojo") { |
+ url::Replacements<char> replacements; |
+ replacements.SetScheme("file", url::Component(0, 4)); |
+ mapped_url = mapped_url.ReplaceComponents(replacements); |
+ } |
+ return mapped_url; |
+ } |
+ |
+ private: |
+ std::map<GURL, GURL> mappings_; |
+}; |
+ |
+class TestExternal : public ApplicationDelegate { |
+ public: |
+ TestExternal() : configure_incoming_connection_called_(false) {} |
+ |
+ void Initialize(ApplicationImpl* app) override { |
+ initialize_args_ = app->args(); |
+ base::MessageLoop::current()->Quit(); |
+ } |
+ |
+ bool ConfigureIncomingConnection(ApplicationConnection* connection) override { |
+ configure_incoming_connection_called_ = true; |
+ base::MessageLoop::current()->Quit(); |
+ return true; |
+ } |
+ |
+ const std::vector<std::string>& initialize_args() const { |
+ return initialize_args_; |
+ } |
+ |
+ bool configure_incoming_connection_called() const { |
+ return configure_incoming_connection_called_; |
+ } |
+ |
+ private: |
+ std::vector<std::string> initialize_args_; |
+ bool configure_incoming_connection_called_; |
+}; |
+ |
+class ApplicationManagerTest : public testing::Test { |
+ public: |
+ ApplicationManagerTest() : tester_context_(&loop_) {} |
+ |
+ ~ApplicationManagerTest() override {} |
+ |
+ void SetUp() override { |
+ application_manager_.reset(new ApplicationManager(&test_delegate_)); |
+ test_loader_ = new TestApplicationLoader; |
+ test_loader_->set_context(&context_); |
+ application_manager_->set_default_loader( |
+ scoped_ptr<ApplicationLoader>(test_loader_)); |
+ |
+ TestServicePtr service_proxy; |
+ application_manager_->ConnectToService(GURL(kTestURLString), |
+ &service_proxy); |
+ test_client_.reset(new TestClient(service_proxy.Pass())); |
+ } |
+ |
+ void TearDown() override { |
+ test_client_.reset(); |
+ application_manager_.reset(); |
+ } |
+ |
+ void AddLoaderForURL(const GURL& url, const std::string& requestor_url) { |
+ application_manager_->SetLoaderForURL( |
+ make_scoped_ptr(new Tester(&tester_context_, requestor_url)), url); |
+ } |
+ |
+ bool HasFactoryForTestURL() { |
+ ApplicationManager::TestAPI manager_test_api(application_manager_.get()); |
+ return manager_test_api.HasFactoryForURL(GURL(kTestURLString)); |
+ } |
+ |
+ protected: |
+ base::ShadowingAtExitManager at_exit_; |
+ TestDelegate test_delegate_; |
+ TestApplicationLoader* test_loader_; |
+ TesterContext tester_context_; |
+ TestContext context_; |
+ base::MessageLoop loop_; |
+ scoped_ptr<TestClient> test_client_; |
+ scoped_ptr<ApplicationManager> application_manager_; |
+ DISALLOW_COPY_AND_ASSIGN(ApplicationManagerTest); |
+}; |
+ |
+TEST_F(ApplicationManagerTest, Basic) { |
+ test_client_->Test("test"); |
+ loop_.Run(); |
+ EXPECT_EQ(std::string("test"), context_.last_test_string); |
+} |
+ |
+// Confirm that no arguments are sent to an application by default. |
+TEST_F(ApplicationManagerTest, NoArgs) { |
+ ApplicationManager am(&test_delegate_); |
+ GURL test_url("test:test"); |
+ TestApplicationLoader* loader = new TestApplicationLoader; |
+ loader->set_context(&context_); |
+ am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(loader), test_url); |
+ TestServicePtr test_service; |
+ am.ConnectToService(test_url, &test_service); |
+ TestClient test_client(test_service.Pass()); |
+ test_client.Test("test"); |
+ loop_.Run(); |
+ std::vector<std::string> app_args = loader->GetArgs(); |
+ EXPECT_EQ(0U, app_args.size()); |
+} |
+ |
+// Confirm that arguments are sent to an application. |
+TEST_F(ApplicationManagerTest, Args) { |
+ ApplicationManager am(&test_delegate_); |
+ GURL test_url("test:test"); |
+ std::vector<std::string> args; |
+ args.push_back("test_arg1"); |
+ args.push_back("test_arg2"); |
+ am.SetArgsForURL(args, test_url); |
+ TestApplicationLoader* loader = new TestApplicationLoader; |
+ loader->set_context(&context_); |
+ am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(loader), test_url); |
+ TestServicePtr test_service; |
+ am.ConnectToService(test_url, &test_service); |
+ TestClient test_client(test_service.Pass()); |
+ test_client.Test("test"); |
+ loop_.Run(); |
+ std::vector<std::string> app_args = loader->GetArgs(); |
+ ASSERT_EQ(args.size(), app_args.size()); |
+ EXPECT_EQ(args[0], app_args[0]); |
+ EXPECT_EQ(args[1], app_args[1]); |
+} |
+ |
+// Confirm that arguments are aggregated through mappings. |
+TEST_F(ApplicationManagerTest, ArgsAndMapping) { |
+ ApplicationManager am(&test_delegate_); |
+ GURL test_url("test:test"); |
+ GURL test_url2("test:test2"); |
+ test_delegate_.AddMapping(test_url, test_url2); |
+ std::vector<std::string> args; |
+ args.push_back("test_arg1"); |
+ args.push_back("test_arg2"); |
+ am.SetArgsForURL(args, test_url); |
+ std::vector<std::string> args2; |
+ args2.push_back("test_arg3"); |
+ args2.push_back("test_arg4"); |
+ am.SetArgsForURL(args2, test_url2); |
+ TestApplicationLoader* loader = new TestApplicationLoader; |
+ loader->set_context(&context_); |
+ am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(loader), test_url2); |
+ { |
+ // Connext to the mapped url |
+ TestServicePtr test_service; |
+ am.ConnectToService(test_url, &test_service); |
+ TestClient test_client(test_service.Pass()); |
+ test_client.Test("test"); |
+ loop_.Run(); |
+ std::vector<std::string> app_args = loader->GetArgs(); |
+ ASSERT_EQ(args.size() + args2.size(), app_args.size()); |
+ EXPECT_EQ(args[0], app_args[0]); |
+ EXPECT_EQ(args[1], app_args[1]); |
+ EXPECT_EQ(args2[0], app_args[2]); |
+ EXPECT_EQ(args2[1], app_args[3]); |
+ } |
+ { |
+ // Connext to the target url |
+ TestServicePtr test_service; |
+ am.ConnectToService(test_url2, &test_service); |
+ TestClient test_client(test_service.Pass()); |
+ test_client.Test("test"); |
+ loop_.Run(); |
+ std::vector<std::string> app_args = loader->GetArgs(); |
+ ASSERT_EQ(args.size() + args2.size(), app_args.size()); |
+ EXPECT_EQ(args[0], app_args[0]); |
+ EXPECT_EQ(args[1], app_args[1]); |
+ EXPECT_EQ(args2[0], app_args[2]); |
+ EXPECT_EQ(args2[1], app_args[3]); |
+ } |
+} |
+ |
+TEST_F(ApplicationManagerTest, ClientError) { |
+ test_client_->Test("test"); |
+ EXPECT_TRUE(HasFactoryForTestURL()); |
+ loop_.Run(); |
+ EXPECT_EQ(1, context_.num_impls); |
+ test_client_.reset(); |
+ loop_.Run(); |
+ EXPECT_EQ(0, context_.num_impls); |
+ EXPECT_TRUE(HasFactoryForTestURL()); |
+} |
+ |
+TEST_F(ApplicationManagerTest, Deletes) { |
+ { |
+ ApplicationManager am(&test_delegate_); |
+ TestApplicationLoader* default_loader = new TestApplicationLoader; |
+ default_loader->set_context(&context_); |
+ TestApplicationLoader* url_loader1 = new TestApplicationLoader; |
+ TestApplicationLoader* url_loader2 = new TestApplicationLoader; |
+ url_loader1->set_context(&context_); |
+ url_loader2->set_context(&context_); |
+ TestApplicationLoader* scheme_loader1 = new TestApplicationLoader; |
+ TestApplicationLoader* scheme_loader2 = new TestApplicationLoader; |
+ scheme_loader1->set_context(&context_); |
+ scheme_loader2->set_context(&context_); |
+ am.set_default_loader(scoped_ptr<ApplicationLoader>(default_loader)); |
+ am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(url_loader1), |
+ GURL("test:test1")); |
+ am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(url_loader2), |
+ GURL("test:test1")); |
+ am.SetLoaderForScheme(scoped_ptr<ApplicationLoader>(scheme_loader1), |
+ "test"); |
+ am.SetLoaderForScheme(scoped_ptr<ApplicationLoader>(scheme_loader2), |
+ "test"); |
+ } |
+ EXPECT_EQ(5, context_.num_loader_deletes); |
+} |
+ |
+// Confirm that both urls and schemes can have their loaders explicitly set. |
+TEST_F(ApplicationManagerTest, SetLoaders) { |
+ TestApplicationLoader* default_loader = new TestApplicationLoader; |
+ TestApplicationLoader* url_loader = new TestApplicationLoader; |
+ TestApplicationLoader* scheme_loader = new TestApplicationLoader; |
+ application_manager_->set_default_loader( |
+ scoped_ptr<ApplicationLoader>(default_loader)); |
+ application_manager_->SetLoaderForURL( |
+ scoped_ptr<ApplicationLoader>(url_loader), GURL("test:test1")); |
+ application_manager_->SetLoaderForScheme( |
+ scoped_ptr<ApplicationLoader>(scheme_loader), "test"); |
+ |
+ // test::test1 should go to url_loader. |
+ TestServicePtr test_service; |
+ application_manager_->ConnectToService(GURL("test:test1"), &test_service); |
+ EXPECT_EQ(1, url_loader->num_loads()); |
+ EXPECT_EQ(0, scheme_loader->num_loads()); |
+ EXPECT_EQ(0, default_loader->num_loads()); |
+ |
+ // test::test2 should go to scheme loader. |
+ application_manager_->ConnectToService(GURL("test:test2"), &test_service); |
+ EXPECT_EQ(1, url_loader->num_loads()); |
+ EXPECT_EQ(1, scheme_loader->num_loads()); |
+ EXPECT_EQ(0, default_loader->num_loads()); |
+ |
+ // http::test1 should go to default loader. |
+ application_manager_->ConnectToService(GURL("http:test1"), &test_service); |
+ EXPECT_EQ(1, url_loader->num_loads()); |
+ EXPECT_EQ(1, scheme_loader->num_loads()); |
+ EXPECT_EQ(1, default_loader->num_loads()); |
+} |
+ |
+// Confirm that the url of a service is correctly passed to another service that |
+// it loads. |
+TEST_F(ApplicationManagerTest, ACallB) { |
+ // Any url can load a. |
+ AddLoaderForURL(GURL(kTestAURLString), std::string()); |
+ |
+ // Only a can load b. |
+ AddLoaderForURL(GURL(kTestBURLString), kTestAURLString); |
+ |
+ TestAPtr a; |
+ application_manager_->ConnectToService(GURL(kTestAURLString), &a); |
+ a->CallB(); |
+ loop_.Run(); |
+ EXPECT_EQ(1, tester_context_.num_b_calls()); |
+ EXPECT_TRUE(tester_context_.a_called_quit()); |
+} |
+ |
+// A calls B which calls C. |
+TEST_F(ApplicationManagerTest, BCallC) { |
+ // Any url can load a. |
+ AddLoaderForURL(GURL(kTestAURLString), std::string()); |
+ |
+ // Only a can load b. |
+ AddLoaderForURL(GURL(kTestBURLString), kTestAURLString); |
+ |
+ TestAPtr a; |
+ application_manager_->ConnectToService(GURL(kTestAURLString), &a); |
+ a->CallCFromB(); |
+ loop_.Run(); |
+ |
+ EXPECT_EQ(1, tester_context_.num_b_calls()); |
+ EXPECT_EQ(1, tester_context_.num_c_calls()); |
+ EXPECT_TRUE(tester_context_.a_called_quit()); |
+} |
+ |
+// Confirm that a service impl will be deleted if the app that connected to |
+// it goes away. |
+TEST_F(ApplicationManagerTest, BDeleted) { |
+ AddLoaderForURL(GURL(kTestAURLString), std::string()); |
+ AddLoaderForURL(GURL(kTestBURLString), std::string()); |
+ |
+ TestAPtr a; |
+ application_manager_->ConnectToService(GURL(kTestAURLString), &a); |
+ |
+ a->CallB(); |
+ loop_.Run(); |
+ |
+ // Kills the a app. |
+ application_manager_->SetLoaderForURL(scoped_ptr<ApplicationLoader>(), |
+ GURL(kTestAURLString)); |
+ loop_.Run(); |
+ |
+ EXPECT_EQ(1, tester_context_.num_b_deletes()); |
+} |
+ |
+// Confirm that the url of a service is correctly passed to another service that |
+// it loads, and that it can be rejected. |
+TEST_F(ApplicationManagerTest, ANoLoadB) { |
+ // Any url can load a. |
+ AddLoaderForURL(GURL(kTestAURLString), std::string()); |
+ |
+ // Only c can load b, so this will fail. |
+ AddLoaderForURL(GURL(kTestBURLString), "test:TestC"); |
+ |
+ TestAPtr a; |
+ application_manager_->ConnectToService(GURL(kTestAURLString), &a); |
+ a->CallB(); |
+ loop_.Run(); |
+ EXPECT_EQ(0, tester_context_.num_b_calls()); |
+ |
+ EXPECT_FALSE(tester_context_.a_called_quit()); |
+ EXPECT_TRUE(tester_context_.tester_called_quit()); |
+} |
+ |
+TEST_F(ApplicationManagerTest, NoServiceNoLoad) { |
+ AddLoaderForURL(GURL(kTestAURLString), std::string()); |
+ |
+ // There is no TestC service implementation registered with |
+ // ApplicationManager, so this cannot succeed (but also shouldn't crash). |
+ TestCPtr c; |
+ application_manager_->ConnectToService(GURL(kTestAURLString), &c); |
+ QuitMessageLoopErrorHandler quitter; |
+ c.set_error_handler(&quitter); |
+ |
+ loop_.Run(); |
+ EXPECT_TRUE(c.encountered_error()); |
+} |
+ |
+TEST_F(ApplicationManagerTest, MappedURLsShouldNotCauseDuplicateLoad) { |
+ test_delegate_.AddMapping(GURL("foo:foo2"), GURL("foo:foo")); |
+ // 1 because ApplicationManagerTest connects once at startup. |
+ EXPECT_EQ(1, test_loader_->num_loads()); |
+ |
+ TestServicePtr test_service; |
+ application_manager_->ConnectToService(GURL("foo:foo"), &test_service); |
+ EXPECT_EQ(2, test_loader_->num_loads()); |
+ |
+ TestServicePtr test_service2; |
+ application_manager_->ConnectToService(GURL("foo:foo2"), &test_service2); |
+ EXPECT_EQ(2, test_loader_->num_loads()); |
+ |
+ TestServicePtr test_service3; |
+ application_manager_->ConnectToService(GURL("bar:bar"), &test_service2); |
+ EXPECT_EQ(3, test_loader_->num_loads()); |
+} |
+ |
+TEST_F(ApplicationManagerTest, MappedURLsShouldWorkWithLoaders) { |
+ TestApplicationLoader* custom_loader = new TestApplicationLoader; |
+ TestContext context; |
+ custom_loader->set_context(&context); |
+ application_manager_->SetLoaderForURL(make_scoped_ptr(custom_loader), |
+ GURL("mojo:foo")); |
+ test_delegate_.AddMapping(GURL("mojo:foo2"), GURL("mojo:foo")); |
+ |
+ TestServicePtr test_service; |
+ application_manager_->ConnectToService(GURL("mojo:foo2"), &test_service); |
+ EXPECT_EQ(1, custom_loader->num_loads()); |
+ custom_loader->set_context(nullptr); |
+} |
+ |
+TEST_F(ApplicationManagerTest, ExternalApp) { |
+ ApplicationPtr application; |
+ TestExternal external; |
+ std::vector<std::string> args; |
+ args.push_back("test"); |
+ ApplicationImpl app(&external, GetProxy(&application)); |
+ application_manager_->RegisterExternalApplication(GURL("mojo:test"), args, |
+ application.Pass()); |
+ loop_.Run(); |
+ EXPECT_EQ(args, external.initialize_args()); |
+ application_manager_->ConnectToServiceByName(GURL("mojo:test"), |
+ std::string()); |
+ loop_.Run(); |
+ EXPECT_TRUE(external.configure_incoming_connection_called()); |
+}; |
+ |
+TEST_F(ApplicationManagerTest, TestQueryWithLoaders) { |
+ TestApplicationLoader* url_loader = new TestApplicationLoader; |
+ TestApplicationLoader* scheme_loader = new TestApplicationLoader; |
+ application_manager_->SetLoaderForURL( |
+ scoped_ptr<ApplicationLoader>(url_loader), GURL("test:test1")); |
+ application_manager_->SetLoaderForScheme( |
+ scoped_ptr<ApplicationLoader>(scheme_loader), "test"); |
+ |
+ // test::test1 should go to url_loader. |
+ TestServicePtr test_service; |
+ application_manager_->ConnectToService(GURL("test:test1?foo=bar"), |
+ &test_service); |
+ EXPECT_EQ(1, url_loader->num_loads()); |
+ EXPECT_EQ(0, scheme_loader->num_loads()); |
+ |
+ // test::test2 should go to scheme loader. |
+ application_manager_->ConnectToService(GURL("test:test2?foo=bar"), |
+ &test_service); |
+ EXPECT_EQ(1, url_loader->num_loads()); |
+ EXPECT_EQ(1, scheme_loader->num_loads()); |
+} |
+ |
+TEST_F(ApplicationManagerTest, TestEndApplicationClosure) { |
+ ClosingApplicationLoader* loader = new ClosingApplicationLoader(); |
+ application_manager_->SetLoaderForScheme( |
+ scoped_ptr<ApplicationLoader>(loader), "test"); |
+ |
+ bool called = false; |
+ application_manager_->ConnectToApplication( |
+ GURL("test:test"), GURL(), nullptr, nullptr, |
+ base::Bind(&QuitClosure, base::Unretained(&called))); |
+ loop_.Run(); |
+ EXPECT_TRUE(called); |
+} |
+ |
+} // namespace |
+} // namespace shell |
+} // namespace mojo |