12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280 |
- // Copyright 2018 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 <fuchsia/camera3/cpp/fidl.h>
- #include <fuchsia/legacymetrics/cpp/fidl.h>
- #include <fuchsia/legacymetrics/cpp/fidl_test_base.h>
- #include <fuchsia/media/cpp/fidl.h>
- #include <fuchsia/modular/cpp/fidl.h>
- #include <fuchsia/web/cpp/fidl.h>
- #include <lib/fdio/directory.h>
- #include <lib/fidl/cpp/binding.h>
- #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 <utility>
- #include <vector>
- #include "base/auto_reset.h"
- #include "base/barrier_closure.h"
- #include "base/base_paths.h"
- #include "base/callback_helpers.h"
- #include "base/files/file_util.h"
- #include "base/fuchsia/file_utils.h"
- #include "base/fuchsia/filtered_service_directory.h"
- #include "base/fuchsia/fuchsia_logging.h"
- #include "base/fuchsia/mem_buffer_util.h"
- #include "base/fuchsia/scoped_service_binding.h"
- #include "base/fuchsia/test_component_controller.h"
- #include "base/path_service.h"
- #include "base/run_loop.h"
- #include "base/strings/strcat.h"
- #include "base/strings/string_piece.h"
- #include "base/test/bind.h"
- #include "base/test/scoped_run_loop_timeout.h"
- #include "base/test/task_environment.h"
- #include "base/test/test_future.h"
- #include "base/test/test_timeouts.h"
- #include "base/threading/sequenced_task_runner_handle.h"
- #include "build/build_config.h"
- #include "fuchsia_web/common/string_util.h"
- #include "fuchsia_web/common/test/fit_adapter.h"
- #include "fuchsia_web/common/test/frame_test_util.h"
- #include "fuchsia_web/common/test/test_devtools_list_fetcher.h"
- #include "fuchsia_web/common/test/url_request_rewrite_test_util.h"
- #include "fuchsia_web/runners/cast/cast_runner.h"
- #include "fuchsia_web/runners/cast/cast_runner_integration_test_base.h"
- #include "fuchsia_web/runners/cast/cast_runner_switches.h"
- #include "fuchsia_web/runners/cast/fake_api_bindings.h"
- #include "fuchsia_web/runners/cast/fake_application_config_manager.h"
- #include "fuchsia_web/runners/cast/fidl/fidl/chromium/cast/cpp/fidl.h"
- #include "fuchsia_web/runners/common/modular/agent_impl.h"
- #include "fuchsia_web/runners/common/modular/fake_component_context.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace {
- constexpr char kTestAppId[] = "00000000";
- constexpr char kSecondTestAppId[] = "FFFFFFFF";
- constexpr char kBlankAppUrl[] = "/defaultresponse";
- constexpr char kEchoHeaderPath[] = "/echoheader?Test";
- constexpr char kDummyAgentUrl[] =
- "fuchsia-pkg://fuchsia.com/dummy_agent#meta/dummy_agent.cmx";
- class FakeCorsExemptHeaderProvider final
- : public chromium::cast::CorsExemptHeaderProvider {
- public:
- FakeCorsExemptHeaderProvider() = default;
- ~FakeCorsExemptHeaderProvider() override = default;
- FakeCorsExemptHeaderProvider(const FakeCorsExemptHeaderProvider&) = delete;
- FakeCorsExemptHeaderProvider& operator=(const FakeCorsExemptHeaderProvider&) =
- delete;
- private:
- void GetCorsExemptHeaderNames(
- GetCorsExemptHeaderNamesCallback callback) override {
- callback({StringToBytes("Test")});
- }
- };
- class FakeUrlRequestRewriteRulesProvider final
- : public chromium::cast::UrlRequestRewriteRulesProvider {
- public:
- FakeUrlRequestRewriteRulesProvider() = default;
- ~FakeUrlRequestRewriteRulesProvider() override = default;
- FakeUrlRequestRewriteRulesProvider(
- const FakeUrlRequestRewriteRulesProvider&) = delete;
- FakeUrlRequestRewriteRulesProvider& operator=(
- const FakeUrlRequestRewriteRulesProvider&) = delete;
- private:
- void GetUrlRequestRewriteRules(
- GetUrlRequestRewriteRulesCallback callback) override {
- // Only send the rules once. They do not expire
- if (rules_sent_)
- return;
- rules_sent_ = true;
- std::vector<fuchsia::web::UrlRequestRewrite> rewrites;
- rewrites.push_back(CreateRewriteAddHeaders("Test", "TestHeaderValue"));
- fuchsia::web::UrlRequestRewriteRule rule;
- rule.set_rewrites(std::move(rewrites));
- std::vector<fuchsia::web::UrlRequestRewriteRule> rules;
- rules.push_back(std::move(rule));
- callback(std::move(rules));
- }
- bool rules_sent_ = false;
- };
- class FakeApplicationContext final : public chromium::cast::ApplicationContext {
- public:
- FakeApplicationContext() = default;
- ~FakeApplicationContext() override = default;
- FakeApplicationContext(const FakeApplicationContext&) = delete;
- FakeApplicationContext& operator=(const FakeApplicationContext&) = delete;
- chromium::cast::ApplicationController* controller() {
- if (!controller_)
- return nullptr;
- return controller_.get();
- }
- absl::optional<int64_t> WaitForApplicationTerminated() {
- base::RunLoop loop;
- on_application_terminated_ = loop.QuitClosure();
- loop.Run();
- return application_exit_code_;
- }
- private:
- // chromium::cast::ApplicationContext implementation.
- void GetMediaSessionId(GetMediaSessionIdCallback callback) override {
- callback(1);
- }
- void SetApplicationController(
- fidl::InterfaceHandle<chromium::cast::ApplicationController> controller)
- override {
- controller_ = controller.Bind();
- }
- void OnApplicationExit(int64_t exit_code) override {
- application_exit_code_ = exit_code;
- if (on_application_terminated_)
- std::move(on_application_terminated_).Run();
- }
- chromium::cast::ApplicationControllerPtr controller_;
- absl::optional<int64_t> application_exit_code_;
- base::OnceClosure on_application_terminated_;
- };
- class FakeComponentState : public cr_fuchsia::AgentImpl::ComponentStateBase {
- public:
- FakeComponentState(
- base::StringPiece component_url,
- chromium::cast::ApplicationConfigManager* app_config_manager,
- chromium::cast::ApiBindings* bindings_manager,
- chromium::cast::UrlRequestRewriteRulesProvider*
- url_request_rules_provider)
- : ComponentStateBase(component_url),
- app_config_binding_(outgoing_directory(), app_config_manager),
- bindings_manager_binding_(outgoing_directory(), bindings_manager),
- context_binding_(outgoing_directory(), &application_context_) {
- if (url_request_rules_provider) {
- url_request_rules_provider_binding_.emplace(outgoing_directory(),
- url_request_rules_provider);
- }
- }
- ~FakeComponentState() override {
- if (on_delete_)
- std::move(on_delete_).Run();
- }
- FakeComponentState(const FakeComponentState&) = delete;
- FakeComponentState& operator=(const FakeComponentState&) = delete;
- // Make outgoing_directory() public.
- using ComponentStateBase::outgoing_directory;
- FakeApplicationContext* application_context() {
- return &application_context_;
- }
- void set_on_delete(base::OnceClosure on_delete) {
- on_delete_ = std::move(on_delete);
- }
- void Disconnect() { DisconnectClientsAndTeardown(); }
- bool api_bindings_has_clients() {
- return bindings_manager_binding_.has_clients();
- }
- bool url_request_rules_provider_has_clients() {
- if (url_request_rules_provider_binding_) {
- return url_request_rules_provider_binding_->has_clients();
- }
- return false;
- }
- protected:
- const base::ScopedServiceBinding<chromium::cast::ApplicationConfigManager>
- app_config_binding_;
- const base::ScopedServiceBinding<chromium::cast::ApiBindings>
- bindings_manager_binding_;
- absl::optional<base::ScopedServiceBinding<
- chromium::cast::UrlRequestRewriteRulesProvider>>
- url_request_rules_provider_binding_;
- FakeApplicationContext application_context_;
- const base::ScopedServiceBinding<chromium::cast::ApplicationContext>
- context_binding_;
- base::OnceClosure on_delete_;
- };
- class TestCastComponent {
- public:
- explicit TestCastComponent(fuchsia::sys::RunnerPtr& cast_runner)
- : app_config_manager_binding_(&component_services_, &app_config_manager_),
- cast_runner_(cast_runner.get()) {
- EXPECT_TRUE(cast_runner_);
- }
- ~TestCastComponent() {
- if (component_controller_)
- ShutdownComponent();
- }
- TestCastComponent(const TestCastComponent&) = delete;
- TestCastComponent& operator=(const FakeComponentState&) = delete;
- void CreateComponentContextAndStartComponent(
- base::StringPiece app_id = kTestAppId) {
- ASSERT_FALSE(component_context_)
- << "ComponentContext may only be created once";
- auto component_url = base::StrCat({"cast:", app_id});
- InjectQueryApi();
- CreateComponentContext(component_url);
- StartCastComponent(component_url);
- WaitComponentStateCreated();
- WaitQueryApiConnected();
- }
- void CreateComponentContext(const base::StringPiece& component_url,
- bool with_fake_agent = true) {
- ASSERT_FALSE(component_context_)
- << "ComponentContext may only be created once";
- url_request_rewrite_rules_provider_ =
- std::make_unique<FakeUrlRequestRewriteRulesProvider>();
- component_context_ = std::make_unique<cr_fuchsia::FakeComponentContext>(
- &component_services_, component_url);
- if (with_fake_agent) {
- component_context_->RegisterCreateComponentStateCallback(
- FakeApplicationConfigManager::kFakeAgentUrl,
- base::BindRepeating(&TestCastComponent::OnComponentConnect,
- base::Unretained(this)));
- }
- }
- void StartCastComponent(base::StringPiece component_url) {
- ASSERT_FALSE(component_services_client_)
- << "Component may only be started once";
- // Configure the Runner, including a service directory channel to publish
- // services to.
- fuchsia::sys::StartupInfo startup_info;
- startup_info.launch_info.url = std::string(component_url);
- fidl::InterfaceHandle<fuchsia::io::Directory> outgoing_directory;
- startup_info.launch_info.directory_request =
- outgoing_directory.NewRequest().TakeChannel();
- fidl::InterfaceHandle<fuchsia::io::Directory> svc_directory;
- EXPECT_EQ(fdio_service_connect_at(
- outgoing_directory.channel().get(), "svc",
- svc_directory.NewRequest().TakeChannel().release()),
- ZX_OK);
- component_services_client_ =
- std::make_unique<sys::ServiceDirectory>(std::move(svc_directory));
- // Populate |component_services_| with services for the component to use.
- fidl::InterfaceHandle<fuchsia::io::Directory> directory;
- component_services_.GetOrCreateDirectory("svc")->Serve(
- fuchsia::io::OpenFlags::RIGHT_READABLE |
- fuchsia::io::OpenFlags::RIGHT_WRITABLE,
- directory.NewRequest().TakeChannel());
- ASSERT_EQ(component_services_.AddPublicService(
- cors_exempt_header_provider_binding_.GetHandler(
- &cors_exempt_header_provider_)),
- ZX_OK);
- // Provide the directory of services in the |flat_namespace|.
- startup_info.flat_namespace.paths.emplace_back(base::kServiceDirectoryPath);
- startup_info.flat_namespace.directories.emplace_back(
- directory.TakeChannel());
- fuchsia::sys::Package package;
- package.resolved_url = std::string(component_url);
- cast_runner_->StartComponent(std::move(package), std::move(startup_info),
- component_controller_.ptr().NewRequest());
- component_controller_.ptr().set_error_handler([](zx_status_t status) {
- ZX_LOG(ERROR, status) << "Component launch failed";
- ADD_FAILURE();
- });
- }
- void RegisterAppWithTestData(GURL url) {
- fuchsia::web::ContentDirectoryProvider provider;
- provider.set_name("testdata");
- base::FilePath pkg_path;
- ASSERT_TRUE(
- base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &pkg_path));
- provider.set_directory(base::OpenDirectoryHandle(
- pkg_path.AppendASCII("fuchsia_web/runners/cast/testdata")));
- std::vector<fuchsia::web::ContentDirectoryProvider> providers;
- providers.emplace_back(std::move(provider));
- auto app_config =
- FakeApplicationConfigManager::CreateConfig(kTestAppId, url);
- app_config.set_content_directories_for_isolated_application(
- std::move(providers));
- app_config_manager_.AddAppConfig(std::move(app_config));
- }
- // Executes |code| in the context of the test application and then returns
- // the result serialized as string. If the code evaluates to a promise then
- // execution is blocked until the promise is complete and the result of the
- // promise is returned.
- std::string ExecuteJavaScript(const std::string& code) {
- fuchsia::web::WebMessage message;
- message.set_data(base::MemBufferFromString(code, "test-msg"));
- test_port_->PostMessage(
- std::move(message),
- [](fuchsia::web::MessagePort_PostMessage_Result result) {
- EXPECT_TRUE(result.is_response());
- });
- base::test::TestFuture<fuchsia::web::WebMessage> response;
- test_port_->ReceiveMessage(CallbackToFitFunction(response.GetCallback()));
- EXPECT_TRUE(response.Wait());
- absl::optional<std::string> response_string =
- base::StringFromMemBuffer(response.Get().data());
- EXPECT_TRUE(response_string.has_value());
- return response_string.value_or(std::string());
- }
- void CheckAppUrl(const GURL& app_url) {
- EXPECT_EQ(ExecuteJavaScript("window.location.href"), app_url.spec());
- }
- void ShutdownComponent() {
- EXPECT_TRUE(component_controller_);
- if (component_state_) {
- base::RunLoop run_loop;
- component_state_->set_on_delete(run_loop.QuitClosure());
- component_controller_.ptr().Unbind();
- run_loop.Run();
- }
- }
- void ExpectControllerDisconnectWithStatus(zx_status_t expected_status) {
- EXPECT_TRUE(component_controller_);
- base::RunLoop loop;
- component_controller_.ptr().set_error_handler(
- [&loop, expected_status](zx_status_t status) {
- loop.Quit();
- EXPECT_EQ(expected_status, status);
- });
- loop.Run();
- }
- void WaitForComponentDestroyed() {
- ASSERT_TRUE(component_state_);
- base::RunLoop state_loop;
- component_state_->set_on_delete(state_loop.QuitClosure());
- if (component_controller_)
- ExpectControllerDisconnectWithStatus(ZX_ERR_PEER_CLOSED);
- state_loop.Run();
- ResetComponentState();
- }
- void ResetComponentState() {
- component_context_ = nullptr;
- component_services_client_ = nullptr;
- component_state_ = nullptr;
- test_port_ = nullptr;
- }
- void OnComponentStateCreated(base::OnceClosure callback) {
- ASSERT_FALSE(component_state_created_callback_);
- component_state_created_callback_ = std::move(callback);
- }
- FakeApplicationConfigManager* app_config_manager() {
- return &app_config_manager_;
- }
- FakeApiBindingsImpl* api_bindings() { return &api_bindings_; }
- cr_fuchsia::FakeComponentContext* component_context() {
- return component_context_.get();
- }
- base::TestComponentController* component_controller() {
- return &component_controller_;
- }
- sys::OutgoingDirectory* component_services() { return &component_services_; }
- sys::ServiceDirectory* component_services_client() {
- return component_services_client_.get();
- }
- FakeComponentState* component_state() { return component_state_; }
- private:
- void InjectQueryApi() {
- // Inject an API which can be used to evaluate arbitrary Javascript and
- // return the results over a MessagePort.
- std::vector<chromium::cast::ApiBinding> binding_list;
- chromium::cast::ApiBinding eval_js_binding;
- eval_js_binding.set_before_load_script(base::MemBufferFromString(
- "function valueOrUndefinedString(value) {"
- " return (typeof(value) == 'undefined') ? 'undefined' : value;"
- "}"
- "window.addEventListener('DOMContentLoaded', (event) => {"
- " var port = cast.__platform__.PortConnector.bind('testport');"
- " port.onmessage = (e) => {"
- " var result = eval(e.data);"
- " if (result && typeof(result.then) == 'function') {"
- " result"
- " .then(result =>"
- " port.postMessage(valueOrUndefinedString(result)))"
- " .catch(e => port.postMessage(JSON.stringify(e)));"
- " } else {"
- " port.postMessage(valueOrUndefinedString(result));"
- " }"
- " };"
- "});",
- "test"));
- binding_list.emplace_back(std::move(eval_js_binding));
- api_bindings_.set_bindings(std::move(binding_list));
- }
- void WaitQueryApiConnected() {
- EXPECT_FALSE(test_port_);
- test_port_ = api_bindings_.RunAndReturnConnectedPort("testport").Bind();
- }
- void WaitComponentStateCreated() {
- base::RunLoop run_loop;
- base::OnceClosure old_component_state_created_callback =
- std::move(component_state_created_callback_);
- component_state_created_callback_ = base::BindLambdaForTesting([&] {
- if (old_component_state_created_callback) {
- std::move(old_component_state_created_callback).Run();
- }
- run_loop.Quit();
- });
- run_loop.Run();
- }
- std::unique_ptr<cr_fuchsia::AgentImpl::ComponentStateBase> OnComponentConnect(
- base::StringPiece component_url) {
- auto component_state = std::make_unique<FakeComponentState>(
- component_url, &app_config_manager_, &api_bindings_,
- url_request_rewrite_rules_provider_.get());
- component_state_ = component_state.get();
- if (component_state_created_callback_)
- std::move(component_state_created_callback_).Run();
- return component_state;
- }
- FakeApplicationConfigManager app_config_manager_;
- FakeApiBindingsImpl api_bindings_;
- std::unique_ptr<FakeUrlRequestRewriteRulesProvider>
- url_request_rewrite_rules_provider_;
- FakeCorsExemptHeaderProvider cors_exempt_header_provider_;
- fidl::BindingSet<chromium::cast::CorsExemptHeaderProvider>
- cors_exempt_header_provider_binding_;
- // Incoming service directory, ComponentContext and per-component state.
- sys::OutgoingDirectory component_services_;
- base::ScopedServiceBinding<chromium::cast::ApplicationConfigManager>
- app_config_manager_binding_;
- std::unique_ptr<cr_fuchsia::FakeComponentContext> component_context_;
- base::TestComponentController component_controller_;
- std::unique_ptr<sys::ServiceDirectory> component_services_client_;
- FakeComponentState* component_state_ = nullptr;
- fuchsia::web::MessagePortPtr test_port_;
- base::OnceClosure component_state_created_callback_;
- fuchsia::sys::Runner* const cast_runner_;
- };
- } // namespace
- // A basic integration test ensuring a basic cast request launches the right
- // URL in the Chromium service.
- TEST_F(CastRunnerIntegrationTest, BasicRequest) {
- TestCastComponent component(cast_runner());
- GURL app_url = test_server().GetURL(kBlankAppUrl);
- component.app_config_manager()->AddApp(kTestAppId, app_url);
- component.CreateComponentContextAndStartComponent();
- component.CheckAppUrl(app_url);
- }
- // Verify that the Runner can continue to be used even after its Context has
- // crashed. Regression test for https://crbug.com/1066826.
- // TODO(crbug.com/1066833): Replace this with a WebRunner test, ideally a
- // unit-test, which can simulate Context disconnection more simply.
- // TODO(crbug.com/1010222): Once CastRunner migrates to creating the WebEngine
- // component directly, it should be possible to rehabilitate and re-enable
- // this test. At present it is not straightforward to terminate the
- // WebEngine component instance, only the ContextProvider, which will not
- // result in the WebEngine instance being torn-down.
- TEST_F(CastRunnerIntegrationTest, DISABLED_CanRecreateContext) {
- TestCastComponent component(cast_runner());
- const GURL app_url = test_server().GetURL(kBlankAppUrl);
- component.app_config_manager()->AddApp(kTestAppId, app_url);
- // Create a Cast component and verify that it has loaded.
- component.CreateComponentContextAndStartComponent(kTestAppId);
- component.CheckAppUrl(app_url);
- // Terminate the component that provides the ContextProvider service and
- // wait for the Cast component to terminate, without allowing the message-
- // loop to spin in-between.
- component.WaitForComponentDestroyed();
- // Create a second Cast component and verify that it has loaded.
- // There is no guarantee that the CastRunner has detected the old web.Context
- // disconnecting yet, so attempts to launch Cast components could fail.
- // WebContentRunner::CreateFrameWithParams() will synchronously verify that
- // the web.Context is not-yet-closed, to work-around that.
- TestCastComponent second_component(cast_runner());
- second_component.app_config_manager()->AddApp(kTestAppId, app_url);
- second_component.CreateComponentContextAndStartComponent(kTestAppId);
- second_component.CheckAppUrl(app_url);
- }
- TEST_F(CastRunnerIntegrationTest, ApiBindings) {
- TestCastComponent component(cast_runner());
- component.app_config_manager()->AddApp(kTestAppId,
- test_server().GetURL(kBlankAppUrl));
- component.CreateComponentContextAndStartComponent();
- // Verify that we can communicate with the binding added in
- // CastRunnerIntegrationTest().
- EXPECT_EQ(component.ExecuteJavaScript("1+2+\"\""), "3");
- }
- TEST_F(CastRunnerIntegrationTest, IncorrectCastAppId) {
- TestCastComponent component(cast_runner());
- const char kIncorrectComponentUrl[] = "cast:99999999";
- component.CreateComponentContext(kIncorrectComponentUrl);
- component.StartCastComponent(kIncorrectComponentUrl);
- // Run the loop until the ComponentController is dropped.
- component.ExpectControllerDisconnectWithStatus(ZX_ERR_PEER_CLOSED);
- EXPECT_TRUE(!component.component_state());
- }
- TEST_F(CastRunnerIntegrationTest, UrlRequestRewriteRulesProvider) {
- TestCastComponent component(cast_runner());
- GURL echo_app_url = test_server().GetURL(kEchoHeaderPath);
- component.app_config_manager()->AddApp(kTestAppId, echo_app_url);
- component.CreateComponentContextAndStartComponent();
- component.CheckAppUrl(echo_app_url);
- EXPECT_EQ(component.ExecuteJavaScript("document.body.innerText"),
- "TestHeaderValue");
- }
- TEST_F(CastRunnerIntegrationTest, ApplicationControllerBound) {
- TestCastComponent component(cast_runner());
- component.app_config_manager()->AddApp(kTestAppId,
- test_server().GetURL(kBlankAppUrl));
- component.CreateComponentContextAndStartComponent();
- // Spin the message loop to handle creation of the component state.
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(component.component_state());
- EXPECT_TRUE(component.component_state()->application_context()->controller());
- }
- // Verify an App launched with remote debugging enabled is properly reachable.
- TEST_F(CastRunnerIntegrationTest, RemoteDebugging) {
- TestCastComponent component(cast_runner());
- GURL app_url = test_server().GetURL(kBlankAppUrl);
- auto app_config =
- FakeApplicationConfigManager::CreateConfig(kTestAppId, app_url);
- app_config.set_enable_remote_debugging(true);
- component.app_config_manager()->AddAppConfig(std::move(app_config));
- component.CreateComponentContextAndStartComponent();
- // Connect to the debug service and ensure we get the proper response.
- base::Value devtools_list =
- GetDevToolsListFromPort(CastRunner::kRemoteDebuggingPort);
- ASSERT_TRUE(devtools_list.is_list());
- EXPECT_EQ(devtools_list.GetListDeprecated().size(), 1u);
- base::Value* devtools_url =
- devtools_list.GetListDeprecated()[0].FindPath("url");
- ASSERT_TRUE(devtools_url->is_string());
- EXPECT_EQ(devtools_url->GetString(), app_url.spec());
- }
- TEST_F(CastRunnerIntegrationTest, IsolatedContext) {
- TestCastComponent component(cast_runner());
- const GURL kContentDirectoryUrl("fuchsia-dir://testdata/empty.html");
- component.RegisterAppWithTestData(kContentDirectoryUrl);
- component.CreateComponentContextAndStartComponent();
- component.CheckAppUrl(kContentDirectoryUrl);
- }
- // Test the lack of CastAgent service does not cause a CastRunner crash.
- TEST_F(CastRunnerIntegrationTest, NoCastAgent) {
- TestCastComponent component(cast_runner());
- component.app_config_manager()->AddApp(kTestAppId,
- test_server().GetURL(kEchoHeaderPath));
- component.StartCastComponent(base::StrCat({"cast:", kTestAppId}));
- component.ExpectControllerDisconnectWithStatus(ZX_ERR_PEER_CLOSED);
- }
- // Test the CastAgent disconnecting does not cause a CastRunner crash.
- TEST_F(CastRunnerIntegrationTest, DisconnectedCastAgent) {
- TestCastComponent component(cast_runner());
- component.app_config_manager()->AddApp(kTestAppId,
- test_server().GetURL(kEchoHeaderPath));
- component.CreateComponentContextAndStartComponent();
- // Tear down the ComponentState, this should close the Agent connection and
- // shut down the CastComponent.
- component.component_state()->Disconnect();
- component.ExpectControllerDisconnectWithStatus(ZX_ERR_PEER_CLOSED);
- }
- // Test that the ApiBindings and RewriteRules are received from the secondary
- // DummyAgent. This validates that the |agent_url| retrieved from
- // AppConfigManager is the one used to retrieve the bindings and the rewrite
- // rules.
- TEST_F(CastRunnerIntegrationTest, ApplicationConfigAgentUrl) {
- TestCastComponent component(cast_runner());
- // These are part of the secondary agent, and CastRunner will contact
- // the secondary agent for both of them.
- FakeUrlRequestRewriteRulesProvider dummy_url_request_rewrite_rules_provider;
- FakeApiBindingsImpl 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(kBlankAppUrl));
- app_config.set_agent_url(kDummyAgentUrl);
- component.app_config_manager()->AddAppConfig(std::move(app_config));
- // Instantiate the bindings that are returned in the multi-agent scenario. The
- // bindings returned for the single-agent scenario are not initialized.
- std::vector<chromium::cast::ApiBinding> binding_list;
- chromium::cast::ApiBinding echo_binding;
- echo_binding.set_before_load_script(base::MemBufferFromString(
- "window.echo = cast.__platform__.PortConnector.bind('dummyService');",
- "test"));
- binding_list.emplace_back(std::move(echo_binding));
- // Assign the bindings to the multi-agent binding.
- dummy_agent_api_bindings.set_bindings(std::move(binding_list));
- auto component_url = base::StrCat({"cast:", kTestAppId});
- component.CreateComponentContext(component_url, /*with_fake_agent=*/false);
- EXPECT_TRUE(component.component_context());
- base::RunLoop run_loop;
- FakeComponentState* dummy_component_state = nullptr;
- component.component_context()->RegisterCreateComponentStateCallback(
- kDummyAgentUrl,
- base::BindLambdaForTesting(
- [&](base::StringPiece component_url)
- -> std::unique_ptr<cr_fuchsia::AgentImpl::ComponentStateBase> {
- run_loop.Quit();
- auto result = std::make_unique<FakeComponentState>(
- component_url, component.app_config_manager(),
- &dummy_agent_api_bindings,
- &dummy_url_request_rewrite_rules_provider);
- dummy_component_state = result.get();
- return result;
- }));
- component.StartCastComponent(component_url);
- // Wait for the component state to be created.
- run_loop.Run();
- // Validate that the component state in the default agent wasn't crated.
- EXPECT_FALSE(component.component_state());
- // Shutdown component before destroying dummy_agent_api_bindings.
- base::RunLoop shutdown_run_loop;
- dummy_component_state->set_on_delete(shutdown_run_loop.QuitClosure());
- component.component_controller()->ptr().Unbind();
- shutdown_run_loop.Run();
- }
- // Test that when RewriteRules are not provided, a WebComponent is still
- // created. Further validate that the primary agent does not provide ApiBindings
- // or RewriteRules.
- TEST_F(CastRunnerIntegrationTest, ApplicationConfigAgentUrlRewriteOptional) {
- TestCastComponent component(cast_runner());
- FakeApiBindingsImpl 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(kBlankAppUrl));
- app_config.set_agent_url(kDummyAgentUrl);
- component.app_config_manager()->AddAppConfig(std::move(app_config));
- // Instantiate the bindings that are returned in the multi-agent scenario. The
- // bindings returned for the single-agent scenario are not initialized.
- std::vector<chromium::cast::ApiBinding> binding_list;
- chromium::cast::ApiBinding echo_binding;
- echo_binding.set_before_load_script(base::MemBufferFromString(
- "window.echo = cast.__platform__.PortConnector.bind('dummyService');",
- "test"));
- binding_list.emplace_back(std::move(echo_binding));
- // Assign the bindings to the multi-agent binding.
- dummy_agent_api_bindings.set_bindings(std::move(binding_list));
- auto component_url = base::StrCat({"cast:", kTestAppId});
- component.CreateComponentContext(component_url, /*with_fake_agent=*/false);
- base::RunLoop run_loop;
- FakeComponentState* dummy_component_state = nullptr;
- component.component_context()->RegisterCreateComponentStateCallback(
- kDummyAgentUrl,
- base::BindLambdaForTesting(
- [&](base::StringPiece component_url)
- -> std::unique_ptr<cr_fuchsia::AgentImpl::ComponentStateBase> {
- run_loop.Quit();
- auto result = std::make_unique<FakeComponentState>(
- component_url, component.app_config_manager(),
- &dummy_agent_api_bindings, nullptr);
- dummy_component_state = result.get();
- return result;
- }));
- component.StartCastComponent(component_url);
- // Wait for the component state to be created.
- run_loop.Run();
- // Validate that the component state in the default agent wasn't crated.
- EXPECT_FALSE(component.component_state());
- // Shutdown component before destroying dummy_agent_api_bindings.
- base::RunLoop shutdown_run_loop;
- dummy_component_state->set_on_delete(shutdown_run_loop.QuitClosure());
- component.component_controller()->ptr().Unbind();
- shutdown_run_loop.Run();
- }
- class AudioCastRunnerIntegrationTest : public CastRunnerIntegrationTest {
- public:
- AudioCastRunnerIntegrationTest()
- : CastRunnerIntegrationTest(
- test::kCastRunnerFeaturesFakeAudioDeviceEnumerator) {}
- };
- TEST_F(AudioCastRunnerIntegrationTest, MicrophoneRedirect) {
- TestCastComponent component(cast_runner());
- GURL app_url = test_server().GetURL("/microphone.html");
- auto app_config =
- FakeApplicationConfigManager::CreateConfig(kTestAppId, app_url);
- fuchsia::web::PermissionDescriptor mic_permission;
- mic_permission.set_type(fuchsia::web::PermissionType::MICROPHONE);
- app_config.mutable_permissions()->push_back(std::move(mic_permission));
- component.app_config_manager()->AddAppConfig(std::move(app_config));
- component.CreateComponentContextAndStartComponent();
- // Expect fuchsia.media.Audio connection to be redirected to the agent.
- base::RunLoop run_loop;
- ASSERT_EQ(
- component.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_),
- ZX_OK);
- component.ExecuteJavaScript("connectMicrophone();");
- // Will quit once AudioCapturer is connected.
- run_loop.Run();
- }
- TEST_F(CastRunnerIntegrationTest, CameraRedirect) {
- TestCastComponent component(cast_runner());
- GURL app_url = test_server().GetURL("/camera.html");
- auto app_config =
- FakeApplicationConfigManager::CreateConfig(kTestAppId, app_url);
- fuchsia::web::PermissionDescriptor camera_permission;
- camera_permission.set_type(fuchsia::web::PermissionType::CAMERA);
- app_config.mutable_permissions()->push_back(std::move(camera_permission));
- component.app_config_manager()->AddAppConfig(std::move(app_config));
- component.CreateComponentContextAndStartComponent();
- // Expect fuchsia.camera3.DeviceWatcher connection to be redirected to the
- // agent.
- bool received_device_watcher_request = false;
- ASSERT_EQ(
- component.component_state()->outgoing_directory()->AddPublicService(
- std::make_unique<vfs::Service>(
- [&received_device_watcher_request](
- zx::channel channel, async_dispatcher_t* dispatcher) mutable {
- received_device_watcher_request = true;
- }),
- fuchsia::camera3::DeviceWatcher::Name_),
- ZX_OK);
- component.ExecuteJavaScript("connectCamera();");
- EXPECT_TRUE(received_device_watcher_request);
- }
- TEST_F(CastRunnerIntegrationTest, CameraAccessAfterComponentShutdown) {
- TestCastComponent component(cast_runner());
- GURL app_url = test_server().GetURL("/camera.html");
- // First app with camera permission.
- auto app_config =
- FakeApplicationConfigManager::CreateConfig(kTestAppId, app_url);
- fuchsia::web::PermissionDescriptor camera_permission;
- camera_permission.set_type(fuchsia::web::PermissionType::CAMERA);
- app_config.mutable_permissions()->push_back(std::move(camera_permission));
- component.app_config_manager()->AddAppConfig(std::move(app_config));
- // Second app without camera permission (but it will still try to access
- // fuchsia.camera3.DeviceWatcher service to enumerate devices).
- TestCastComponent second_component(cast_runner());
- auto app_config_2 =
- FakeApplicationConfigManager::CreateConfig(kSecondTestAppId, app_url);
- second_component.app_config_manager()->AddAppConfig(std::move(app_config_2));
- // Start and then shutdown the first app.
- component.CreateComponentContextAndStartComponent(kTestAppId);
- component.ShutdownComponent();
- component.ResetComponentState();
- // Start the second app and try to connect the camera. It's expected to fail
- // to initialize the camera without crashing CastRunner.
- second_component.CreateComponentContextAndStartComponent(kSecondTestAppId);
- EXPECT_EQ(second_component.ExecuteJavaScript("connectCamera();"),
- "getUserMediaFailed");
- }
- TEST_F(CastRunnerIntegrationTest, MultipleComponentsUsingCamera) {
- TestCastComponent first_component(cast_runner());
- TestCastComponent second_component(cast_runner());
- GURL app_url = test_server().GetURL("/camera.html");
- // Start two apps, both with camera permission.
- auto app_config1 =
- FakeApplicationConfigManager::CreateConfig(kTestAppId, app_url);
- fuchsia::web::PermissionDescriptor camera_permission1;
- camera_permission1.set_type(fuchsia::web::PermissionType::CAMERA);
- app_config1.mutable_permissions()->push_back(std::move(camera_permission1));
- first_component.app_config_manager()->AddAppConfig(std::move(app_config1));
- first_component.CreateComponentContextAndStartComponent(kTestAppId);
- auto app_config2 =
- FakeApplicationConfigManager::CreateConfig(kSecondTestAppId, app_url);
- fuchsia::web::PermissionDescriptor camera_permission2;
- camera_permission2.set_type(fuchsia::web::PermissionType::CAMERA);
- app_config2.mutable_permissions()->push_back(std::move(camera_permission2));
- second_component.app_config_manager()->AddAppConfig(std::move(app_config2));
- second_component.CreateComponentContextAndStartComponent(kSecondTestAppId);
- // Shut down the first component.
- first_component.ShutdownComponent();
- first_component.ResetComponentState();
- // Expect fuchsia.camera3.DeviceWatcher connection to be redirected to the
- // agent.
- bool received_device_watcher_request = false;
- ASSERT_EQ(
- second_component.component_state()
- ->outgoing_directory()
- ->AddPublicService(std::make_unique<vfs::Service>(
- [&received_device_watcher_request](
- zx::channel channel,
- async_dispatcher_t* dispatcher) mutable {
- received_device_watcher_request = true;
- }),
- fuchsia::camera3::DeviceWatcher::Name_),
- ZX_OK);
- second_component.ExecuteJavaScript("connectCamera();");
- EXPECT_TRUE(received_device_watcher_request);
- }
- class HeadlessCastRunnerIntegrationTest : public CastRunnerIntegrationTest {
- public:
- HeadlessCastRunnerIntegrationTest()
- : CastRunnerIntegrationTest(test::kCastRunnerFeaturesHeadless) {}
- };
- // A basic integration test ensuring a basic cast request launches the right
- // URL in the Chromium service.
- TEST_F(HeadlessCastRunnerIntegrationTest, Headless) {
- TestCastComponent component(cast_runner());
- const char kAnimationPath[] = "/css_animation.html";
- const GURL animation_url = test_server().GetURL(kAnimationPath);
- component.app_config_manager()->AddApp(kTestAppId, animation_url);
- component.CreateComponentContextAndStartComponent();
- auto tokens = scenic::ViewTokenPair::New();
- // Create a view.
- auto view_provider = component.component_services_client()
- ->Connect<fuchsia::ui::app::ViewProvider>();
- view_provider->CreateView(std::move(tokens.view_holder_token.value), {}, {});
- component.api_bindings()->RunAndReturnConnectedPort("animation_finished");
- // Verify that dropped "view" EventPair is handled properly.
- tokens.view_token.value.reset();
- component.api_bindings()->RunAndReturnConnectedPort("view_hidden");
- }
- // Isolated *and* headless? Doesn't sound like much fun!
- TEST_F(HeadlessCastRunnerIntegrationTest, IsolatedAndHeadless) {
- TestCastComponent component(cast_runner());
- const GURL kContentDirectoryUrl("fuchsia-dir://testdata/empty.html");
- component.RegisterAppWithTestData(kContentDirectoryUrl);
- component.CreateComponentContextAndStartComponent();
- component.CheckAppUrl(kContentDirectoryUrl);
- }
- // Verifies that the Context can establish a connection to the Agent's
- // MetricsRecorder service.
- TEST_F(CastRunnerIntegrationTest, LegacyMetricsRedirect) {
- TestCastComponent component(cast_runner());
- GURL app_url = test_server().GetURL(kBlankAppUrl);
- component.app_config_manager()->AddApp(kTestAppId, app_url);
- auto component_url = base::StrCat({"cast:", kTestAppId});
- component.CreateComponentContext(component_url);
- EXPECT_TRUE(component.component_context());
- base::RunLoop run_loop;
- // Add MetricsRecorder the the component's incoming_services.
- ASSERT_EQ(
- component.component_services()->AddPublicService(
- std::make_unique<vfs::Service>(
- [&run_loop](zx::channel request, async_dispatcher_t* dispatcher) {
- run_loop.Quit();
- }),
- fuchsia::legacymetrics::MetricsRecorder::Name_),
- ZX_OK);
- component.StartCastComponent(component_url);
- // Wait until we see the CastRunner connect to the MetricsRecorder service.
- run_loop.Run();
- }
- // Verifies that the ApplicationContext::OnApplicationTerminated() is notified
- // with the component exit code if the web content closes itself.
- TEST_F(CastRunnerIntegrationTest, OnApplicationTerminated_WindowClose) {
- TestCastComponent component(cast_runner());
- const GURL url = test_server().GetURL(kBlankAppUrl);
- component.app_config_manager()->AddApp(kTestAppId, url);
- component.CreateComponentContextAndStartComponent();
- // It is possible to observe the ComponentController close before
- // OnApplicationTerminated() is received, so ignore that.
- component.component_controller()->ptr().set_error_handler([](zx_status_t) {});
- // Have the web content close itself, and wait for OnApplicationTerminated().
- EXPECT_EQ(component.ExecuteJavaScript("window.close()"), "undefined");
- absl::optional<zx_status_t> exit_code = component.component_state()
- ->application_context()
- ->WaitForApplicationTerminated();
- ASSERT_TRUE(exit_code);
- EXPECT_EQ(exit_code.value(), ZX_OK);
- }
- // Verifies that the ComponentController reports TerminationReason::EXITED and
- // exit code ZX_OK if the web content terminates itself.
- // TODO(https://crbug.com/1066833): Make this a WebRunner test.
- TEST_F(CastRunnerIntegrationTest, OnTerminated_WindowClose) {
- TestCastComponent component(cast_runner());
- const GURL url = test_server().GetURL(kBlankAppUrl);
- component.app_config_manager()->AddApp(kTestAppId, url);
- component.CreateComponentContextAndStartComponent();
- // Register an handler on the ComponentController channel, for the
- // OnTerminated event.
- base::RunLoop exit_code_loop;
- component.component_controller()->ptr().set_error_handler(
- [quit_loop = exit_code_loop.QuitClosure()](zx_status_t) {
- quit_loop.Run();
- ADD_FAILURE();
- });
- component.component_controller()->ptr().events().OnTerminated =
- [quit_loop = exit_code_loop.QuitClosure()](
- int64_t exit_code, fuchsia::sys::TerminationReason reason) {
- quit_loop.Run();
- EXPECT_EQ(reason, fuchsia::sys::TerminationReason::EXITED);
- EXPECT_EQ(exit_code, ZX_OK);
- };
- // Have the web content close itself, and wait for OnTerminated().
- EXPECT_EQ(component.ExecuteJavaScript("window.close()"), "undefined");
- exit_code_loop.Run();
- component.component_controller()->ptr().Unbind();
- }
- // Verifies that the ComponentController reports TerminationReason::EXITED and
- // exit code ZX_OK if Kill() is used.
- // TODO(https://crbug.com/1066833): Make this a WebRunner test.
- TEST_F(CastRunnerIntegrationTest, OnTerminated_ComponentKill) {
- TestCastComponent component(cast_runner());
- const GURL url = test_server().GetURL(kBlankAppUrl);
- component.app_config_manager()->AddApp(kTestAppId, url);
- component.CreateComponentContextAndStartComponent();
- // Register an handler on the ComponentController channel, for the
- // OnTerminated event.
- base::RunLoop exit_code_loop;
- component.component_controller()->ptr().set_error_handler(
- [quit_loop = exit_code_loop.QuitClosure()](zx_status_t) {
- quit_loop.Run();
- ADD_FAILURE();
- });
- component.component_controller()->ptr().events().OnTerminated =
- [quit_loop = exit_code_loop.QuitClosure()](
- int64_t exit_code, fuchsia::sys::TerminationReason reason) {
- quit_loop.Run();
- EXPECT_EQ(reason, fuchsia::sys::TerminationReason::EXITED);
- EXPECT_EQ(exit_code, ZX_OK);
- };
- // Kill() the component and wait for OnTerminated().
- component.component_controller()->ptr()->Kill();
- exit_code_loop.Run();
- component.component_controller()->ptr().Unbind();
- }
- // Ensures that CastRunner handles the value not being specified.
- // TODO(https://crrev.com/c/2516246): Check for no logging.
- TEST_F(CastRunnerIntegrationTest, InitialMinConsoleLogSeverity_NotSet) {
- TestCastComponent component(cast_runner());
- GURL app_url = test_server().GetURL(kBlankAppUrl);
- auto app_config =
- FakeApplicationConfigManager::CreateConfig(kTestAppId, app_url);
- EXPECT_FALSE(app_config.has_initial_min_console_log_severity());
- component.app_config_manager()->AddAppConfig(std::move(app_config));
- component.CreateComponentContextAndStartComponent();
- component.CheckAppUrl(app_url);
- }
- // TODO(https://crrev.com/c/2516246): Check for logging.
- TEST_F(CastRunnerIntegrationTest, InitialMinConsoleLogSeverity_DEBUG) {
- TestCastComponent component(cast_runner());
- GURL app_url = test_server().GetURL(kBlankAppUrl);
- auto app_config =
- FakeApplicationConfigManager::CreateConfig(kTestAppId, app_url);
- *app_config.mutable_initial_min_console_log_severity() =
- fuchsia::diagnostics::Severity::DEBUG;
- component.app_config_manager()->AddAppConfig(std::move(app_config));
- component.CreateComponentContextAndStartComponent();
- component.CheckAppUrl(app_url);
- }
- TEST_F(CastRunnerIntegrationTest, WebGLContextAbsentWithoutVulkanFeature) {
- TestCastComponent component(cast_runner());
- const char kTestPath[] = "/webgl_presence.html";
- const GURL test_url = test_server().GetURL(kTestPath);
- component.app_config_manager()->AddApp(kTestAppId, test_url);
- component.CreateComponentContextAndStartComponent();
- EXPECT_EQ(component.ExecuteJavaScript("document.title"), "absent");
- }
- TEST_F(CastRunnerIntegrationTest,
- WebGLContextAbsentWithoutVulkanFeature_IsolatedRunner) {
- TestCastComponent component(cast_runner());
- const GURL kContentDirectoryUrl("fuchsia-dir://testdata/webgl_presence.html");
- component.RegisterAppWithTestData(kContentDirectoryUrl);
- component.CreateComponentContextAndStartComponent();
- component.CheckAppUrl(kContentDirectoryUrl);
- EXPECT_EQ(component.ExecuteJavaScript("document.title"), "absent");
- }
- // Verifies that starting a component fails if CORS exempt headers cannot be
- // fetched.
- TEST_F(CastRunnerIntegrationTest, MissingCorsExemptHeaderProvider) {
- TestCastComponent component(cast_runner());
- GURL app_url = test_server().GetURL(kBlankAppUrl);
- component.app_config_manager()->AddApp(kTestAppId, app_url);
- // Start the Cast component, and wait for the controller to disconnect.
- component.StartCastComponent(base::StrCat({"cast:", kTestAppId}));
- component.ExpectControllerDisconnectWithStatus(ZX_ERR_PEER_CLOSED);
- EXPECT_FALSE(component.component_state());
- }
- // Verifies that CastRunner offers a chromium.cast.DataReset service.
- // Verifies that after the DeletePersistentData() API is invoked, no further
- // component-start requests are honoured.
- // TODO(crbug.com/1146474): Expand the test to verify that the persisted data is
- // correctly cleared (e.g. using a custom test HTML app that uses persisted
- // data).
- TEST_F(CastRunnerIntegrationTest, DataReset_Service) {
- base::RunLoop loop;
- auto data_reset = cast_runner_services().Connect<chromium::cast::DataReset>();
- data_reset.set_error_handler([quit_loop = loop.QuitClosure()](zx_status_t) {
- quit_loop.Run();
- ADD_FAILURE();
- });
- bool succeeded = false;
- data_reset->DeletePersistentData([&succeeded, &loop](bool result) {
- succeeded = result;
- loop.Quit();
- });
- loop.Run();
- EXPECT_TRUE(succeeded);
- // Verify that it is no longer possible to launch a component.
- TestCastComponent component(cast_runner());
- GURL app_url = test_server().GetURL(kBlankAppUrl);
- component.app_config_manager()->AddApp(kTestAppId, app_url);
- component.StartCastComponent(base::StrCat({"cast:", kTestAppId}));
- component.ExpectControllerDisconnectWithStatus(ZX_ERR_PEER_CLOSED);
- }
- // Verifies that CastRunner offers a chromium.cast.DataReset component, that
- // provides the DataReset service.
- TEST_F(CastRunnerIntegrationTest, DataReset_component) {
- TestCastComponent component(cast_runner());
- constexpr char kDataResetComponentName[] = "cast:chromium.cast.DataReset";
- component.StartCastComponent(kDataResetComponentName);
- base::RunLoop loop;
- auto data_reset = component.component_services_client()
- ->Connect<chromium::cast::DataReset>();
- data_reset.set_error_handler([quit_loop = loop.QuitClosure()](zx_status_t) {
- quit_loop.Run();
- ADD_FAILURE();
- });
- bool succeeded = false;
- data_reset->DeletePersistentData([&succeeded, &loop](bool result) {
- succeeded = result;
- loop.Quit();
- });
- loop.Run();
- EXPECT_TRUE(succeeded);
- }
- class CastRunnerFrameHostIntegrationTest : public CastRunnerIntegrationTest {
- public:
- CastRunnerFrameHostIntegrationTest()
- : CastRunnerIntegrationTest(test::kCastRunnerFeaturesFrameHost) {}
- };
- // Verifies that the CastRunner offers a fuchsia.web.FrameHost service.
- // TODO(crbug.com/1144102): Clean up config-data vs command-line flags handling
- // and add a not-enabled test here.
- TEST_F(CastRunnerFrameHostIntegrationTest, FrameHostComponent) {
- TestCastComponent component(cast_runner());
- constexpr char kFrameHostComponentName[] = "cast:fuchsia.web.FrameHost";
- component.StartCastComponent(kFrameHostComponentName);
- // Connect to the fuchsia.web.FrameHost service and create a Frame.
- auto frame_host =
- component.component_services_client()->Connect<fuchsia::web::FrameHost>();
- fuchsia::web::FramePtr frame;
- frame_host->CreateFrameWithParams(fuchsia::web::CreateFrameParams(),
- frame.NewRequest());
- // Verify that a response is received for a LoadUrl() request to the frame.
- fuchsia::web::NavigationControllerPtr controller;
- frame->GetNavigationController(controller.NewRequest());
- const GURL url = test_server().GetURL(kBlankAppUrl);
- EXPECT_TRUE(LoadUrlAndExpectResponse(
- controller.get(), fuchsia::web::LoadUrlParams(), url.spec()));
- }
- #if defined(ARCH_CPU_ARM_FAMILY)
- // TODO(crbug.com/1058247): Support Vulkan in tests on ARM64.
- #define MAYBE_VulkanCastRunnerIntegrationTest \
- DISABLED_VulkanCastRunnerIntegrationTest
- #else
- #define MAYBE_VulkanCastRunnerIntegrationTest VulkanCastRunnerIntegrationTest
- #endif
- class MAYBE_VulkanCastRunnerIntegrationTest : public CastRunnerIntegrationTest {
- public:
- MAYBE_VulkanCastRunnerIntegrationTest()
- : CastRunnerIntegrationTest(test::kCastRunnerFeaturesVulkan) {}
- };
- TEST_F(MAYBE_VulkanCastRunnerIntegrationTest,
- WebGLContextPresentWithVulkanFeature) {
- TestCastComponent component(cast_runner());
- const char kTestPath[] = "/webgl_presence.html";
- const GURL test_url = test_server().GetURL(kTestPath);
- component.app_config_manager()->AddApp(kTestAppId, test_url);
- component.CreateComponentContextAndStartComponent();
- EXPECT_EQ(component.ExecuteJavaScript("document.title"), "present");
- }
- TEST_F(MAYBE_VulkanCastRunnerIntegrationTest,
- WebGLContextPresentWithVulkanFeature_IsolatedRunner) {
- TestCastComponent component(cast_runner());
- const GURL kContentDirectoryUrl("fuchsia-dir://testdata/webgl_presence.html");
- component.RegisterAppWithTestData(kContentDirectoryUrl);
- component.CreateComponentContextAndStartComponent();
- component.CheckAppUrl(kContentDirectoryUrl);
- EXPECT_EQ(component.ExecuteJavaScript("document.title"), "present");
- }
|