0

Reland: [Fuchsia] Cleanup cast_runner integration tests.

Removed test-only methods from CastRunner, WebContentRunner and
CastComponent that were previously used in
cast_runner_integration_tests.

1. Removed CastRunner and WebContentRunner constructors that take
web.Context. Now context is always created in WebContentRunner.
2. Removed test-only methods.
3. Updated TestComponentContext to allow initialization with all
services cloned from /svc.

The tests now inject a script into the frame in order to test
functionality that was previously tested with the test-only methods.

Previous attempt to land this CL was reverted due to flake in
CastRunnerIntegrationTest.CanRecreateContext test. The test kills
WebEngine and was waiting Component termination and assumed that
Context and ContextProvider were torn down as well, but they may
be destroyed with some delay. To fix this issue this version of the
CL adds explicit wait for Context destruction and removes
ContextProvider caching from WebContentRunner.

Bug: 1062351
Change-Id: I18fa11e85d2194bba1ed3896167a64fac8a51c0b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2143494
Commit-Queue: Kevin Marshall <kmarshall@chromium.org>
Reviewed-by: Kevin Marshall <kmarshall@chromium.org>
Auto-Submit: Sergey Ulanov <sergeyu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#758053}
This commit is contained in:
Sergey Ulanov
2020-04-09 22:46:45 +00:00
committed by Commit Bot
parent 164abacd72
commit f1d9f13c9a
17 changed files with 323 additions and 405 deletions

