// Copyright 2015 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 "base/path_service.h" #include "base/run_loop.h" #include "mojo/application/public/cpp/application_connection.h" #include "mojo/application/public/cpp/application_delegate.h" #include "mojo/application/public/cpp/application_impl.h" #include "mojo/application/public/cpp/interface_factory.h" #include "mojo/application/public/interfaces/content_handler.mojom.h" #include "mojo/application/public/interfaces/service_provider.mojom.h" #include "mojo/package_manager/package_manager_impl.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/shell/application_loader.h" #include "mojo/shell/application_manager.h" #include "mojo/shell/connect_util.h" #include "mojo/shell/fetcher.h" #include "mojo/shell/test_package_manager.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { namespace package_manager { namespace test { namespace { const char kTestMimeType[] = "test/mime-type"; class TestFetcher : public shell::Fetcher { public: TestFetcher(const FetchCallback& fetch_callback, const GURL& url, const std::string& mime_type) : Fetcher(fetch_callback), url_(url), mime_type_(mime_type) { loader_callback_.Run(make_scoped_ptr(this)); } ~TestFetcher() override {} // Fetcher: const GURL& GetURL() const override { return url_; } GURL GetRedirectURL() const override { return GURL("yyy"); } GURL GetRedirectReferer() const override { return GURL(); } URLResponsePtr AsURLResponse(base::TaskRunner* task_runner, uint32_t skip) override { return URLResponse::New().Pass(); } void AsPath( base::TaskRunner* task_runner, base::Callback callback) override {} std::string MimeType() override { return mime_type_; } bool HasMojoMagic() override { return false; } bool PeekFirstLine(std::string* line) override { return false; } private: const GURL url_; const std::string mime_type_; DISALLOW_COPY_AND_ASSIGN(TestFetcher); }; void QuitClosure(bool* value) { *value = true; base::MessageLoop::current()->QuitWhenIdle(); } class TestContentHandler : public ContentHandler, public ApplicationDelegate { public: TestContentHandler(ApplicationConnection* connection, InterfaceRequest request) : binding_(this, request.Pass()) {} // ContentHandler: void StartApplication( InterfaceRequest application_request, URLResponsePtr response, const Callback& destruct_callback) override { apps_.push_back(new ApplicationImpl(this, application_request.Pass())); destruct_callback.Run(); } private: StrongBinding binding_; ScopedVector apps_; DISALLOW_COPY_AND_ASSIGN(TestContentHandler); }; class TestApplicationLoader : public shell::ApplicationLoader, public ApplicationDelegate, public InterfaceFactory { public: TestApplicationLoader() : num_loads_(0) {} ~TestApplicationLoader() override {} int num_loads() const { return num_loads_; } const GURL& last_requestor_url() const { return last_requestor_url_; } private: // ApplicationLoader implementation. void Load(const GURL& url, InterfaceRequest application_request) override { ++num_loads_; test_app_.reset(new ApplicationImpl(this, application_request.Pass())); } // ApplicationDelegate implementation. bool ConfigureIncomingConnection(ApplicationConnection* connection) override { connection->AddService(this); last_requestor_url_ = GURL(connection->GetRemoteApplicationURL()); return true; } // InterfaceFactory implementation. void Create(ApplicationConnection* connection, InterfaceRequest request) override { new TestContentHandler(connection, request.Pass()); } scoped_ptr test_app_; int num_loads_; GURL last_requestor_url_; DISALLOW_COPY_AND_ASSIGN(TestApplicationLoader); }; class TestPackageManager : public PackageManagerImpl { public: explicit TestPackageManager(const base::FilePath& package_path) : PackageManagerImpl(package_path, nullptr), mime_type_(kTestMimeType) {} ~TestPackageManager() override {} void set_mime_type(const std::string& mime_type) { mime_type_ = mime_type; } // PackageManagerImpl: void FetchRequest( URLRequestPtr request, const shell::Fetcher::FetchCallback& loader_callback) override { new TestFetcher(loader_callback, GURL(request->url), mime_type_); } private: std::string mime_type_; DISALLOW_COPY_AND_ASSIGN(TestPackageManager); }; } // namespace class ContentHandlerTest : public testing::Test { public: ContentHandlerTest() : content_handler_url_("http://test.content.handler"), requestor_url_("http://requestor.url") {} ~ContentHandlerTest() override {} void SetUp() override { base::FilePath shell_dir; PathService::Get(base::DIR_MODULE, &shell_dir); test_package_manager_ = new TestPackageManager(shell_dir); test_package_manager_->RegisterContentHandler(kTestMimeType, content_handler_url_); application_manager_.reset(new shell::ApplicationManager( make_scoped_ptr(test_package_manager_))); } void TearDown() override { test_package_manager_ = nullptr; application_manager_.reset(); } protected: const GURL content_handler_url_; const GURL requestor_url_; base::MessageLoop loop_; scoped_ptr application_manager_; // Owned by ApplicationManager. TestPackageManager* test_package_manager_; DISALLOW_COPY_AND_ASSIGN(ContentHandlerTest); }; TEST_F(ContentHandlerTest, ContentHandlerConnectionGetsRequestorURL) { TestApplicationLoader* loader = new TestApplicationLoader; application_manager_->SetLoaderForURL( scoped_ptr(loader), content_handler_url_); bool called = false; scoped_ptr params( new shell::ConnectToApplicationParams); params->set_source(shell::Identity(requestor_url_)); params->SetTargetURL(GURL("test:test")); params->set_on_application_end( base::Bind(&QuitClosure, base::Unretained(&called))); application_manager_->ConnectToApplication(params.Pass()); loop_.Run(); EXPECT_TRUE(called); ASSERT_EQ(1, loader->num_loads()); EXPECT_EQ(requestor_url_, loader->last_requestor_url()); } TEST_F(ContentHandlerTest, MultipleConnectionsToContentHandlerGetSameContentHandlerId) { TestApplicationLoader* content_handler_loader = new TestApplicationLoader; application_manager_->SetLoaderForURL( scoped_ptr(content_handler_loader), content_handler_url_); uint32_t content_handler_id; { base::RunLoop run_loop; scoped_ptr params( new shell::ConnectToApplicationParams); params->set_source(shell::Identity(requestor_url_)); params->SetTargetURL(GURL("test:test")); params->set_connect_callback([&content_handler_id, &run_loop](uint32_t t) { content_handler_id = t; run_loop.Quit(); }); application_manager_->ConnectToApplication(params.Pass()); run_loop.Run(); EXPECT_NE(Shell::kInvalidContentHandlerID, content_handler_id); } uint32_t content_handler_id2; { base::RunLoop run_loop; scoped_ptr params( new shell::ConnectToApplicationParams); params->set_source(shell::Identity(requestor_url_)); params->SetTargetURL(GURL("test:test")); params->set_connect_callback([&content_handler_id2, &run_loop](uint32_t t) { content_handler_id2 = t; run_loop.Quit(); }); application_manager_->ConnectToApplication(params.Pass()); run_loop.Run(); EXPECT_NE(Shell::kInvalidContentHandlerID, content_handler_id2); } EXPECT_EQ(content_handler_id, content_handler_id2); } TEST_F(ContentHandlerTest, DifferedContentHandlersGetDifferentIDs) { TestApplicationLoader* content_handler_loader = new TestApplicationLoader; application_manager_->SetLoaderForURL( scoped_ptr(content_handler_loader), content_handler_url_); uint32_t content_handler_id; { base::RunLoop run_loop; scoped_ptr params( new shell::ConnectToApplicationParams); params->set_source(shell::Identity(requestor_url_)); params->SetTargetURL(GURL("test:test")); params->set_connect_callback([&content_handler_id, &run_loop](uint32_t t) { content_handler_id = t; run_loop.Quit(); }); application_manager_->ConnectToApplication(params.Pass()); run_loop.Run(); EXPECT_NE(Shell::kInvalidContentHandlerID, content_handler_id); } const std::string mime_type2 = "test/mime-type2"; const GURL content_handler_url2("http://test.content.handler2"); test_package_manager_->set_mime_type(mime_type2); test_package_manager_->RegisterContentHandler(mime_type2, content_handler_url2); TestApplicationLoader* content_handler_loader2 = new TestApplicationLoader; application_manager_->SetLoaderForURL( scoped_ptr(content_handler_loader2), content_handler_url2); uint32_t content_handler_id2; { base::RunLoop run_loop; scoped_ptr params( new shell::ConnectToApplicationParams); params->set_source(shell::Identity(requestor_url_)); params->SetTargetURL(GURL("test2:test2")); params->set_connect_callback([&content_handler_id2, &run_loop](uint32_t t) { content_handler_id2 = t; run_loop.Quit(); }); application_manager_->ConnectToApplication(params.Pass()); run_loop.Run(); EXPECT_NE(Shell::kInvalidContentHandlerID, content_handler_id2); } EXPECT_NE(content_handler_id, content_handler_id2); } TEST_F(ContentHandlerTest, ConnectWithNoContentHandlerGetsInvalidContentHandlerId) { application_manager_->SetLoaderForURL( scoped_ptr(new TestApplicationLoader), GURL("test:test")); uint32_t content_handler_id = 1u; scoped_ptr params( new shell::ConnectToApplicationParams); params->SetTargetURL(GURL("test:test")); params->set_connect_callback( [&content_handler_id](uint32_t t) { content_handler_id = t; }); application_manager_->ConnectToApplication(params.Pass()); EXPECT_EQ(0u, content_handler_id); } } // namespace test } // namespace package_manager } // namespace mojo