blob: 35f60f131786af0725c94149e051b981b202e968 [file] [log] [blame]
// 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/macros.h"
#include "base/memory/scoped_ptr.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/common/weak_binding_set.h"
#include "mojo/fetcher/about_fetcher.h"
#include "mojo/package_manager/package_manager_impl.h"
#include "mojo/shell/application_loader.h"
#include "mojo/shell/application_manager.h"
#include "mojo/util/filename_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
namespace fetcher {
namespace {
class TestContentHandler : public ApplicationDelegate,
public InterfaceFactory<ContentHandler>,
public ContentHandler {
public:
TestContentHandler() : response_number_(0) {}
~TestContentHandler() override {}
size_t response_number() const { return response_number_; }
const URLResponse* latest_response() const { return latest_response_.get(); }
private:
// Overridden from ApplicationDelegate:
void Initialize(ApplicationImpl* app) override {}
bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
connection->AddService<ContentHandler>(this);
return true;
}
// Overridden from InterfaceFactory<ContentHandler>:
void Create(ApplicationConnection* connection,
InterfaceRequest<ContentHandler> request) override {
bindings_.AddBinding(this, request.Pass());
}
// Overridden from ContentHandler:
void StartApplication(
InterfaceRequest<Application> application,
URLResponsePtr response,
const Callback<void()>& destruct_callback) override {
response_number_++;
latest_response_ = response.Pass();
destruct_callback.Run();
// Drop |application| request. This results in the application manager
// dropping the ServiceProvider interface request provided by the client
// who made the ConnectToApplication() call. Therefore the client could
// listen for connection error of the ServiceProvider interface to learn
// that StartApplication() has been called.
}
size_t response_number_;
URLResponsePtr latest_response_;
WeakBindingSet<ContentHandler> bindings_;
DISALLOW_COPY_AND_ASSIGN(TestContentHandler);
};
class TestLoader : public shell::ApplicationLoader {
public:
explicit TestLoader(ApplicationDelegate* delegate) : delegate_(delegate) {}
~TestLoader() override {}
private:
// Overridden from ApplicationLoader:
void Load(const GURL& url, InterfaceRequest<Application> request) override {
app_.reset(new ApplicationImpl(delegate_, request.Pass()));
}
ApplicationDelegate* delegate_;
scoped_ptr<ApplicationImpl> app_;
DISALLOW_COPY_AND_ASSIGN(TestLoader);
};
class AboutFetcherTest : public testing::Test {
public:
AboutFetcherTest() {}
~AboutFetcherTest() override {}
protected:
const TestContentHandler* html_content_handler() const {
return &html_content_handler_;
}
void ConnectAndWait(const std::string& url) {
base::RunLoop run_loop;
ServiceProviderPtr service_provider;
InterfaceRequest<ServiceProvider> service_provider_request =
GetProxy(&service_provider);
// This connection error handler will be called when:
// - TestContentHandler::StartApplication() has been called (please see
// comments in that method); or
// - the application manager fails to fetch the requested URL.
service_provider.set_connection_error_handler(
[&run_loop]() { run_loop.Quit(); });
scoped_ptr<shell::ConnectToApplicationParams> params(
new shell::ConnectToApplicationParams);
params->SetTargetURL(GURL(url));
params->set_services(service_provider_request.Pass());
application_manager_->ConnectToApplication(params.Pass());
run_loop.Run();
}
// Overridden from testing::Test:
void SetUp() override {
base::FilePath shell_dir;
PathService::Get(base::DIR_MODULE, &shell_dir);
scoped_ptr<package_manager::PackageManagerImpl> package_manager(
new package_manager::PackageManagerImpl(shell_dir, nullptr));
package_manager->RegisterContentHandler(
"text/html", GURL("test:html_content_handler"));
application_manager_.reset(
new shell::ApplicationManager(package_manager.Pass()));
application_manager_->SetLoaderForURL(
make_scoped_ptr(new TestLoader(&html_content_handler_)),
GURL("test:html_content_handler"));
}
void TearDown() override { application_manager_.reset(); }
private:
base::ShadowingAtExitManager at_exit_;
TestContentHandler html_content_handler_;
base::MessageLoop loop_;
scoped_ptr<shell::ApplicationManager> application_manager_;
DISALLOW_COPY_AND_ASSIGN(AboutFetcherTest);
};
TEST_F(AboutFetcherTest, AboutBlank) {
ConnectAndWait("about:blank");
ASSERT_EQ(1u, html_content_handler()->response_number());
const URLResponse* response = html_content_handler()->latest_response();
EXPECT_EQ("about:blank", response->url);
EXPECT_EQ(200u, response->status_code);
EXPECT_EQ("text/html", response->mime_type);
EXPECT_FALSE(response->body.is_valid());
}
TEST_F(AboutFetcherTest, UnrecognizedURL) {
ConnectAndWait("about:some_unrecognized_url");
ASSERT_EQ(1u, html_content_handler()->response_number());
const URLResponse* response = html_content_handler()->latest_response();
EXPECT_EQ("about:some_unrecognized_url", response->url);
EXPECT_EQ(404u, response->status_code);
EXPECT_EQ("text/html", response->mime_type);
EXPECT_FALSE(response->body.is_valid());
}
} // namespace
} // namespace fetcher
} // namespace mojo