context_provider_impl_unittest.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "fuchsia_web/webengine/context_provider_impl.h"
  5. #include <fuchsia/sys/cpp/fidl_test_base.h>
  6. #include <fuchsia/web/cpp/fidl.h>
  7. #include <lib/fdio/directory.h>
  8. #include <lib/fidl/cpp/binding.h>
  9. #include <lib/sys/cpp/component_context.h>
  10. #include <lib/sys/cpp/outgoing_directory.h>
  11. #include <lib/zx/socket.h>
  12. #include <zircon/processargs.h>
  13. #include <zircon/types.h>
  14. #include <functional>
  15. #include <string>
  16. #include <utility>
  17. #include <vector>
  18. #include "base/base_switches.h"
  19. #include "base/bind.h"
  20. #include "base/callback.h"
  21. #include "base/callback_helpers.h"
  22. #include "base/command_line.h"
  23. #include "base/files/file.h"
  24. #include "base/files/file_util.h"
  25. #include "base/files/scoped_temp_dir.h"
  26. #include "base/fuchsia/file_utils.h"
  27. #include "base/fuchsia/fuchsia_logging.h"
  28. #include "base/fuchsia/process_context.h"
  29. #include "base/fuchsia/scoped_service_binding.h"
  30. #include "base/fuchsia/test_component_context_for_process.h"
  31. #include "base/path_service.h"
  32. #include "base/strings/strcat.h"
  33. #include "base/test/bind.h"
  34. #include "base/test/multiprocess_test.h"
  35. #include "base/test/task_environment.h"
  36. #include "base/test/test_timeouts.h"
  37. #include "build/build_config.h"
  38. #include "fuchsia_web/webengine/fake_context.h"
  39. #include "fuchsia_web/webengine/switches.h"
  40. #include "services/network/public/cpp/network_switches.h"
  41. #include "testing/gmock/include/gmock/gmock.h"
  42. #include "testing/gtest/include/gtest/gtest.h"
  43. #include "testing/multiprocess_func_list.h"
  44. namespace {
  45. constexpr char kTestDataFileIn[] = "DataFileIn";
  46. constexpr char kTestDataFileOut[] = "DataFileOut";
  47. constexpr char kUrl[] = "chrome://:emorhc";
  48. constexpr char kTitle[] = "Palindrome";
  49. constexpr uint64_t kTestQuotaBytes = 1024;
  50. constexpr char kTestQuotaBytesSwitchValue[] = "1024";
  51. MULTIPROCESS_TEST_MAIN(SpawnContextServer) {
  52. base::test::SingleThreadTaskEnvironment task_environment(
  53. base::test::SingleThreadTaskEnvironment::MainThreadType::IO);
  54. LOG(INFO) << "SpawnContextServer test component started.";
  55. base::FilePath data_dir(base::kPersistedDataDirectoryPath);
  56. if (base::PathExists(data_dir.AppendASCII(kTestDataFileIn))) {
  57. auto out_file = data_dir.AppendASCII(kTestDataFileOut);
  58. EXPECT_EQ(base::WriteFile(out_file, nullptr, 0), 0);
  59. }
  60. // Publish the fake fuchsia.web.Context implementation for the test to use.
  61. FakeContext context;
  62. fidl::BindingSet<fuchsia::web::Context> bindings;
  63. base::ComponentContextForProcess()->outgoing()->AddPublicService(
  64. bindings.GetHandler(&context), "fuchsia.web.Context");
  65. base::ComponentContextForProcess()->outgoing()->ServeFromStartupInfo();
  66. // When a Frame's NavigationEventListener is bound, immediately broadcast a
  67. // navigation event to its listeners.
  68. context.set_on_create_frame_callback(
  69. base::BindRepeating([](FakeFrame* frame) {
  70. frame->set_on_set_listener_callback(base::BindOnce(
  71. [](FakeFrame* frame) {
  72. fuchsia::web::NavigationState state;
  73. state.set_url(kUrl);
  74. state.set_title(kTitle);
  75. frame->listener()->OnNavigationStateChanged(std::move(state),
  76. []() {});
  77. },
  78. frame));
  79. }));
  80. // Quit the process when the context is destroyed.
  81. base::RunLoop run_loop;
  82. bindings.set_empty_set_handler(
  83. [quit_loop = run_loop.QuitClosure()]() { quit_loop.Run(); });
  84. run_loop.Run();
  85. return 0;
  86. }
  87. // Fake implementation of the Launcher for the isolated environment in which
  88. // web instance Components are launched.
  89. class FakeSysLauncher final : public fuchsia::sys::testing::Launcher_TestBase {
  90. public:
  91. using CreateComponentCallback =
  92. base::OnceCallback<void(const base::CommandLine&)>;
  93. explicit FakeSysLauncher(fuchsia::sys::Launcher* real_launcher)
  94. : real_launcher_(real_launcher) {}
  95. ~FakeSysLauncher() override = default;
  96. void set_create_component_callback(CreateComponentCallback callback) {
  97. create_component_callback_ = std::move(callback);
  98. }
  99. void Bind(fidl::InterfaceRequest<fuchsia::sys::Launcher> request) {
  100. bindings_.AddBinding(this, std::move(request));
  101. }
  102. // fuchsia::sys::Launcher implementation.
  103. void CreateComponent(fuchsia::sys::LaunchInfo launch_info,
  104. fidl::InterfaceRequest<fuchsia::sys::ComponentController>
  105. request) override {
  106. // |arguments| should not include argv[0] (i.e. the program name), which
  107. // would be empty in a no-program CommandLine instance. Verify that the
  108. // |arguments| are either empty or have a non-empty first element.
  109. EXPECT_TRUE(launch_info.arguments->empty() ||
  110. !launch_info.arguments->at(0).empty());
  111. // |arguments| omits argv[0] so cannot be used directly to initialize a
  112. // CommandLine, but CommandLine provides useful switch processing logic.
  113. // Prepend an empty element to a copy of |arguments| and use that to create
  114. // a valid CommandLine.
  115. std::vector<std::string> command_line_args(*launch_info.arguments);
  116. command_line_args.emplace(command_line_args.begin());
  117. const base::CommandLine command_line(command_line_args);
  118. CHECK(!command_line.HasSwitch(switches::kTestChildProcess));
  119. // If a create-component-callback is specified then there is no need to
  120. // actually launch a component.
  121. if (create_component_callback_) {
  122. std::move(create_component_callback_).Run(command_line);
  123. return;
  124. }
  125. // Otherwise, launch another instance of this test executable, configured to
  126. // run as a test child (similar to SpawnMultiProcessTestChild()). The
  127. // test-suite's component manifest cannot be re-used for this because it
  128. // specifies the "isolated-persistent-data" feature, causing the framework
  129. // to populate /data, which prevents the |data_directory| supplied in the
  130. // CreateContextParams from being mapped.
  131. // Launch the component via a fake manifest identical to the one used for
  132. // web instances, but which runs this test executable.
  133. EXPECT_EQ(launch_info.url,
  134. "fuchsia-pkg://fuchsia.com/web_engine#meta/web_instance.cmx");
  135. launch_info.url =
  136. "fuchsia-pkg://fuchsia.com/web_engine_unittests#meta/"
  137. "web_engine_unittests_fake_instance.cmx";
  138. launch_info.arguments->push_back(base::StrCat(
  139. {"--", switches::kTestChildProcess, "=SpawnContextServer"}));
  140. // Bind /tmp in the new Component's flat namespace, to allow it to see
  141. // the GTest flagfile, if any.
  142. fuchsia::io::DirectoryHandle tmp_directory;
  143. zx_status_t status = fdio_open(
  144. "/tmp", static_cast<uint32_t>(fuchsia::io::OpenFlags::RIGHT_READABLE),
  145. tmp_directory.NewRequest().TakeChannel().release());
  146. ZX_CHECK(status == ZX_OK, status) << "fdio_open(/tmp)";
  147. launch_info.flat_namespace->paths.push_back("/tmp");
  148. launch_info.flat_namespace->directories.push_back(
  149. tmp_directory.TakeChannel());
  150. // Redirect the sub-process Component's stderr to feed into the test output.
  151. launch_info.err = fuchsia::sys::FileDescriptor::New();
  152. launch_info.err->type0 = PA_FD;
  153. status = fdio_fd_clone(STDERR_FILENO,
  154. launch_info.err->handle0.reset_and_get_address());
  155. ZX_CHECK(status == ZX_OK, status);
  156. real_launcher_->CreateComponent(std::move(launch_info), std::move(request));
  157. }
  158. private:
  159. void NotImplemented_(const std::string& name) override {
  160. ADD_FAILURE() << "Unexpected call: " << name;
  161. }
  162. fidl::BindingSet<fuchsia::sys::Launcher> bindings_;
  163. fuchsia::sys::Launcher* const real_launcher_;
  164. CreateComponentCallback create_component_callback_;
  165. };
  166. // Fake implementation of the isolated Environment created by ContextProvider.
  167. class FakeNestedSysEnvironment
  168. : public fuchsia::sys::testing::Environment_TestBase {
  169. public:
  170. explicit FakeNestedSysEnvironment(FakeSysLauncher* fake_launcher)
  171. : fake_launcher_(fake_launcher) {}
  172. ~FakeNestedSysEnvironment() override = default;
  173. void Bind(fidl::InterfaceRequest<fuchsia::sys::Environment> request) {
  174. bindings_.AddBinding(this, std::move(request));
  175. }
  176. // fuchsia::sys::Environment implementation.
  177. void GetLauncher(fidl::InterfaceRequest<fuchsia::sys::Launcher>
  178. launcher_request) override {
  179. fake_launcher_->Bind(std::move(launcher_request));
  180. }
  181. private:
  182. void NotImplemented_(const std::string& name) override {
  183. ADD_FAILURE() << "Unexpected call: " << name;
  184. }
  185. FakeSysLauncher* const fake_launcher_;
  186. fidl::BindingSet<fuchsia::sys::Environment> bindings_;
  187. };
  188. // Fake implementation of the Environment in which the ContextProvider runs.
  189. class FakeSysEnvironment final
  190. : public fuchsia::sys::testing::Environment_TestBase {
  191. public:
  192. FakeSysEnvironment(sys::OutgoingDirectory* outgoing_directory,
  193. fuchsia::sys::Launcher* real_launcher)
  194. : bindings_(outgoing_directory, this),
  195. fake_launcher_(real_launcher),
  196. fake_nested_environment_(&fake_launcher_) {}
  197. ~FakeSysEnvironment() override = default;
  198. FakeSysLauncher& fake_launcher() { return fake_launcher_; }
  199. // fuchsia::sys::Environment implementation.
  200. void CreateNestedEnvironment(
  201. fidl::InterfaceRequest<fuchsia::sys::Environment> environment_request,
  202. fidl::InterfaceRequest<fuchsia::sys::EnvironmentController>
  203. controller_request,
  204. std::string label,
  205. fuchsia::sys::ServiceListPtr additional_services,
  206. fuchsia::sys::EnvironmentOptions options) override {
  207. EXPECT_TRUE(environment_request);
  208. EXPECT_TRUE(controller_request);
  209. EXPECT_FALSE(label.empty());
  210. // The nested environment should receive only the Loader service.
  211. ASSERT_TRUE(additional_services);
  212. ASSERT_EQ(additional_services->names.size(), 1u);
  213. EXPECT_EQ(additional_services->names[0], "fuchsia.sys.Loader");
  214. EXPECT_TRUE(additional_services->host_directory);
  215. EXPECT_FALSE(options.inherit_parent_services);
  216. EXPECT_FALSE(options.use_parent_runners);
  217. EXPECT_TRUE(options.delete_storage_on_death);
  218. fake_nested_environment_.Bind(std::move(environment_request));
  219. nested_environment_controller_request_ = std::move(controller_request);
  220. }
  221. void GetDirectory(zx::channel request) override {
  222. base::ComponentContextForProcess()->svc()->CloneChannel(
  223. fidl::InterfaceRequest<fuchsia::io::Directory>(std::move(request)));
  224. }
  225. private:
  226. void NotImplemented_(const std::string& name) override {
  227. ADD_FAILURE() << "Unexpected call: " << name;
  228. }
  229. base::ScopedServiceBinding<fuchsia::sys::Environment> bindings_;
  230. FakeSysLauncher fake_launcher_;
  231. FakeNestedSysEnvironment fake_nested_environment_;
  232. fidl::InterfaceRequest<fuchsia::sys::EnvironmentController>
  233. nested_environment_controller_request_;
  234. };
  235. fuchsia::web::CreateContextParams BuildCreateContextParams() {
  236. fuchsia::web::CreateContextParams output;
  237. zx_status_t result = fdio_service_connect(
  238. base::kServiceDirectoryPath,
  239. output.mutable_service_directory()->NewRequest().TakeChannel().release());
  240. ZX_CHECK(result == ZX_OK, result) << "Failed to open /svc";
  241. return output;
  242. }
  243. fidl::InterfaceHandle<fuchsia::io::Directory> OpenCacheDirectory() {
  244. fidl::InterfaceHandle<fuchsia::io::Directory> cache_handle;
  245. zx_status_t result =
  246. fdio_service_connect(base::kPersistedCacheDirectoryPath,
  247. cache_handle.NewRequest().TakeChannel().release());
  248. ZX_CHECK(result == ZX_OK, result) << "Failed to open /cache";
  249. return cache_handle;
  250. }
  251. } // namespace
  252. class ContextProviderImplTest : public base::MultiProcessTest {
  253. public:
  254. ContextProviderImplTest()
  255. : sys_launcher_(base::ComponentContextForProcess()
  256. ->svc()
  257. ->Connect<fuchsia::sys::Launcher>()),
  258. fake_environment_(test_component_context_.additional_services(),
  259. sys_launcher_.get()),
  260. provider_(std::make_unique<ContextProviderImpl>()) {
  261. bindings_.AddBinding(provider_.get(), provider_ptr_.NewRequest());
  262. }
  263. ContextProviderImplTest(const ContextProviderImplTest&) = delete;
  264. ContextProviderImplTest& operator=(const ContextProviderImplTest&) = delete;
  265. ~ContextProviderImplTest() override {
  266. provider_ptr_.Unbind();
  267. base::RunLoop().RunUntilIdle();
  268. }
  269. // Check if a Context is responsive by creating a Frame from it and then
  270. // listening for an event.
  271. void CheckContextResponsive(
  272. fidl::InterfacePtr<fuchsia::web::Context>* context) {
  273. // Call a Context method and wait for it to invoke a listener call.
  274. base::RunLoop run_loop;
  275. context->set_error_handler(
  276. [quit_loop = run_loop.QuitClosure()](zx_status_t status) {
  277. quit_loop.Run();
  278. ZX_LOG(ERROR, status) << " Context lost.";
  279. ADD_FAILURE();
  280. });
  281. fuchsia::web::FramePtr frame_ptr;
  282. frame_ptr.set_error_handler(
  283. [quit_loop = run_loop.QuitClosure()](zx_status_t status) {
  284. quit_loop.Run();
  285. ZX_LOG(ERROR, status) << " Frame lost.";
  286. ADD_FAILURE();
  287. });
  288. (*context)->CreateFrame(frame_ptr.NewRequest());
  289. // Create a Frame and expect to see a navigation event.
  290. CapturingNavigationStateObserver change_listener(run_loop.QuitClosure());
  291. fidl::Binding<fuchsia::web::NavigationEventListener>
  292. change_listener_binding(&change_listener);
  293. frame_ptr->SetNavigationEventListener2(change_listener_binding.NewBinding(),
  294. /*flags=*/{});
  295. run_loop.Run();
  296. ASSERT_TRUE(change_listener.captured_state()->has_url());
  297. EXPECT_EQ(change_listener.captured_state()->url(), kUrl);
  298. ASSERT_TRUE(change_listener.captured_state()->has_title());
  299. EXPECT_EQ(change_listener.captured_state()->title(), kTitle);
  300. }
  301. // Checks that the Context channel was dropped.
  302. void CheckContextUnresponsive(
  303. fidl::InterfacePtr<fuchsia::web::Context>* context) {
  304. base::RunLoop run_loop;
  305. context->set_error_handler(
  306. [quit_loop = run_loop.QuitClosure()](zx_status_t status) {
  307. quit_loop.Run();
  308. EXPECT_EQ(status, ZX_ERR_PEER_CLOSED);
  309. });
  310. fuchsia::web::FramePtr frame;
  311. (*context)->CreateFrame(frame.NewRequest());
  312. // The error handler should be called here.
  313. run_loop.Run();
  314. }
  315. protected:
  316. base::test::SingleThreadTaskEnvironment task_environment_{
  317. base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
  318. // fuchsia.sys.Launcher member must be constructed before the test component
  319. // context replaces the process' component context.
  320. fuchsia::sys::LauncherPtr sys_launcher_;
  321. // Used to replace the process component context with one providing a fake
  322. // fuchsia.sys.Environment, through which a nested Environment and fake
  323. // Launcher are obtained.
  324. base::TestComponentContextForProcess test_component_context_;
  325. FakeSysEnvironment fake_environment_;
  326. std::unique_ptr<ContextProviderImpl> provider_;
  327. fuchsia::web::ContextProviderPtr provider_ptr_;
  328. fidl::BindingSet<fuchsia::web::ContextProvider> bindings_;
  329. private:
  330. struct CapturingNavigationStateObserver
  331. : public fuchsia::web::NavigationEventListener {
  332. public:
  333. explicit CapturingNavigationStateObserver(base::OnceClosure on_change_cb)
  334. : on_change_cb_(std::move(on_change_cb)) {}
  335. ~CapturingNavigationStateObserver() override = default;
  336. void OnNavigationStateChanged(
  337. fuchsia::web::NavigationState change,
  338. OnNavigationStateChangedCallback callback) override {
  339. captured_state_ = std::move(change);
  340. std::move(on_change_cb_).Run();
  341. }
  342. fuchsia::web::NavigationState* captured_state() { return &captured_state_; }
  343. private:
  344. base::OnceClosure on_change_cb_;
  345. fuchsia::web::NavigationState captured_state_;
  346. };
  347. };
  348. TEST_F(ContextProviderImplTest, CanCreateContext) {
  349. // Connect to a new context process.
  350. fidl::InterfacePtr<fuchsia::web::Context> context;
  351. fuchsia::web::CreateContextParams create_params = BuildCreateContextParams();
  352. provider_ptr_->Create(std::move(create_params), context.NewRequest());
  353. CheckContextResponsive(&context);
  354. }
  355. TEST_F(ContextProviderImplTest, CreateValidatesServiceDirectory) {
  356. // Attempt to create a Context without specifying a service directory.
  357. fidl::InterfacePtr<fuchsia::web::Context> context;
  358. fuchsia::web::CreateContextParams create_params;
  359. provider_ptr_->Create(std::move(create_params), context.NewRequest());
  360. base::RunLoop run_loop;
  361. context.set_error_handler(
  362. [quit_loop = run_loop.QuitClosure()](zx_status_t status) {
  363. quit_loop.Run();
  364. EXPECT_EQ(status, ZX_ERR_INVALID_ARGS);
  365. });
  366. run_loop.Run();
  367. }
  368. TEST_F(ContextProviderImplTest, CreateValidatesDataDirectory) {
  369. // Deliberately supply the wrong kind of object as the data-directory.
  370. fidl::InterfacePtr<fuchsia::web::Context> context;
  371. fuchsia::web::CreateContextParams create_params = BuildCreateContextParams();
  372. zx::socket socket1, socket2;
  373. ASSERT_EQ(zx::socket::create(0, &socket1, &socket2), ZX_OK);
  374. create_params.set_data_directory(
  375. fidl::InterfaceHandle<fuchsia::io::Directory>(
  376. zx::channel(socket1.release())));
  377. provider_ptr_->Create(std::move(create_params), context.NewRequest());
  378. base::RunLoop run_loop;
  379. context.set_error_handler(
  380. [quit_loop = run_loop.QuitClosure()](zx_status_t status) {
  381. quit_loop.Run();
  382. EXPECT_TRUE(status == ZX_ERR_PEER_CLOSED);
  383. });
  384. run_loop.Run();
  385. }
  386. TEST_F(ContextProviderImplTest, CreateValidatesDrmFlags) {
  387. {
  388. // Request Widevine DRM but do not enable VULKAN.
  389. fidl::InterfacePtr<fuchsia::web::Context> context;
  390. fuchsia::web::CreateContextParams create_params =
  391. BuildCreateContextParams();
  392. *create_params.mutable_features() =
  393. fuchsia::web::ContextFeatureFlags::WIDEVINE_CDM;
  394. *create_params.mutable_cdm_data_directory() = OpenCacheDirectory();
  395. provider_ptr_->Create(std::move(create_params), context.NewRequest());
  396. base::RunLoop run_loop;
  397. context.set_error_handler(
  398. [quit_loop = run_loop.QuitClosure()](zx_status_t status) {
  399. quit_loop.Run();
  400. EXPECT_EQ(status, ZX_ERR_NOT_SUPPORTED);
  401. });
  402. run_loop.Run();
  403. }
  404. {
  405. // Request PlayReady DRM but do not enable VULKAN.
  406. fidl::InterfacePtr<fuchsia::web::Context> context;
  407. fuchsia::web::CreateContextParams create_params =
  408. BuildCreateContextParams();
  409. create_params.set_playready_key_system("foo");
  410. *create_params.mutable_cdm_data_directory() = OpenCacheDirectory();
  411. provider_ptr_->Create(std::move(create_params), context.NewRequest());
  412. base::RunLoop run_loop;
  413. context.set_error_handler(
  414. [quit_loop = run_loop.QuitClosure()](zx_status_t status) {
  415. quit_loop.Run();
  416. EXPECT_EQ(status, ZX_ERR_NOT_SUPPORTED);
  417. });
  418. run_loop.Run();
  419. }
  420. {
  421. // Requesting DRM without VULKAN is acceptable for HEADLESS Contexts.
  422. fidl::InterfacePtr<fuchsia::web::Context> context;
  423. fuchsia::web::CreateContextParams create_params =
  424. BuildCreateContextParams();
  425. *create_params.mutable_features() =
  426. fuchsia::web::ContextFeatureFlags::WIDEVINE_CDM |
  427. fuchsia::web::ContextFeatureFlags::HEADLESS;
  428. *create_params.mutable_cdm_data_directory() = OpenCacheDirectory();
  429. provider_ptr_->Create(std::move(create_params), context.NewRequest());
  430. base::RunLoop run_loop;
  431. context.set_error_handler(
  432. [quit_loop = run_loop.QuitClosure()](zx_status_t status) {
  433. quit_loop.Run();
  434. ZX_LOG(ERROR, status);
  435. ADD_FAILURE();
  436. });
  437. // Spin the loop to allow CreateContext() to be handled, and the |context|
  438. // channel to be disconnected, in case of failure.
  439. run_loop.RunUntilIdle();
  440. }
  441. }
  442. TEST_F(ContextProviderImplTest, MultipleConcurrentClients) {
  443. // Bind a Provider connection, and create a Context from it.
  444. fuchsia::web::ContextProviderPtr provider_1_ptr;
  445. bindings_.AddBinding(provider_.get(), provider_1_ptr.NewRequest());
  446. fuchsia::web::ContextPtr context_1;
  447. provider_1_ptr->Create(BuildCreateContextParams(), context_1.NewRequest());
  448. // Do the same on another Provider connection.
  449. fuchsia::web::ContextProviderPtr provider_2_ptr;
  450. bindings_.AddBinding(provider_.get(), provider_2_ptr.NewRequest());
  451. fuchsia::web::ContextPtr context_2;
  452. provider_2_ptr->Create(BuildCreateContextParams(), context_2.NewRequest());
  453. CheckContextResponsive(&context_1);
  454. CheckContextResponsive(&context_2);
  455. // Ensure that the initial ContextProvider connection is still usable, by
  456. // creating and verifying another Context from it.
  457. fuchsia::web::ContextPtr context_3;
  458. provider_2_ptr->Create(BuildCreateContextParams(), context_3.NewRequest());
  459. CheckContextResponsive(&context_3);
  460. }
  461. TEST_F(ContextProviderImplTest, WithProfileDir) {
  462. base::ScopedTempDir profile_temp_dir;
  463. // Connect to a new context process.
  464. fidl::InterfacePtr<fuchsia::web::Context> context;
  465. fuchsia::web::CreateContextParams create_params = BuildCreateContextParams();
  466. // Setup data dir.
  467. ASSERT_TRUE(profile_temp_dir.CreateUniqueTempDir());
  468. ASSERT_EQ(
  469. base::WriteFile(profile_temp_dir.GetPath().AppendASCII(kTestDataFileIn),
  470. nullptr, 0),
  471. 0);
  472. // Pass a handle data dir to the context.
  473. create_params.set_data_directory(
  474. base::OpenDirectoryHandle(profile_temp_dir.GetPath()));
  475. provider_ptr_->Create(std::move(create_params), context.NewRequest());
  476. CheckContextResponsive(&context);
  477. // Verify that the context process can write to the data dir.
  478. EXPECT_TRUE(base::PathExists(
  479. profile_temp_dir.GetPath().AppendASCII(kTestDataFileOut)));
  480. }
  481. TEST_F(ContextProviderImplTest, FailsDataDirectoryIsFile) {
  482. base::FilePath temp_file_path;
  483. // Connect to a new context process.
  484. fidl::InterfacePtr<fuchsia::web::Context> context;
  485. fuchsia::web::CreateContextParams create_params = BuildCreateContextParams();
  486. // Pass in a handle to a file instead of a directory.
  487. CHECK(base::CreateTemporaryFile(&temp_file_path));
  488. create_params.set_data_directory(base::OpenDirectoryHandle(temp_file_path));
  489. provider_ptr_->Create(std::move(create_params), context.NewRequest());
  490. CheckContextUnresponsive(&context);
  491. }
  492. // Tests that unsafely_treat_insecure_origins_as_secure properly adds the right
  493. // command-line arguments to the Context process.
  494. TEST_F(ContextProviderImplTest, WithInsecureOriginsAsSecure) {
  495. base::RunLoop loop;
  496. fake_environment_.fake_launcher().set_create_component_callback(
  497. base::BindLambdaForTesting([&loop](const base::CommandLine& command) {
  498. loop.Quit();
  499. EXPECT_TRUE(command.HasSwitch(switches::kAllowRunningInsecureContent));
  500. EXPECT_THAT(command.GetSwitchValueASCII(switches::kDisableFeatures),
  501. testing::HasSubstr("AutoupgradeMixedContent"));
  502. EXPECT_EQ(command.GetSwitchValueASCII(
  503. network::switches::kUnsafelyTreatInsecureOriginAsSecure),
  504. "http://example.com");
  505. }));
  506. fuchsia::web::ContextPtr context;
  507. context.set_error_handler([&loop](zx_status_t status) {
  508. loop.Quit();
  509. ZX_LOG(ERROR, status);
  510. ADD_FAILURE();
  511. });
  512. fuchsia::web::CreateContextParams create_params = BuildCreateContextParams();
  513. std::vector<std::string> insecure_origins;
  514. insecure_origins.push_back(switches::kAllowRunningInsecureContent);
  515. insecure_origins.push_back("disable-mixed-content-autoupgrade");
  516. insecure_origins.push_back("http://example.com");
  517. create_params.set_unsafely_treat_insecure_origins_as_secure(
  518. std::move(insecure_origins));
  519. provider_ptr_->Create(std::move(create_params), context.NewRequest());
  520. loop.Run();
  521. }
  522. TEST_F(ContextProviderImplTest, WithDataQuotaBytes) {
  523. base::RunLoop loop;
  524. fake_environment_.fake_launcher().set_create_component_callback(
  525. base::BindLambdaForTesting([&loop](const base::CommandLine& command) {
  526. loop.Quit();
  527. EXPECT_EQ(command.GetSwitchValueASCII("data-quota-bytes"),
  528. kTestQuotaBytesSwitchValue);
  529. }));
  530. fuchsia::web::ContextPtr context;
  531. context.set_error_handler([&loop](zx_status_t status) {
  532. loop.Quit();
  533. ZX_LOG(ERROR, status);
  534. ADD_FAILURE();
  535. });
  536. fuchsia::web::CreateContextParams create_params = BuildCreateContextParams();
  537. base::ScopedTempDir profile_temp_dir;
  538. ASSERT_TRUE(profile_temp_dir.CreateUniqueTempDir());
  539. create_params.set_data_directory(
  540. base::OpenDirectoryHandle(profile_temp_dir.GetPath()));
  541. create_params.set_data_quota_bytes(kTestQuotaBytes);
  542. provider_ptr_->Create(std::move(create_params), context.NewRequest());
  543. loop.Run();
  544. }
  545. // TODO(crbug.com/1013412): This test doesn't actually exercise DRM, so could
  546. // be executed everywhere if DRM support were configurable.
  547. #if defined(ARCH_CPU_ARM64)
  548. TEST_F(ContextProviderImplTest, WithCdmDataQuotaBytes) {
  549. base::RunLoop loop;
  550. fake_environment_.fake_launcher().set_create_component_callback(
  551. base::BindLambdaForTesting([&loop](const base::CommandLine& command) {
  552. loop.Quit();
  553. EXPECT_EQ(command.GetSwitchValueASCII("cdm-data-quota-bytes"),
  554. kTestQuotaBytesSwitchValue);
  555. }));
  556. fuchsia::web::ContextPtr context;
  557. context.set_error_handler([&loop](zx_status_t status) {
  558. loop.Quit();
  559. ZX_LOG(ERROR, status);
  560. ADD_FAILURE();
  561. });
  562. fuchsia::web::CreateContextParams create_params = BuildCreateContextParams();
  563. base::ScopedTempDir profile_temp_dir;
  564. ASSERT_TRUE(profile_temp_dir.CreateUniqueTempDir());
  565. create_params.set_cdm_data_directory(
  566. base::OpenDirectoryHandle(profile_temp_dir.GetPath()));
  567. create_params.set_features(fuchsia::web::ContextFeatureFlags::HEADLESS |
  568. fuchsia::web::ContextFeatureFlags::WIDEVINE_CDM);
  569. create_params.set_cdm_data_quota_bytes(kTestQuotaBytes);
  570. provider_ptr_->Create(std::move(create_params), context.NewRequest());
  571. loop.Run();
  572. }
  573. #endif // defined(ARCH_CPU_ARM64)