@ -9,6 +9,7 @@
#include <lib/fidl/cpp/interface_handle.h>
#include <lib/sys/cpp/component_context.h>
#include "base/files/file_enumerator.h"
#include "base/fuchsia/default_context.h"
#include "base/fuchsia/filtered_service_directory.h"
#include "base/fuchsia/fuchsia_logging.h"
@ -16,7 +17,8 @@
namespace base {
TestComponentContextForProcess::TestComponentContextForProcess() {
TestComponentContextForProcess::TestComponentContextForProcess(
InitialState initial_state) {
// TODO(https://crbug.com/1038786): Migrate to sys::ComponentContextProvider
// once it provides access to an sys::OutgoingDirectory or PseudoDir through
// which to publish additional_services().
@ -26,6 +28,15 @@ TestComponentContextForProcess::TestComponentContextForProcess() {
context_services_ = std::make_unique<fuchsia::FilteredServiceDirectory>(
base::fuchsia::ComponentContextForCurrentProcess()->svc().get());
// Push all services from /svc to the test context if requested.
if (initial_state == InitialState::kCloneAll) {
base::FileEnumerator file_enum(base::FilePath("/svc"), false,
base::FileEnumerator::FILES);
for (auto file = file_enum.Next(); !file.empty(); file = file_enum.Next()) {
AddService(file.BaseName().value());
}
}
// Create a ServiceDirectory backed by the contents of |incoming_directory|.
fidl::InterfaceHandle<::fuchsia::io::Directory> incoming_directory;
context_services_->ConnectClient(incoming_directory.NewRequest());
@ -60,10 +71,15 @@ sys::OutgoingDirectory* TestComponentContextForProcess::additional_services() {
return context_services_->outgoing_directory();
}
void TestComponentContextForProcess::AddService(
const base::StringPiece service) {
context_services_->AddService(service);
}
void TestComponentContextForProcess::AddServices(
base::span<const base::StringPiece> services) {
for (auto service : services)
context_services_->AddService(service);
AddService(service);
}
} // namespace base

@ -41,18 +41,25 @@ class FilteredServiceDirectory;
// test base-class:
//
// TEST(MyFunkyTest, IsFunky) {
// TestComponentContextForTest test_context;
// TestComponentContextForProcess test_context;
// // Configure the |test_context|.
// // Run tests of code that uses ComponentContextForProcess().
// }
//
// Services from the original process-global ComponentContext (usually the
// environment in which the test process is running), can be exposed through the
// |test_context| with AddServices(), during test setup:
// By default created context doesn't expose any services. Services from the
// original process-global ComponentContext (usually the environment in which
// the test process is running), can be exposed through the |test_context| with
// AddServices(), during test setup:
//
// test_context.AddServices({fuchsia::memorypressure::Provider::Name_, ...});
// // ... Execute tests which use fuchsia.memorypressure.Provider ...
//
// Alternatively InitialState::kEmpty can be passed to the constructor to expose
// all services listed in /svc, e.g.:
//
// TestComponentContextForProcess test_context(
// TestComponentContextForProcess::InitialState::kEmpty);
//
// Fake/mock implementations can be exposed via additional_services():
//
// ScopedServiceBinding<funky::Service> binding(
@ -68,7 +75,13 @@ class FilteredServiceDirectory;
//
class BASE_EXPORT TestComponentContextForProcess {
public:
TestComponentContextForProcess();
enum class InitialState {
kEmpty,
kCloneAll,
};
TestComponentContextForProcess(
InitialState initial_state = InitialState::kEmpty);
~TestComponentContextForProcess();
TestComponentContextForProcess(const TestComponentContextForProcess&) =
@ -80,8 +93,9 @@ class BASE_EXPORT TestComponentContextForProcess {
// published for use by the code-under test.
sys::OutgoingDirectory* additional_services();
// Allows the specified services from the original ComponentContext to be
// Allows the specified service(s) from the original ComponentContext to be
// exposed via the test default ComponentContext.
void AddService(const base::StringPiece service);
void AddServices(base::span<const base::StringPiece> services);
// Returns the directory of services that the code under test has published

@ -20,7 +20,7 @@
namespace cr_fuchsia {
fuchsia::web::ContextProviderPtr ConnectContextProvider(
fidl::InterfaceHandle<fuchsia::io::Directory> StartWebEngineForTests(
fidl::InterfaceRequest<fuchsia::sys::ComponentController>
component_controller_request,
const base::CommandLine& command_line) {
@ -49,12 +49,16 @@ fuchsia::web::ContextProviderPtr ConnectContextProvider(
launcher->CreateComponent(std::move(launch_info),
std::move(component_controller_request));
sys::ServiceDirectory web_engine_service_dir(
std::move(web_engine_services_dir));
return web_engine_services_dir;
}
fuchsia::web::ContextProviderPtr context_provider;
web_engine_service_dir.Connect(context_provider.NewRequest());
return context_provider;
fuchsia::web::ContextProviderPtr ConnectContextProvider(
fidl::InterfaceRequest<fuchsia::sys::ComponentController>
component_controller_request,
const base::CommandLine& command_line) {
sys::ServiceDirectory web_engine_service_dir(StartWebEngineForTests(
std::move(component_controller_request), command_line));
return web_engine_service_dir.Connect<fuchsia::web::ContextProvider>();
}
} // namespace cr_fuchsia

@ -8,11 +8,18 @@
#include <fuchsia/sys/cpp/fidl.h>
#include <fuchsia/web/cpp/fidl.h>
#include <lib/fidl/cpp/interface_request.h>
#include <lib/sys/cpp/service_directory.h>
#include "base/command_line.h"
namespace cr_fuchsia {
fidl::InterfaceHandle<fuchsia::io::Directory> StartWebEngineForTests(
fidl::InterfaceRequest<fuchsia::sys::ComponentController>
component_controller_request,
const base::CommandLine& command_line =
base::CommandLine(base::CommandLine::NO_PROGRAM));
// TODO(crbug.com/1046615): Use test manifests for package specification.
fuchsia::web::ContextProviderPtr ConnectContextProvider(
fidl::InterfaceRequest<fuchsia::sys::ComponentController>

@ -156,7 +156,4 @@ void CastComponent::OnZxHandleSignalled(zx_handle_t handle,
DCHECK(runner()->is_headless());
frame()->DisableHeadlessRendering();
if (on_headless_disconnect_cb_)
std::move(on_headless_disconnect_cb_).Run();
}

@ -11,7 +11,6 @@
#include <vector>
#include "base/fuchsia/startup_context.h"
#include "base/gtest_prod_util.h"
#include "base/message_loop/message_pump_for_io.h"
#include "base/message_loop/message_pump_fuchsia.h"
#include "base/optional.h"
@ -58,13 +57,6 @@ class CastComponent : public WebComponent,
// WebComponent overrides.
void StartComponent() final;
// Sets a callback that will be invoked when the handle controlling the
// lifetime of a headless "view" is dropped.
void set_on_headless_disconnect_for_test(
base::OnceClosure on_headless_disconnect_cb) {
on_headless_disconnect_cb_ = std::move(on_headless_disconnect_cb);
}
const chromium::cast::ApplicationConfig& application_config() {
return application_config_;
}
@ -74,8 +66,6 @@ class CastComponent : public WebComponent,
CastRunner* runner() const;
private:
FRIEND_TEST_ALL_PREFIXES(HeadlessCastRunnerIntegrationTest, Headless);
void OnRewriteRulesReceived(
std::vector<fuchsia::web::UrlRequestRewriteRule> rewrite_rules);
@ -113,8 +103,6 @@ class CastComponent : public WebComponent,
zx::eventpair headless_view_token_;
base::MessagePumpForIO::ZxHandleWatchController headless_disconnect_watch_;
base::OnceClosure on_headless_disconnect_cb_;
fidl::Binding<fuchsia::web::NavigationEventListener>
navigation_listener_binding_;

@ -117,24 +117,13 @@ const char CastRunner::kAgentComponentUrl[] =
CastRunner::CastRunner(
WebContentRunner::GetContextParamsCallback get_context_params_callback,
bool is_headless,
sys::OutgoingDirectory* outgoing_directory)
bool is_headless)
: WebContentRunner(base::BindRepeating(&CastRunner::GetMainContextParams,
base::Unretained(this)),
outgoing_directory),
base::Unretained(this))),
get_context_params_callback_(std::move(get_context_params_callback)),
is_headless_(is_headless),
common_create_context_params_(BuildCreateContextParamsForIsolatedRunners(
get_context_params_callback_.Run())),
service_directory_(CreateServiceDirectory()) {}
CastRunner::CastRunner(OnDestructionCallback on_destruction_callback,
fuchsia::web::ContextPtr context,
bool is_headless)
: WebContentRunner(std::move(context)),
is_headless_(is_headless),
on_destruction_callback_(std::move(on_destruction_callback)) {}
CastRunner::~CastRunner() = default;
void CastRunner::StartComponent(
@ -212,10 +201,6 @@ void CastRunner::StartComponent(
pending_components_.emplace(std::move(pending_component_params));
}
size_t CastRunner::GetChildCastRunnerCountForTest() {
return isolated_runners_.size();
}
void CastRunner::DestroyComponent(WebComponent* component) {
WebContentRunner::DestroyComponent(component);
@ -370,16 +355,12 @@ void CastRunner::CreateAndRegisterCastComponent(
CastRunner* CastRunner::CreateChildRunnerForIsolatedComponent(
CastComponent::CastComponentParams* component_params) {
// Construct the CreateContextParams in order to create a new Context.
// Some common parameters must be inherited from
// |common_create_context_params_|.
fuchsia::web::CreateContextParams isolated_context_params;
zx_status_t status =
common_create_context_params_.Clone(&isolated_context_params);
if (status != ZX_OK) {
ZX_LOG(ERROR, status) << "clone";
return nullptr;
}
// Construct the CreateContextParams in order to create a new Context. Some
// common parameters must be inherited from default params returned from
// |get_context_params_callback_|.
fuchsia::web::CreateContextParams isolated_context_params =
BuildCreateContextParamsForIsolatedRunners(
get_context_params_callback_.Run());
// Service redirection is not necessary for isolated context. Pass default
// /svc as is, without overriding any services.
@ -391,17 +372,16 @@ CastRunner* CastRunner::CreateChildRunnerForIsolatedComponent(
std::move(*component_params->app_config
.mutable_content_directories_for_isolated_application()));
std::unique_ptr<CastRunner> cast_runner(new CastRunner(
base::BindOnce(&CastRunner::OnChildRunnerDestroyed,
base::Unretained(this)),
CreateWebContext(std::move(isolated_context_params)), is_headless()));
auto create_context_params_callback = base::BindRepeating(
[](fuchsia::web::CreateContextParams isolated_context_params) {
return isolated_context_params;
},
base::Passed(std::move(isolated_context_params)));
// If test code is listening for Component creation events, then wire up the
// isolated CastRunner to signal component creation events.
if (web_component_created_callback_for_test()) {
cast_runner->SetWebComponentCreatedCallbackForTest(
web_component_created_callback_for_test());
}
auto cast_runner = std::make_unique<CastRunner>(
std::move(create_context_params_callback), is_headless());
cast_runner->on_destruction_callback_ = base::BindOnce(
&CastRunner::OnChildRunnerDestroyed, base::Unretained(this));
CastRunner* cast_runner_ptr = cast_runner.get();
isolated_runners_.insert(std::move(cast_runner));

@ -29,16 +29,17 @@ class FilteredServiceDirectory;
// sys::Runner which instantiates Cast activities specified via cast/casts URIs.
class CastRunner : public WebContentRunner {
public:
using OnDestructionCallback = base::OnceCallback<void(CastRunner*)>;
static constexpr uint16_t kRemoteDebuggingPort = 9222;
// Creates a Runner for Cast components and publishes it into the specified
// OutgoingDirectory.
// |get_context_params_callback|: Returns the context parameters to use.
// |is_headless|: True if |get_context_params_callback| sets the HEADLESS
// feature flag.
// |outgoing_directory|: The directory that this CastRunner will publish
// itself to.
CastRunner(GetContextParamsCallback get_context_params_callback,
bool is_headless,
sys::OutgoingDirectory* outgoing_directory);
bool is_headless);
~CastRunner() override;
CastRunner(const CastRunner&) = delete;
@ -59,20 +60,7 @@ class CastRunner : public WebContentRunner {
// Returns true if this Runner is configured not to use Scenic.
bool is_headless() const { return is_headless_; }
// Returns the number of active CastRunner instances.
size_t GetChildCastRunnerCountForTest();
private:
using OnDestructionCallback = base::OnceCallback<void(CastRunner*)>;
// Constructor used for creating CastRunners that run apps in dedicated
// Contexts. Child CastRunners may only spawn one Component and will be
// destroyed by their parents when their singleton Components are destroyed.
// |on_destruction_callback| is invoked when the child component is destroyed.
CastRunner(OnDestructionCallback on_destruction_callback,
fuchsia::web::ContextPtr context,
bool is_headless);
// Creates and returns the service directory that is passed to the main web
// context.
std::unique_ptr<base::fuchsia::FilteredServiceDirectory>
@ -116,9 +104,6 @@ class CastRunner : public WebContentRunner {
base::UniquePtrComparator>
pending_components_;
// Used as a template for creating the ContextPtrs of isolated Runners.
fuchsia::web::CreateContextParams common_create_context_params_;
// Invoked upon destruction of "isolated" runners, used to signal termination
// to parents.
OnDestructionCallback on_destruction_callback_;

@ -8,13 +8,17 @@
#include <lib/sys/cpp/component_context.h>
#include <lib/ui/scenic/cpp/view_token_pair.h>
#include <lib/zx/channel.h>
#include <zircon/processargs.h>
#include "base/base_paths_fuchsia.h"
#include "base/callback_helpers.h"
#include "base/fuchsia/file_utils.h"
#include "base/fuchsia/filtered_service_directory.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/scoped_service_binding.h"
#include "base/fuchsia/test_component_context_for_process.h"
#include "base/path_service.h"
#include "base/strings/strcat.h"
#include "base/strings/stringprintf.h"
#include "base/test/bind_test_util.h"
#include "base/test/task_environment.h"
@ -26,6 +30,7 @@
#include "fuchsia/base/frame_test_util.h"
#include "fuchsia/base/fuchsia_dir_scheme.h"
#include "fuchsia/base/mem_buffer_util.h"
#include "fuchsia/base/release_channel.h"
#include "fuchsia/base/result_receiver.h"
#include "fuchsia/base/string_util.h"
#include "fuchsia/base/test_devtools_list_fetcher.h"
@ -34,11 +39,8 @@
#include "fuchsia/runners/cast/cast_runner.h"
#include "fuchsia/runners/cast/fake_application_config_manager.h"
#include "fuchsia/runners/cast/test_api_bindings.h"
#include "fuchsia/runners/common/web_component.h"
#include "fuchsia/runners/common/web_content_runner.h"
#include "net/test/embedded_test_server/default_handlers.h"
#include "net/test/embedded_test_server/http_request.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@ -47,7 +49,6 @@ constexpr char kTestAppId[] = "00000000";
constexpr char kBlankAppUrl[] = "/defaultresponse";
constexpr char kEchoHeaderPath[] = "/echoheader?Test";
constexpr char kEchoAppPath[] = "/echo.html";
constexpr char kTestServerRoot[] =
FILE_PATH_LITERAL("fuchsia/runners/cast/testdata");
@ -55,10 +56,6 @@ constexpr char kTestServerRoot[] =
constexpr char kDummyAgentUrl[] =
"fuchsia-pkg://fuchsia.com/dummy_agent#meta/dummy_agent.cmx";
void ComponentErrorHandler(zx_status_t status) {
ZX_LOG(ERROR, status) << "Component launch failed";
ADD_FAILURE();
}
// Helper used to ensure that cr_fuchsia::RegisterFuchsiaDirScheme() is called
// once per process to register fuchsia-dir scheme. In cast_runner this function
@ -94,7 +91,8 @@ class FakeUrlRequestRewriteRulesProvider
rules_sent_ = true;
std::vector<fuchsia::web::UrlRequestRewrite> rewrites;
rewrites.push_back(cr_fuchsia::CreateRewriteAddHeaders("Test", "Value"));
rewrites.push_back(
cr_fuchsia::CreateRewriteAddHeaders("Test", "TestHeaderValue"));
fuchsia::web::UrlRequestRewriteRule rule;
rule.set_rewrites(std::move(rewrites));
std::vector<fuchsia::web::UrlRequestRewriteRule> rules;
@ -197,31 +195,37 @@ class FakeComponentState : public cr_fuchsia::AgentImpl::ComponentStateBase {
context_binding_;
base::OnceClosure on_delete_;
};
} // namespace
class CastRunnerIntegrationTest : public testing::Test {
public:
CastRunnerIntegrationTest()
: CastRunnerIntegrationTest(fuchsia::web::ContextFeatureFlags::NETWORK) {}
CastRunnerIntegrationTest() : CastRunnerIntegrationTest(/*headless=*/false) {}
CastRunnerIntegrationTest(const CastRunnerIntegrationTest&) = delete;
CastRunnerIntegrationTest& operator=(const CastRunnerIntegrationTest&) =
delete;
void TearDown() override {
if (component_controller_)
ShutdownComponent();
// Disconnect the CastRunner & let things tear-down.
cast_runner_ptr_.Unbind();
base::RunLoop().RunUntilIdle();
}
protected:
explicit CastRunnerIntegrationTest(
fuchsia::web::ContextFeatureFlags feature_flags)
explicit CastRunnerIntegrationTest(bool headless)
: app_config_manager_binding_(&component_services_,
&app_config_manager_) {
EnsureFuchsiaDirSchemeInitialized();
// Create the CastRunner, published into |outgoing_directory_|.
fuchsia::web::ContextFeatureFlags feature_flags =
fuchsia::web::ContextFeatureFlags::NETWORK;
if (headless) {
feature_flags =
feature_flags | fuchsia::web::ContextFeatureFlags::HEADLESS;
}
WebContentRunner::GetContextParamsCallback get_context_params =
base::BindLambdaForTesting([feature_flags]() {
fuchsia::web::CreateContextParams create_context_params;
@ -231,19 +235,15 @@ class CastRunnerIntegrationTest : public testing::Test {
base::FilePath(base::fuchsia::kServiceDirectoryPath)));
CHECK(create_context_params.service_directory());
const uint16_t kRemoteDebuggingAnyPort = 0;
create_context_params.set_remote_debugging_port(
kRemoteDebuggingAnyPort);
CastRunner::kRemoteDebuggingPort);
return create_context_params;
});
cast_runner_ = std::make_unique<CastRunner>(
std::move(get_context_params),
(feature_flags & fuchsia::web::ContextFeatureFlags::HEADLESS) ==
fuchsia::web::ContextFeatureFlags::HEADLESS,
&outgoing_directory_);
cast_runner_ =
std::make_unique<CastRunner>(std::move(get_context_params), headless);
cast_runner_->PublishRunnerService(&outgoing_directory_);
cast_runner_->SetContextProviderForTest(cr_fuchsia::ConnectContextProvider(
context_provider_controller_.NewRequest()));
StartAndPublishWebEngine();
// Connect to the CastRunner's fuchsia.sys.Runner interface.
fidl::InterfaceHandle<fuchsia::io::Directory> directory;
@ -260,6 +260,24 @@ class CastRunnerIntegrationTest : public testing::Test {
test_server_.ServeFilesFromSourceDirectory(kTestServerRoot);
net::test_server::RegisterDefaultHandlers(&test_server_);
EXPECT_TRUE(test_server_.Start());
// Inject ApiBinding that used by ExecuteJavaScript().
std::vector<chromium::cast::ApiBinding> binding_list;
chromium::cast::ApiBinding eval_js_binding;
eval_js_binding.set_before_load_script(cr_fuchsia::MemBufferFromString(
"window.addEventListener('DOMContentLoaded', (event) => {"
" var port = cast.__platform__.PortConnector.bind('testport');"
" port.onmessage = (e) => {"
" var result = eval(e.data);"
" if (typeof(result) == \"undefined\") {"
" result = \"undefined\";"
" }"
" port.postMessage(result);"
" };"
"});",
"test"));
binding_list.emplace_back(std::move(eval_js_binding));
api_bindings_.set_bindings(std::move(binding_list));
}
std::unique_ptr<cr_fuchsia::AgentImpl::ComponentStateBase> OnComponentConnect(
@ -269,12 +287,31 @@ class CastRunnerIntegrationTest : public testing::Test {
url_request_rewrite_rules_provider_.get());
component_state_ = component_state.get();
if (init_component_state_callback_)
std::move(init_component_state_callback_).Run(component_state_);
if (component_state_created_callback_)
std::move(component_state_created_callback_).Run();
return component_state;
}
void StartAndPublishWebEngine() {
fidl::InterfaceHandle<fuchsia::io::Directory> web_engine_outgoing_dir =
cr_fuchsia::StartWebEngineForTests(web_engine_controller_.NewRequest());
sys::ServiceDirectory web_engine_outgoing_services(
std::move(web_engine_outgoing_dir));
test_component_context_.additional_services()
->RemovePublicService<fuchsia::web::ContextProvider>();
test_component_context_.additional_services()->AddPublicService(
std::make_unique<vfs::Service>(
[web_engine_outgoing_services =
std::move(web_engine_outgoing_services)](
zx::channel channel, async_dispatcher_t* dispatcher) {
web_engine_outgoing_services.Connect(
fuchsia::web::ContextProvider::Name_, std::move(channel));
}),
fuchsia::web::ContextProvider::Name_);
}
void RegisterAppWithTestData(GURL url) {
fuchsia::web::ContentDirectoryProvider provider;
provider.set_name("testdata");
@ -296,7 +333,8 @@ class CastRunnerIntegrationTest : public testing::Test {
auto component_url = base::StringPrintf("cast:%s", kTestAppId);
CreateComponentContext(component_url);
StartCastComponent(component_url);
WaitComponentCreated();
WaitComponentState();
WaitTestPort();
}
void CreateComponentContext(const base::StringPiece& component_url) {
@ -322,7 +360,7 @@ class CastRunnerIntegrationTest : public testing::Test {
startup_info.launch_info.directory_request =
outgoing_directory.NewRequest().TakeChannel();
fidl::InterfaceHandle<::fuchsia::io::Directory> svc_directory;
fidl::InterfaceHandle<fuchsia::io::Directory> svc_directory;
CHECK_EQ(fdio_service_connect_at(
outgoing_directory.channel().get(), "svc",
svc_directory.NewRequest().TakeChannel().release()),
@ -340,40 +378,67 @@ class CastRunnerIntegrationTest : public testing::Test {
fuchsia::sys::Package package;
package.resolved_url = component_url.as_string();
cast_runner_ptr_->StartComponent(std::move(package),
std::move(startup_info),
component_controller_.NewRequest());
component_controller_.set_error_handler(&ComponentErrorHandler);
cast_runner_->StartComponent(std::move(package), std::move(startup_info),
component_controller_.NewRequest());
component_controller_.set_error_handler([](zx_status_t status) {
ZX_LOG(ERROR, status) << "Component launch failed";
ADD_FAILURE();
});
}
void WaitComponentCreated() {
ASSERT_FALSE(cast_component_);
// Executes |code| in the context of the test application and the returns
// serialized as string.
std::string ExecuteJavaScript(const std::string& code) {
fuchsia::web::WebMessage message;
message.set_data(cr_fuchsia::MemBufferFromString(code, "test-msg"));
test_port_->PostMessage(
std::move(message),
[](fuchsia::web::MessagePort_PostMessage_Result result) {
EXPECT_TRUE(result.is_response());
});
base::RunLoop response_loop;
cr_fuchsia::ResultReceiver<fuchsia::web::WebMessage> response(
response_loop.QuitClosure());
test_port_->ReceiveMessage(
cr_fuchsia::CallbackToFitFunction(response.GetReceiveCallback()));
response_loop.Run();
std::string response_string;
EXPECT_TRUE(
cr_fuchsia::StringFromMemBuffer(response->data(), &response_string));
return response_string;
}
void WaitComponentState() {
base::RunLoop run_loop;
cr_fuchsia::ResultReceiver<WebComponent*> component_receiver(
run_loop.QuitClosure());
cast_runner_->SetWebComponentCreatedCallbackForTest(
base::AdaptCallbackForRepeating(
component_receiver.GetReceiveCallback()));
component_state_created_callback_ = run_loop.QuitClosure();
run_loop.Run();
ASSERT_NE(*component_receiver, nullptr);
cast_component_ = reinterpret_cast<CastComponent*>(*component_receiver);
}
void WaitUrlAndTitle(const GURL& url, const std::string& title) {
void WaitTestPort() {
CHECK(!test_port_);
test_port_ = api_bindings_.RunUntilMessagePortReceived("testport").Bind();
}
void CheckAppUrl(const GURL& app_url) {
EXPECT_EQ(ExecuteJavaScript("window.location.href"), app_url.spec());
}
void ShutdownComponent() {
DCHECK(component_controller_);
base::RunLoop run_loop;
cr_fuchsia::TestNavigationListener listener;
fidl::Binding<fuchsia::web::NavigationEventListener> listener_binding(
&listener);
cast_component_->frame()->SetNavigationEventListener(
listener_binding.NewBinding());
listener.RunUntilUrlAndTitleEquals(url, title);
component_state_->set_on_delete(run_loop.QuitClosure());
component_controller_.Unbind();
run_loop.Run();
component_controller_ = nullptr;
}
void WaitForComponentDestroyed() {
ASSERT_TRUE(cast_component_);
ASSERT_TRUE(component_state_);
base::RunLoop state_loop;
component_state_->set_on_delete(state_loop.QuitClosure());
@ -392,13 +457,14 @@ class CastRunnerIntegrationTest : public testing::Test {
component_context_ = nullptr;
component_services_client_ = nullptr;
component_state_ = nullptr;
cast_component_ = nullptr;
}
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
net::EmbeddedTestServer test_server_;
fuchsia::sys::ComponentControllerPtr web_engine_controller_;
FakeApplicationConfigManager app_config_manager_;
TestApiBindings api_bindings_;
std::unique_ptr<FakeUrlRequestRewriteRulesProvider>
@ -412,16 +478,17 @@ class CastRunnerIntegrationTest : public testing::Test {
fuchsia::sys::ComponentControllerPtr component_controller_;
std::unique_ptr<sys::ServiceDirectory> component_services_client_;
FakeComponentState* component_state_ = nullptr;
CastComponent* cast_component_ = nullptr;
fuchsia::web::MessagePortPtr test_port_;
base::OnceCallback<void(FakeComponentState*)> init_component_state_callback_;
base::OnceClosure component_state_created_callback_;
// ServiceDirectory into which the CastRunner will publish itself.
sys::OutgoingDirectory outgoing_directory_;
std::unique_ptr<CastRunner> cast_runner_;
fuchsia::sys::RunnerPtr cast_runner_ptr_;
fuchsia::sys::ComponentControllerPtr context_provider_controller_;
base::TestComponentContextForProcess test_component_context_{
base::TestComponentContextForProcess::InitialState::kCloneAll};
};
// A basic integration test ensuring a basic cast request launches the right
@ -431,28 +498,8 @@ TEST_F(CastRunnerIntegrationTest, BasicRequest) {
app_config_manager_.AddApp(kTestAppId, app_url);
CreateComponentContextAndStartComponent();
fuchsia::web::NavigationControllerPtr nav_controller;
cast_component_->frame()->GetNavigationController(
nav_controller.NewRequest());
// Ensure the NavigationState has the expected URL.
{
base::RunLoop run_loop;
cr_fuchsia::ResultReceiver<fuchsia::web::NavigationState> nav_entry(
run_loop.QuitClosure());
nav_controller->GetVisibleEntry(
cr_fuchsia::CallbackToFitFunction(nav_entry.GetReceiveCallback()));
run_loop.Run();
ASSERT_TRUE(nav_entry->has_url());
EXPECT_EQ(nav_entry->url(), app_url.spec());
}
EXPECT_FALSE(cast_runner_->is_headless());
// Verify that the component is torn down when |component_controller| is
// unbound.
component_controller_.Unbind();
WaitForComponentDestroyed();
CheckAppUrl(app_url);
}
// Verify that the Runner can continue to be used even after its Context has
@ -462,67 +509,40 @@ TEST_F(CastRunnerIntegrationTest, CanRecreateContext) {
// Execute two iterations of launching the component and verifying that it
// reaches the expected URL.
for (int i = 0; i < 2; ++i) {
SCOPED_TRACE(testing::Message() << "Test iteration " << i);
const GURL app_url = test_server_.GetURL(kBlankAppUrl);
app_config_manager_.AddApp(kTestAppId, app_url);
CreateComponentContextAndStartComponent();
fuchsia::web::NavigationControllerPtr nav_controller;
cast_component_->frame()->GetNavigationController(
nav_controller.NewRequest());
CheckAppUrl(app_url);
base::RunLoop run_loop;
cr_fuchsia::ResultReceiver<fuchsia::web::NavigationState> nav_entry(
run_loop.QuitClosure());
nav_controller->GetVisibleEntry(
cr_fuchsia::CallbackToFitFunction(nav_entry.GetReceiveCallback()));
run_loop.Run();
// Setup a loop to wait for Context destruction after WebEngine is killed
// below.
base::RunLoop context_lost_loop;
cast_runner_->SetOnContextLostCallback(context_lost_loop.QuitClosure());
ASSERT_TRUE(nav_entry->has_url());
EXPECT_EQ(nav_entry->url(), app_url.spec());
web_engine_controller_->Kill();
// Fake teardown of the Context, forcing the next StartComponent to create
// a new one.
cast_runner_->DisconnectContextForTest();
// Wait for the component and the Context to be torn down.
WaitForComponentDestroyed();
context_lost_loop.Run();
// Start a new WebEngine instance for the next iteration.
if (i < 1)
StartAndPublishWebEngine();
}
}
TEST_F(CastRunnerIntegrationTest, ApiBindings) {
app_config_manager_.AddApp(kTestAppId, test_server_.GetURL(kEchoAppPath));
std::vector<chromium::cast::ApiBinding> binding_list;
chromium::cast::ApiBinding echo_binding;
echo_binding.set_before_load_script(cr_fuchsia::MemBufferFromString(
"window.echo = cast.__platform__.PortConnector.bind('echoService');",
"test"));
binding_list.emplace_back(std::move(echo_binding));
api_bindings_.set_bindings(std::move(binding_list));
app_config_manager_.AddApp(kTestAppId, test_server_.GetURL(kBlankAppUrl));
CreateComponentContextAndStartComponent();
fuchsia::web::MessagePortPtr port =
api_bindings_.RunUntilMessagePortReceived("echoService").Bind();
fuchsia::web::WebMessage message;
message.set_data(cr_fuchsia::MemBufferFromString("ping", "ping-msg"));
port->PostMessage(std::move(message),
[](fuchsia::web::MessagePort_PostMessage_Result result) {
EXPECT_TRUE(result.is_response());
});
base::RunLoop response_loop;
cr_fuchsia::ResultReceiver<fuchsia::web::WebMessage> response(
response_loop.QuitClosure());
port->ReceiveMessage(
cr_fuchsia::CallbackToFitFunction(response.GetReceiveCallback()));
response_loop.Run();
std::string response_string;
EXPECT_TRUE(
cr_fuchsia::StringFromMemBuffer(response->data(), &response_string));
EXPECT_EQ("ack ping", response_string);
EXPECT_TRUE(component_state_->api_bindings_has_clients());
// Verify that we can communicate with the binding added in
// CastRunnerIntegrationTest().
EXPECT_EQ(ExecuteJavaScript("1+2+\"\""), "3");
}
TEST_F(CastRunnerIntegrationTest, IncorrectCastAppId) {
@ -538,12 +558,9 @@ TEST_F(CastRunnerIntegrationTest, IncorrectCastAppId) {
EXPECT_EQ(status, ZX_ERR_PEER_CLOSED);
run_loop.Quit();
});
cr_fuchsia::ResultReceiver<WebComponent*> web_component(
run_loop.QuitClosure());
cast_runner_->SetWebComponentCreatedCallbackForTest(
AdaptCallbackForRepeating(web_component.GetReceiveCallback()));
run_loop.Run();
EXPECT_FALSE(web_component.has_value());
EXPECT_FALSE(component_state_->api_bindings_has_clients());
}
TEST_F(CastRunnerIntegrationTest, UrlRequestRewriteRulesProvider) {
@ -552,20 +569,9 @@ TEST_F(CastRunnerIntegrationTest, UrlRequestRewriteRulesProvider) {
CreateComponentContextAndStartComponent();
// Bind a TestNavigationListener to the Frame.
cr_fuchsia::TestNavigationListener navigation_listener;
fidl::Binding<fuchsia::web::NavigationEventListener>
navigation_listener_binding(&navigation_listener);
cast_component_->frame()->SetNavigationEventListener(
navigation_listener_binding.NewBinding());
navigation_listener.RunUntilUrlEquals(echo_app_url);
CheckAppUrl(echo_app_url);
// Check the header was properly set.
base::Optional<base::Value> result = cr_fuchsia::ExecuteJavaScript(
cast_component_->frame(), "document.body.innerText");
ASSERT_TRUE(result);
ASSERT_TRUE(result->is_string());
EXPECT_EQ(result->GetString(), "Value");
EXPECT_EQ(ExecuteJavaScript("document.body.innerText"), "TestHeaderValue");
}
TEST_F(CastRunnerIntegrationTest, ApplicationControllerBound) {
@ -589,25 +595,9 @@ TEST_F(CastRunnerIntegrationTest, RemoteDebugging) {
CreateComponentContextAndStartComponent();
// Get the remote debugging port from the Context.
uint16_t remote_debugging_port = 0;
{
base::RunLoop run_loop;
cr_fuchsia::ResultReceiver<
fuchsia::web::Context_GetRemoteDebuggingPort_Result>
port_receiver(run_loop.QuitClosure());
cast_runner_->GetContext()->GetRemoteDebuggingPort(
cr_fuchsia::CallbackToFitFunction(port_receiver.GetReceiveCallback()));
run_loop.Run();
ASSERT_TRUE(port_receiver->is_response());
remote_debugging_port = port_receiver->response().port;
ASSERT_TRUE(remote_debugging_port != 0);
}
// Connect to the debug service and ensure we get the proper response.
base::Value devtools_list =
cr_fuchsia::GetDevToolsListFromPort(remote_debugging_port);
cr_fuchsia::GetDevToolsListFromPort(CastRunner::kRemoteDebuggingPort);
ASSERT_TRUE(devtools_list.is_list());
EXPECT_EQ(devtools_list.GetList().size(), 1u);
@ -617,23 +607,11 @@ TEST_F(CastRunnerIntegrationTest, RemoteDebugging) {
}
TEST_F(CastRunnerIntegrationTest, IsolatedContext) {
const GURL kContentDirectoryUrl("fuchsia-dir://testdata/echo.html");
EXPECT_EQ(cast_runner_->GetChildCastRunnerCountForTest(), 0u);
const GURL kContentDirectoryUrl("fuchsia-dir://testdata/empty.html");
RegisterAppWithTestData(kContentDirectoryUrl);
CreateComponentContextAndStartComponent();
EXPECT_EQ(cast_runner_->GetChildCastRunnerCountForTest(), 1u);
WaitUrlAndTitle(kContentDirectoryUrl, "echo");
// Verify that the component is torn down when |component_controller| is
// unbound.
component_controller_.Unbind();
WaitForComponentDestroyed();
EXPECT_EQ(cast_runner_->GetChildCastRunnerCountForTest(), 0u);
CheckAppUrl(kContentDirectoryUrl);
}
// Test the lack of CastAgent service does not cause a CastRunner crash.
@ -655,9 +633,6 @@ TEST_F(CastRunnerIntegrationTest, DisconnectedCastAgent) {
app_config_manager_.AddApp(kTestAppId, test_server_.GetURL(kEchoHeaderPath));
CreateComponentContextAndStartComponent();
fuchsia::web::NavigationControllerPtr nav_controller;
cast_component_->frame()->GetNavigationController(
nav_controller.NewRequest());
base::RunLoop run_loop;
component_controller_.set_error_handler([&run_loop](zx_status_t error) {
@ -684,7 +659,7 @@ TEST_F(CastRunnerIntegrationTest, ApplicationConfigAgentUrl) {
// Indicate that this app is to get bindings from a secondary agent.
auto app_config = FakeApplicationConfigManager::CreateConfig(
kTestAppId, test_server_.GetURL(kEchoAppPath));
kTestAppId, test_server_.GetURL(kBlankAppUrl));
app_config.set_agent_url(kDummyAgentUrl);
app_config_manager_.AddAppConfig(std::move(app_config));
@ -713,6 +688,7 @@ TEST_F(CastRunnerIntegrationTest, ApplicationConfigAgentUrl) {
}));
StartCastComponent(component_url);
WaitComponentState();
base::RunLoop().RunUntilIdle();
@ -720,6 +696,9 @@ TEST_F(CastRunnerIntegrationTest, ApplicationConfigAgentUrl) {
EXPECT_FALSE(component_state_->api_bindings_has_clients());
// Validate that the correct rewrite rules were requested.
EXPECT_FALSE(component_state_->url_request_rules_provider_has_clients());
// Shutdown component before destroying dummy_agent_api_bindings.
ShutdownComponent();
}
// Test that when RewriteRules are not provided, a WebComponent is still
@ -727,10 +706,9 @@ TEST_F(CastRunnerIntegrationTest, ApplicationConfigAgentUrl) {
// or RewriteRules.
TEST_F(CastRunnerIntegrationTest, ApplicationConfigAgentUrlRewriteOptional) {
TestApiBindings dummy_agent_api_bindings;
// Indicate that this app is to get bindings from a secondary agent.
auto app_config = FakeApplicationConfigManager::CreateConfig(
kTestAppId, test_server_.GetURL(kEchoAppPath));
kTestAppId, test_server_.GetURL(kBlankAppUrl));
app_config.set_agent_url(kDummyAgentUrl);
app_config_manager_.AddAppConfig(std::move(app_config));
@ -759,7 +737,7 @@ TEST_F(CastRunnerIntegrationTest, ApplicationConfigAgentUrlRewriteOptional) {
}));
StartCastComponent(component_url);
WaitComponentCreated();
WaitComponentState();
base::RunLoop().RunUntilIdle();
@ -767,10 +745,13 @@ TEST_F(CastRunnerIntegrationTest, ApplicationConfigAgentUrlRewriteOptional) {
EXPECT_FALSE(component_state_->api_bindings_has_clients());
// Validate that the primary agent didn't provide its RewriteRules.
EXPECT_FALSE(component_state_->url_request_rules_provider_has_clients());
// Shutdown component before destroying dummy_agent_api_bindings.
ShutdownComponent();
}
TEST_F(CastRunnerIntegrationTest, MicRedirect) {
GURL app_url = test_server_.GetURL("/mic.html");
TEST_F(CastRunnerIntegrationTest, MicrophoneRedirect) {
GURL app_url = test_server_.GetURL("/microphone.html");
auto app_config =
FakeApplicationConfigManager::CreateConfig(kTestAppId, app_url);
@ -779,82 +760,57 @@ TEST_F(CastRunnerIntegrationTest, MicRedirect) {
app_config.mutable_permissions()->push_back(std::move(mic_permission));
app_config_manager_.AddAppConfig(std::move(app_config));
base::RunLoop run_loop;
init_component_state_callback_ = base::BindOnce(
[](base::OnceClosure quit_closure, FakeComponentState* component_state) {
component_state->outgoing_directory()->AddPublicService(
std::make_unique<vfs::Service>(
[quit_closure = std::move(quit_closure)](
zx::channel channel,
async_dispatcher_t* dispatcher) mutable {
std::move(quit_closure).Run();
}),
fuchsia::media::Audio::Name_);
},
base::Passed(run_loop.QuitClosure()));
CreateComponentContextAndStartComponent();
// Expect fuchsia.media.Audio connection to be redirected to the agent.
base::RunLoop run_loop;
component_state_->outgoing_directory()->AddPublicService(
std::make_unique<vfs::Service>(
[quit_closure = run_loop.QuitClosure()](
zx::channel channel, async_dispatcher_t* dispatcher) mutable {
std::move(quit_closure).Run();
}),
fuchsia::media::Audio::Name_);
ExecuteJavaScript("connectMicrophone();");
// Will quit once AudioCapturer is connected.
run_loop.Run();
}
class HeadlessCastRunnerIntegrationTest : public CastRunnerIntegrationTest {
public:
HeadlessCastRunnerIntegrationTest()
: CastRunnerIntegrationTest(fuchsia::web::ContextFeatureFlags::HEADLESS |
fuchsia::web::ContextFeatureFlags::NETWORK) {}
: CastRunnerIntegrationTest(/*headless=*/true) {}
};
// A basic integration test ensuring a basic cast request launches the right
// URL in the Chromium service.
TEST_F(HeadlessCastRunnerIntegrationTest, Headless) {
ASSERT_TRUE(cast_runner_->is_headless());
const char kAnimationPath[] = "/css_animation.html";
const GURL animation_url = test_server_.GetURL(kAnimationPath);
app_config_manager_.AddApp(kTestAppId, animation_url);
CreateComponentContextAndStartComponent();
auto tokens = scenic::ViewTokenPair::New();
cast_component_->CreateView(std::move(tokens.view_holder_token.value), {},
{});
WaitUrlAndTitle(animation_url, "animation finished");
// Create a view.
auto view_provider =
component_services_client_->Connect<fuchsia::ui::app::ViewProvider>();
view_provider->CreateView(std::move(tokens.view_holder_token.value), {}, {});
// Verify that dropping the "view" EventPair is handled by the CastComponent.
{
base::RunLoop run_loop;
cast_component_->set_on_headless_disconnect_for_test(
run_loop.QuitClosure());
tokens.view_token.value.reset();
run_loop.Run();
}
api_bindings_.RunUntilMessagePortReceived("animation_finished");
component_controller_.Unbind();
base::RunLoop().RunUntilIdle();
// Verify that dropped "view" EventPair is handled properly.
tokens.view_token.value.reset();
api_bindings_.RunUntilMessagePortReceived("view_hidden");
}
// Isolated *and* headless? Doesn't sound like much fun!
TEST_F(HeadlessCastRunnerIntegrationTest, IsolatedAndHeadless) {
ASSERT_TRUE(cast_runner_->is_headless());
const GURL kContentDirectoryUrl("fuchsia-dir://testdata/echo.html");
EXPECT_EQ(cast_runner_->GetChildCastRunnerCountForTest(), 0u);
const GURL kContentDirectoryUrl("fuchsia-dir://testdata/empty.html");
RegisterAppWithTestData(kContentDirectoryUrl);
CreateComponentContextAndStartComponent();
EXPECT_TRUE(cast_component_->runner()->is_headless());
EXPECT_EQ(cast_runner_->GetChildCastRunnerCountForTest(), 1u);
WaitUrlAndTitle(kContentDirectoryUrl, "echo");
// Verify that the component is torn down when |component_controller| is
// unbound.
component_controller_.Unbind();
WaitForComponentDestroyed();
EXPECT_EQ(cast_runner_->GetChildCastRunnerCountForTest(), 0u);
CheckAppUrl(kContentDirectoryUrl);
}

@ -63,8 +63,8 @@ fuchsia::web::CreateContextParams CreateMainContextParams() {
create_context_params.set_user_agent_product("CrKey");
create_context_params.set_user_agent_version("1.43");
const uint16_t kRemoteDebuggingPort = 9222;
create_context_params.set_remote_debugging_port(kRemoteDebuggingPort);
create_context_params.set_remote_debugging_port(
CastRunner::kRemoteDebuggingPort);
// TODO(crbug.com/1023514): Remove this switch when it is no longer
// necessary.
@ -90,8 +90,8 @@ int main(int argc, char** argv) {
WebContentRunner::GetContextParamsCallback get_context_params_callback =
base::BindRepeating(&CreateMainContextParams);
CastRunner runner(
std::move(get_context_params_callback), IsHeadless(),
CastRunner runner(std::move(get_context_params_callback), IsHeadless());
runner.PublishRunnerService(
base::fuchsia::ComponentContextForCurrentProcess()->outgoing().get());
base::fuchsia::ComponentContextForCurrentProcess()

@ -4,6 +4,7 @@
#include "fuchsia/runners/cast/test_api_bindings.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/run_loop.h"
TestApiBindings::TestApiBindings() = default;
@ -25,7 +26,14 @@ TestApiBindings::RunUntilMessagePortReceived(base::StringPiece port_name) {
}
void TestApiBindings::GetAll(GetAllCallback callback) {
callback(std::move(bindings_));
std::vector<chromium::cast::ApiBinding> bindings_clone;
for (auto& binding : bindings_) {
chromium::cast::ApiBinding binding_clone;
zx_status_t status = binding.Clone(&binding_clone);
ZX_CHECK(status == ZX_OK, status);
bindings_clone.push_back(std::move(binding_clone));
}
callback(std::move(bindings_clone));
}
void TestApiBindings::Connect(

@ -31,14 +31,14 @@
isStarted = true;
});
animated.addEventListener('animationend', function() {
document.title = 'animation finished';
});
cast.__platform__.PortConnector.bind('animation_finished');
// Indicates that no animation has run within a second of document load.
setTimeout(function() {
if (!isStarted)
document.title = 'animation never started';
}, 1000);
document.addEventListener("visibilitychange", ()=>{
if (document.hidden) {
cast.__platform__.PortConnector.bind('view_hidden');
}
}, false);
});
</script>
</body>
</html>

@ -0,0 +1 @@
<html></html>

@ -1,4 +1,6 @@
<script>
function connectMicrophone() {
navigator.mediaDevices.getUserMedia({ audio: true, video: false })
.then((stream) => { document.title = 'done'; });
}
</script>

@ -22,35 +22,44 @@
#include "fuchsia/runners/common/web_component.h"
#include "url/gurl.h"
WebContentRunner::WebContentRunner(
GetContextParamsCallback get_context_params_callback,
sys::OutgoingDirectory* outgoing_directory)
: get_context_params_callback_(std::move(get_context_params_callback)) {
service_binding_.emplace(outgoing_directory, this);
}
namespace {
WebContentRunner::WebContentRunner(fuchsia::web::ContextPtr context)
: context_(std::move(context)) {}
WebContentRunner::~WebContentRunner() = default;
fuchsia::web::ContextPtr WebContentRunner::CreateWebContext(
fuchsia::web::ContextPtr CreateWebContext(
fuchsia::web::CreateContextParams context_params) {
auto context_provider = base::fuchsia::ComponentContextForCurrentProcess()
->svc()
->Connect<fuchsia::web::ContextProvider>();
fuchsia::web::ContextPtr web_context;
GetContextProvider()->Create(std::move(context_params),
web_context.NewRequest());
web_context.set_error_handler([](zx_status_t status) {
// If the browser instance died, then exit everything and do not attempt to
// recover. appmgr will relaunch the runner when it is needed again.
ZX_LOG(ERROR, status) << "Connection to Context lost.";
});
context_provider->Create(std::move(context_params), web_context.NewRequest());
return web_context;
}
} // namespace
WebContentRunner::WebContentRunner(
GetContextParamsCallback get_context_params_callback)
: get_context_params_callback_(std::move(get_context_params_callback)) {}
WebContentRunner::~WebContentRunner() = default;
void WebContentRunner::PublishRunnerService(
sys::OutgoingDirectory* outgoing_directory) {
service_binding_.emplace(outgoing_directory, this);
}
fuchsia::web::Context* WebContentRunner::GetContext() {
if (!context_)
if (!context_) {
context_ = CreateWebContext(get_context_params_callback_.Run());
context_.set_error_handler([this](zx_status_t status) {
// If the browser instance died, then exit everything and do not attempt
// to recover. appmgr will relaunch the runner when it is needed again.
ZX_LOG(ERROR, status) << "Connection to Context lost.";
if (on_context_lost_callback_) {
std::move(on_context_lost_callback_).Run();
}
});
}
return context_.get();
}
@ -77,39 +86,15 @@ void WebContentRunner::StartComponent(
RegisterComponent(std::move(component));
}
void WebContentRunner::SetWebComponentCreatedCallbackForTest(
base::RepeatingCallback<void(WebComponent*)> callback) {
DCHECK(components_.empty());
web_component_created_callback_for_test_ = std::move(callback);
}
void WebContentRunner::DestroyComponent(WebComponent* component) {
components_.erase(components_.find(component));
}
void WebContentRunner::RegisterComponent(
std::unique_ptr<WebComponent> component) {
if (web_component_created_callback_for_test_)
web_component_created_callback_for_test_.Run(component.get());
components_.insert(std::move(component));
}
void WebContentRunner::SetContextProviderForTest(
fuchsia::web::ContextProviderPtr context_provider) {
DCHECK(context_provider);
context_provider_ = std::move(context_provider);
}
void WebContentRunner::DisconnectContextForTest() {
context_.Unbind();
}
fuchsia::web::ContextProvider* WebContentRunner::GetContextProvider() {
if (!context_provider_) {
context_provider_ = base::fuchsia::ComponentContextForCurrentProcess()
->svc()
->Connect<fuchsia::web::ContextProvider>();
}
return context_provider_.get();
void WebContentRunner::SetOnContextLostCallback(base::OnceClosure callback) {
on_context_lost_callback_ = std::move(callback);
}

@ -29,22 +29,13 @@ class WebContentRunner : public fuchsia::sys::Runner {
// specified OutgoingDirectory.
// |get_context_params_callback|: Returns parameters for the Runner's
// web.Context.
// |outgoing_directory|: The directory that the Runner's services will be
// published to.
WebContentRunner(GetContextParamsCallback get_context_params_callback,
sys::OutgoingDirectory* outgoing_directory);
// Creates a Runner which launches components using the specified |context|.
// The caller may publish the Runner, or call StartComponent() manually to
// create new components with it.
explicit WebContentRunner(fuchsia::web::ContextPtr context);
explicit WebContentRunner(
GetContextParamsCallback get_context_params_callback);
~WebContentRunner() override;
// TODO(crbug.com/1046615): Make this static when the injected ContextProvider
// goes away.
fuchsia::web::ContextPtr CreateWebContext(
fuchsia::web::CreateContextParams context_params);
// Publishes the fuchsia.sys.Runner service to |outgoing_directory|.
void PublishRunnerService(sys::OutgoingDirectory* outgoing_directory);
// Gets a pointer to this runner's Context, creating one if needed.
fuchsia::web::Context* GetContext();
@ -59,37 +50,19 @@ class WebContentRunner : public fuchsia::sys::Runner {
fidl::InterfaceRequest<fuchsia::sys::ComponentController>
controller_request) override;
// Used by tests to asynchronously access the first WebComponent.
void SetWebComponentCreatedCallbackForTest(
base::RepeatingCallback<void(WebComponent*)> callback);
// Registers a WebComponent, or specialization, with this Runner.
void RegisterComponent(std::unique_ptr<WebComponent> component);
// Overrides the environment's the ContextProvider to use.
// TODO(crbug.com/1046615): Use test manifests for package specification.
void SetContextProviderForTest(
fuchsia::web::ContextProviderPtr context_provider);
// Disconnects the Context used by this Runner.
void DisconnectContextForTest();
protected:
base::RepeatingCallback<void(WebComponent*)>
web_component_created_callback_for_test() const {
return web_component_created_callback_for_test_;
}
// Sets a callback that's called when the context is lost.
void SetOnContextLostCallback(base::OnceClosure callback);
private:
fuchsia::web::ContextProvider* GetContextProvider();
const GetContextParamsCallback get_context_params_callback_;
// If set, invoked whenever a WebComponent is created.
base::RepeatingCallback<void(WebComponent*)>
web_component_created_callback_for_test_;
fuchsia::web::ContextProviderPtr context_provider_;
fuchsia::web::ContextPtr context_;
std::set<std::unique_ptr<WebComponent>, base::UniquePtrComparator>
components_;
@ -99,6 +72,8 @@ class WebContentRunner : public fuchsia::sys::Runner {
base::Optional<base::fuchsia::ScopedServiceBinding<fuchsia::sys::Runner>>
service_binding_;
base::OnceClosure on_context_lost_callback_;
DISALLOW_COPY_AND_ASSIGN(WebContentRunner);
};

@ -57,8 +57,8 @@ int main(int argc, char** argv) {
WebContentRunner::GetContextParamsCallback get_context_params_callback =
base::BindRepeating(&GetContextParams);
WebContentRunner runner(
std::move(get_context_params_callback),
WebContentRunner runner(std::move(get_context_params_callback));
runner.PublishRunnerService(
base::fuchsia::ComponentContextForCurrentProcess()->outgoing().get());
base::fuchsia::ComponentContextForCurrentProcess()