web_engine_integration_test.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. // Copyright 2019 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/mediacodec/cpp/fidl.h>
  5. #include <fuchsia/mem/cpp/fidl.h>
  6. #include <lib/zx/vmo.h>
  7. #include <zircon/rights.h>
  8. #include <zircon/types.h>
  9. #include <string>
  10. #include "base/fuchsia/fuchsia_logging.h"
  11. #include "base/fuchsia/mem_buffer_util.h"
  12. #include "base/fuchsia/process_context.h"
  13. #include "base/strings/stringprintf.h"
  14. #include "base/test/test_future.h"
  15. #include "build/build_config.h"
  16. #include "components/version_info/version_info.h"
  17. #include "fuchsia_web/common/test/fit_adapter.h"
  18. #include "fuchsia_web/common/test/frame_test_util.h"
  19. #include "fuchsia_web/common/test/test_devtools_list_fetcher.h"
  20. #include "fuchsia_web/webengine/web_engine_integration_test_base.h"
  21. #include "media/base/media_switches.h"
  22. #include "media/fuchsia/audio/fake_audio_consumer.h"
  23. #include "media/fuchsia/audio/fake_audio_device_enumerator.h"
  24. #include "media/fuchsia/camera/fake_fuchsia_camera.h"
  25. #include "net/http/http_request_headers.h"
  26. #include "testing/gmock/include/gmock/gmock.h"
  27. namespace {
  28. constexpr char kValidUserAgentProduct[] = "TestProduct";
  29. constexpr char kValidUserAgentVersion[] = "dev.12345";
  30. constexpr char kValidUserAgentProductAndVersion[] = "TestProduct/dev.12345";
  31. constexpr char kInvalidUserAgentProduct[] = "Test/Product";
  32. constexpr char kInvalidUserAgentVersion[] = "dev/12345";
  33. constexpr char kAutoplayVp9OpusUrl[] =
  34. "fuchsia-dir://testdata/play_video.html?codecs=vp9,opus&autoplay=1";
  35. constexpr char kAutoplayVp9OpusToEndUrl[] =
  36. "fuchsia-dir://testdata/"
  37. "play_video.html?codecs=vp9,opus&autoplay=1&reportended=1";
  38. constexpr char kLoadVp9OpusUrl[] =
  39. "fuchsia-dir://testdata/play_video.html?codecs=vp9,opus";
  40. } // namespace
  41. // Starts a WebEngine instance before running the test.
  42. class WebEngineIntegrationTest : public WebEngineIntegrationTestBase {
  43. protected:
  44. WebEngineIntegrationTest() = default;
  45. void SetUp() override {
  46. WebEngineIntegrationTestBase::SetUp();
  47. StartWebEngine(base::CommandLine(base::CommandLine::NO_PROGRAM));
  48. }
  49. void RunPermissionTest(bool grant);
  50. };
  51. class WebEngineIntegrationUserAgentTest : public WebEngineIntegrationTest {
  52. protected:
  53. GURL GetEchoUserAgentUrl() {
  54. static std::string echo_user_agent_header_path =
  55. std::string("/echoheader?") + net::HttpRequestHeaders::kUserAgent;
  56. return embedded_test_server_.GetURL(echo_user_agent_header_path);
  57. }
  58. // Returns the expected user agent string for the current Chrome version.
  59. static std::string GetExpectedUserAgentString() {
  60. // The default (base) user agent string without any client modifications.
  61. // Due to reduced user agent, only the major version is populated, the
  62. // version number is <majorVersion>.0.0.0.
  63. constexpr char kDefaultUserAgentStringWithVersionPlaceholder[] =
  64. "Mozilla/5.0 (Fuchsia) AppleWebKit/537.36 (KHTML, like Gecko) "
  65. "Chrome/%d.0.0.0 Safari/537.36";
  66. std::string expected_ua =
  67. base::StringPrintf(kDefaultUserAgentStringWithVersionPlaceholder,
  68. version_info::GetMajorVersionNumberAsInt());
  69. // Ensure the field was actually populated.
  70. EXPECT_NE(expected_ua.find(version_info::GetMajorVersionNumber()),
  71. std::string::npos);
  72. return expected_ua;
  73. }
  74. static std::string GetExpectedUserAgentStringWithProduct(
  75. const char* product) {
  76. return base::StringPrintf("%s %s", GetExpectedUserAgentString().c_str(),
  77. product);
  78. }
  79. };
  80. // Although this does not need to be an integration test, all other user agent
  81. // tests are here.
  82. TEST_F(WebEngineIntegrationUserAgentTest, Default) {
  83. // Create a Context with no values specified.
  84. fuchsia::web::CreateContextParams create_params = TestContextParams();
  85. CreateContextAndFrameAndLoadUrl(std::move(create_params),
  86. GetEchoUserAgentUrl());
  87. // Query & verify that the header echoed into the document body is as
  88. // expected.
  89. std::string result =
  90. ExecuteJavaScriptWithStringResult("document.body.innerText;");
  91. EXPECT_EQ(result, GetExpectedUserAgentString());
  92. // Query & verify that the navigator.userAgent is as expected.
  93. result = ExecuteJavaScriptWithStringResult("navigator.userAgent;");
  94. EXPECT_EQ(result, GetExpectedUserAgentString());
  95. }
  96. TEST_F(WebEngineIntegrationUserAgentTest, ValidProductOnly) {
  97. // Create a Context with just an embedder product specified.
  98. fuchsia::web::CreateContextParams create_params = TestContextParams();
  99. create_params.set_user_agent_product(kValidUserAgentProduct);
  100. CreateContextAndFrameAndLoadUrl(std::move(create_params),
  101. GetEchoUserAgentUrl());
  102. std::string expected =
  103. GetExpectedUserAgentStringWithProduct(kValidUserAgentProduct);
  104. // Query & verify that the header echoed into the document body contains
  105. // the product tag.
  106. std::string result =
  107. ExecuteJavaScriptWithStringResult("document.body.innerText;");
  108. EXPECT_TRUE(result.find(kValidUserAgentProduct) != std::string::npos);
  109. EXPECT_EQ(result, expected);
  110. // Query & verify that the navigator.userAgent contains the product tag.
  111. result = ExecuteJavaScriptWithStringResult("navigator.userAgent;");
  112. EXPECT_TRUE(result.find(kValidUserAgentProduct) != std::string::npos);
  113. EXPECT_EQ(result, expected);
  114. }
  115. TEST_F(WebEngineIntegrationUserAgentTest, ValidProductAndVersion) {
  116. // Create a Context with both product and version specified.
  117. fuchsia::web::CreateContextParams create_params = TestContextParams();
  118. create_params.set_user_agent_product(kValidUserAgentProduct);
  119. create_params.set_user_agent_version(kValidUserAgentVersion);
  120. CreateContextAndFrameAndLoadUrl(std::move(create_params),
  121. GetEchoUserAgentUrl());
  122. std::string expected =
  123. GetExpectedUserAgentStringWithProduct(kValidUserAgentProductAndVersion);
  124. // Query & verify that the header echoed into the document body contains
  125. // both product & version.
  126. std::string result =
  127. ExecuteJavaScriptWithStringResult("document.body.innerText;");
  128. EXPECT_TRUE(result.find(kValidUserAgentProductAndVersion) !=
  129. std::string::npos);
  130. EXPECT_EQ(result, expected);
  131. // Query & verify that the navigator.userAgent contains product & version.
  132. result = ExecuteJavaScriptWithStringResult("navigator.userAgent;");
  133. EXPECT_TRUE(result.find(kValidUserAgentProductAndVersion) !=
  134. std::string::npos);
  135. EXPECT_EQ(result, expected);
  136. // Verify navigator.platform is empty, see crbug.com/1348646.
  137. EXPECT_EQ(ExecuteJavaScriptWithStringResult("navigator.platform;"), "");
  138. }
  139. TEST_F(WebEngineIntegrationUserAgentTest, InvalidProduct) {
  140. // Try to create a Context with an invalid embedder product tag.
  141. fuchsia::web::CreateContextParams create_params = TestContextParams();
  142. create_params.set_user_agent_product(kInvalidUserAgentProduct);
  143. CreateContextAndExpectError(std::move(create_params), ZX_ERR_INVALID_ARGS);
  144. }
  145. TEST_F(WebEngineIntegrationUserAgentTest, VersionOnly) {
  146. // Try to create a Context with an embedder version but no product.
  147. fuchsia::web::CreateContextParams create_params = TestContextParams();
  148. create_params.set_user_agent_version(kValidUserAgentVersion);
  149. CreateContextAndExpectError(std::move(create_params), ZX_ERR_INVALID_ARGS);
  150. }
  151. TEST_F(WebEngineIntegrationUserAgentTest, ValidProductAndInvalidVersion) {
  152. // Try to create a Context with valid product tag, but invalid version.
  153. fuchsia::web::CreateContextParams create_params = TestContextParams();
  154. create_params.set_user_agent_product(kValidUserAgentProduct);
  155. create_params.set_user_agent_version(kInvalidUserAgentVersion);
  156. CreateContextAndExpectError(std::move(create_params), ZX_ERR_INVALID_ARGS);
  157. }
  158. TEST_F(WebEngineIntegrationTest, CreateFrameWithUnclonableFrameParamsFails) {
  159. CreateContext(TestContextParams());
  160. zx_rights_t kReadRightsWithoutDuplicate =
  161. ZX_RIGHT_TRANSFER | ZX_RIGHT_READ | ZX_RIGHT_MAP | ZX_RIGHT_GET_PROPERTY;
  162. // Create a buffer and remove the ability clone it by changing its rights to
  163. // not include ZX_RIGHT_DUPLICATE.
  164. auto buffer = base::MemBufferFromString("some data", "some name");
  165. zx::vmo unclonable_readonly_vmo;
  166. EXPECT_EQ(ZX_OK, buffer.vmo.duplicate(kReadRightsWithoutDuplicate,
  167. &unclonable_readonly_vmo));
  168. buffer.vmo = std::move(unclonable_readonly_vmo);
  169. // Creation will fail, which will be reported in the error handler below.
  170. fuchsia::web::CreateFrameParams create_frame_params;
  171. create_frame_params.set_explicit_sites_filter_error_page(
  172. fuchsia::mem::Data::WithBuffer(std::move(buffer)));
  173. context_->CreateFrameWithParams(std::move(create_frame_params),
  174. frame_.NewRequest());
  175. base::RunLoop loop;
  176. frame_.set_error_handler(
  177. [quit_loop = loop.QuitClosure()](zx_status_t status) {
  178. EXPECT_EQ(status, ZX_ERR_INVALID_ARGS);
  179. quit_loop.Run();
  180. });
  181. loop.Run();
  182. EXPECT_FALSE(frame_);
  183. }
  184. // Check that if the CreateContextParams has |remote_debugging_port| set then:
  185. // - DevTools becomes available when the first debuggable Frame is created.
  186. // - DevTools closes when the last debuggable Frame is closed.
  187. TEST_F(WebEngineIntegrationTest, RemoteDebuggingPort) {
  188. // Create a Context with remote debugging enabled via an ephemeral port.
  189. fuchsia::web::CreateContextParams create_params = TestContextParams();
  190. create_params.set_remote_debugging_port(0);
  191. // Create a Frame with remote debugging enabled.
  192. fuchsia::web::CreateFrameParams create_frame_params;
  193. create_frame_params.set_enable_remote_debugging(true);
  194. CreateContext(std::move(create_params));
  195. CreateFrameWithParams(std::move(create_frame_params));
  196. // Expect to receive a notification of the selected DevTools port.
  197. base::test::TestFuture<fuchsia::web::Context_GetRemoteDebuggingPort_Result>
  198. port_receiver;
  199. context_->GetRemoteDebuggingPort(
  200. CallbackToFitFunction(port_receiver.GetCallback()));
  201. ASSERT_TRUE(port_receiver.Wait());
  202. ASSERT_TRUE(port_receiver.Get().is_response());
  203. uint16_t remote_debugging_port = port_receiver.Get().response().port;
  204. ASSERT_TRUE(remote_debugging_port != 0);
  205. // Navigate to a URL.
  206. GURL url = embedded_test_server_.GetURL("/defaultresponse");
  207. ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse(url.spec()));
  208. navigation_listener()->RunUntilUrlEquals(url);
  209. base::Value devtools_list = GetDevToolsListFromPort(remote_debugging_port);
  210. ASSERT_TRUE(devtools_list.is_list());
  211. EXPECT_EQ(devtools_list.GetListDeprecated().size(), 1u);
  212. base::Value* devtools_url =
  213. devtools_list.GetListDeprecated()[0].FindPath("url");
  214. ASSERT_TRUE(devtools_url->is_string());
  215. EXPECT_EQ(devtools_url->GetString(), url);
  216. // Create a second frame, without remote debugging enabled. The remote
  217. // debugging service should still report a single Frame is present.
  218. fuchsia::web::FramePtr web_frame2;
  219. web_frame2.set_error_handler([](zx_status_t) { ADD_FAILURE(); });
  220. context()->CreateFrame(web_frame2.NewRequest());
  221. devtools_list = GetDevToolsListFromPort(remote_debugging_port);
  222. ASSERT_TRUE(devtools_list.is_list());
  223. EXPECT_EQ(devtools_list.GetListDeprecated().size(), 1u);
  224. devtools_url = devtools_list.GetListDeprecated()[0].FindPath("url");
  225. ASSERT_TRUE(devtools_url->is_string());
  226. EXPECT_EQ(devtools_url->GetString(), url);
  227. // Tear down the debuggable Frame. The remote debugging service should have
  228. // shut down.
  229. base::RunLoop controller_run_loop;
  230. auto navigation_controller = CreateNavigationController();
  231. navigation_controller.set_error_handler(
  232. [&controller_run_loop](zx_status_t) { controller_run_loop.Quit(); });
  233. frame_.Unbind();
  234. // Wait until the NavigationController shuts down to ensure WebEngine has
  235. // handled the Frame tear down.
  236. controller_run_loop.Run();
  237. devtools_list = GetDevToolsListFromPort(remote_debugging_port);
  238. EXPECT_TRUE(devtools_list.is_none());
  239. }
  240. // Check that remote debugging requests for Frames in non-debuggable Contexts
  241. // cause an error to be reported.
  242. TEST_F(WebEngineIntegrationTest, RequestDebuggableFrameInNonDebuggableContext) {
  243. fuchsia::web::CreateFrameParams create_frame_params;
  244. create_frame_params.set_enable_remote_debugging(true);
  245. CreateContext(TestContextParams());
  246. CreateFrameWithParams(std::move(create_frame_params));
  247. base::RunLoop loop;
  248. frame_.set_error_handler(
  249. [quit_loop = loop.QuitClosure()](zx_status_t status) {
  250. EXPECT_EQ(status, ZX_ERR_INVALID_ARGS);
  251. quit_loop.Run();
  252. });
  253. loop.Run();
  254. }
  255. // Navigates to a resource served under the "testdata" ContentDirectory.
  256. TEST_F(WebEngineIntegrationTest, ContentDirectoryProvider) {
  257. const GURL kUrl("fuchsia-dir://testdata/title1.html");
  258. constexpr char kTitle[] = "title 1";
  259. CreateContextAndFrame(TestContextParamsWithTestData());
  260. // Navigate to test1.html and verify that the resource was correctly
  261. // downloaded and interpreted by inspecting the document title.
  262. ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse(kUrl.spec()));
  263. navigation_listener()->RunUntilUrlAndTitleEquals(kUrl, kTitle);
  264. }
  265. // Configures the default filtered service directory with a fake AudioConsumer
  266. // service for testing.
  267. class WebEngineIntegrationMediaTest : public WebEngineIntegrationTest {
  268. protected:
  269. WebEngineIntegrationMediaTest()
  270. : fake_audio_consumer_service_(filtered_service_directory()
  271. .outgoing_directory()
  272. ->GetOrCreateDirectory("svc")) {
  273. auto* outgoing_directory =
  274. filtered_service_directory().outgoing_directory();
  275. // Publish fake AudioDeviceEnumerator.
  276. outgoing_directory
  277. ->RemovePublicService<fuchsia::media::AudioDeviceEnumerator>();
  278. fake_audio_device_enumerator_.emplace(
  279. outgoing_directory->GetOrCreateDirectory("svc"));
  280. // Intercept `fuchsia::media::Audio` connections in order to count them.
  281. outgoing_directory->RemovePublicService<fuchsia::media::Audio>();
  282. zx_status_t status = outgoing_directory->AddPublicService(
  283. fidl::InterfaceRequestHandler<fuchsia::media::Audio>(
  284. [this](auto request) {
  285. ++num_audio_connections_;
  286. base::ComponentContextForProcess()->svc()->Connect(
  287. std::move(request));
  288. }));
  289. ZX_CHECK(status == ZX_OK, status) << "AddPublicService";
  290. }
  291. // Returns a CreateContextParams that has AUDIO feature, and the "testdata"
  292. // content directory provider configured.
  293. fuchsia::web::CreateContextParams ContextParamsWithAudioAndTestData() {
  294. fuchsia::web::CreateContextParams create_params =
  295. TestContextParamsWithTestData();
  296. *create_params.mutable_features() |=
  297. fuchsia::web::ContextFeatureFlags::AUDIO;
  298. return create_params;
  299. }
  300. media::FakeAudioConsumerService fake_audio_consumer_service_;
  301. absl::optional<media::FakeAudioDeviceEnumerator>
  302. fake_audio_device_enumerator_;
  303. size_t num_audio_connections_ = 0;
  304. };
  305. TEST_F(WebEngineIntegrationMediaTest, PlayAudioToAudioRenderer) {
  306. CreateContextAndFrame(ContextParamsWithAudioAndTestData());
  307. ASSERT_NO_FATAL_FAILURE(
  308. LoadUrlAndExpectResponse("fuchsia-dir://testdata/play_audio.html",
  309. CreateLoadUrlParamsWithUserActivation()));
  310. navigation_listener()->RunUntilTitleEquals("ended");
  311. EXPECT_EQ(num_audio_connections_, 1U);
  312. EXPECT_EQ(fake_audio_consumer_service_.num_instances(), 0U);
  313. }
  314. TEST_F(WebEngineIntegrationMediaTest, PlayAudioToAudioConsumer) {
  315. CreateContextAndFrame(ContextParamsWithAudioAndTestData());
  316. // Send `FrameMediaSettings` with `audio_consumer_session_id`. This enables
  317. // `AudioConsumer`.
  318. static const uint16_t kTestMediaSessionId = 43;
  319. fuchsia::web::FrameMediaSettings media_settings;
  320. media_settings.set_audio_consumer_session_id(kTestMediaSessionId);
  321. frame_->SetMediaSettings(std::move(media_settings));
  322. ASSERT_NO_FATAL_FAILURE(
  323. LoadUrlAndExpectResponse("fuchsia-dir://testdata/play_audio.html",
  324. CreateLoadUrlParamsWithUserActivation()));
  325. navigation_listener()->RunUntilTitleEquals("ended");
  326. EXPECT_EQ(num_audio_connections_, 0U);
  327. ASSERT_EQ(fake_audio_consumer_service_.num_instances(), 1U);
  328. auto pos = fake_audio_consumer_service_.instance(0)->GetMediaPosition();
  329. EXPECT_GT(pos, base::Seconds(2.0));
  330. EXPECT_LT(pos, base::Seconds(2.5));
  331. EXPECT_EQ(fake_audio_consumer_service_.instance(0)->session_id(),
  332. kTestMediaSessionId);
  333. EXPECT_EQ(fake_audio_consumer_service_.instance(0)->volume(), 1.0);
  334. EXPECT_FALSE(fake_audio_consumer_service_.instance(0)->is_muted());
  335. }
  336. // Check that audio cannot play when the AUDIO ContextFeatureFlag is not
  337. // provided.
  338. TEST_F(WebEngineIntegrationMediaTest, PlayAudio_NoFlag) {
  339. // Both FilteredServiceDirectory and test data are needed.
  340. fuchsia::web::CreateContextParams create_params =
  341. TestContextParamsWithTestData();
  342. CreateContextAndFrame(std::move(create_params));
  343. ASSERT_NO_FATAL_FAILURE(
  344. LoadUrlAndExpectResponse("fuchsia-dir://testdata/play_audio.html",
  345. CreateLoadUrlParamsWithUserActivation()));
  346. // The file is still expected to play to the end.
  347. navigation_listener()->RunUntilTitleEquals("ended");
  348. EXPECT_EQ(fake_audio_consumer_service_.num_instances(), 0U);
  349. EXPECT_EQ(num_audio_connections_, 0U);
  350. }
  351. TEST_F(WebEngineIntegrationMediaTest, PlayVideo) {
  352. CreateContextAndFrame(ContextParamsWithAudioAndTestData());
  353. ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse(
  354. kAutoplayVp9OpusToEndUrl, CreateLoadUrlParamsWithUserActivation()));
  355. navigation_listener()->RunUntilTitleEquals("ended");
  356. // Audio should be sent to AudioRenderer (created though `fuchsia.web.Audio`).
  357. EXPECT_EQ(num_audio_connections_, 1U);
  358. EXPECT_EQ(fake_audio_consumer_service_.num_instances(), 0U);
  359. }
  360. void WebEngineIntegrationTest::RunPermissionTest(bool grant) {
  361. CreateContextAndFrame(TestContextParamsWithTestData());
  362. if (grant) {
  363. GrantPermission(fuchsia::web::PermissionType::MICROPHONE,
  364. "fuchsia-dir://testdata/");
  365. }
  366. ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse(
  367. "fuchsia-dir://testdata/check_mic_permission.html"));
  368. navigation_listener()->RunUntilTitleEquals(grant ? "granted" : "denied");
  369. }
  370. TEST_F(WebEngineIntegrationTest, PermissionDenied) {
  371. RunPermissionTest(false);
  372. }
  373. TEST_F(WebEngineIntegrationTest, PermissionGranted) {
  374. RunPermissionTest(true);
  375. }
  376. // TODO(crbug.com/1299352): Flaky.
  377. TEST_F(WebEngineIntegrationMediaTest,
  378. DISABLED_MicrophoneAccess_WithPermission) {
  379. CreateContextAndFrame(ContextParamsWithAudioAndTestData());
  380. GrantPermission(
  381. fuchsia::web::PermissionType::MICROPHONE,
  382. embedded_test_server_.GetURL("/").DeprecatedGetOriginAsURL().spec());
  383. ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse(
  384. embedded_test_server_.GetURL("/mic.html").spec()));
  385. navigation_listener()->RunUntilTitleEquals("ended");
  386. }
  387. TEST_F(WebEngineIntegrationMediaTest, MicrophoneAccess_WithoutPermission) {
  388. CreateContextAndFrame(ContextParamsWithAudioAndTestData());
  389. ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse(
  390. embedded_test_server_.GetURL("/mic.html?NoPermission").spec()));
  391. navigation_listener()->RunUntilTitleEquals("ended-NotFoundError");
  392. }
  393. TEST_F(WebEngineIntegrationMediaTest, SetBlockMediaLoading_Blocked) {
  394. CreateContextAndFrame(ContextParamsWithAudioAndTestData());
  395. frame_->SetBlockMediaLoading(true);
  396. ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse(
  397. kAutoplayVp9OpusUrl, CreateLoadUrlParamsWithUserActivation()));
  398. // Check different indicators that media has not loaded and is not playing.
  399. navigation_listener()->RunUntilTitleEquals("stalled");
  400. EXPECT_EQ(0 /*HAVE_NOTHING*/,
  401. ExecuteJavaScriptWithDoubleResult("bear.readyState"));
  402. EXPECT_EQ(0.0, ExecuteJavaScriptWithDoubleResult("bear.currentTime"));
  403. EXPECT_FALSE(ExecuteJavaScriptWithBoolResult("isMetadataLoaded"));
  404. }
  405. // Initially, set media blocking to be true. When media is unblocked, check that
  406. // it begins playing, since autoplay=true.
  407. TEST_F(WebEngineIntegrationMediaTest, SetBlockMediaLoading_AfterUnblock) {
  408. CreateContextAndFrame(ContextParamsWithAudioAndTestData());
  409. frame_->SetBlockMediaLoading(true);
  410. ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse(
  411. kAutoplayVp9OpusUrl, CreateLoadUrlParamsWithUserActivation()));
  412. // Check that media loading has been blocked.
  413. navigation_listener()->RunUntilTitleEquals("stalled");
  414. // Unblock media from loading and see if media loads and plays, since
  415. // autoplay=true.
  416. frame_->SetBlockMediaLoading(false);
  417. navigation_listener()->RunUntilTitleEquals("playing");
  418. EXPECT_TRUE(ExecuteJavaScriptWithBoolResult("isMetadataLoaded"));
  419. }
  420. // Check that when autoplay=false and media loading was blocked after the
  421. // element has started loading that media will play when play() is called.
  422. TEST_F(WebEngineIntegrationMediaTest,
  423. SetBlockMediaLoading_SetBlockedAfterLoading) {
  424. CreateContextAndFrame(ContextParamsWithAudioAndTestData());
  425. ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse(
  426. kLoadVp9OpusUrl, CreateLoadUrlParamsWithUserActivation()));
  427. navigation_listener()->RunUntilTitleEquals("loaded");
  428. frame_->SetBlockMediaLoading(true);
  429. ExecuteJavaScript(frame_.get(), "bear.play()");
  430. navigation_listener()->RunUntilTitleEquals("playing");
  431. }
  432. TEST_F(WebEngineIntegrationTest, WebGLContextAbsentWithoutVulkanFeature) {
  433. CreateContextAndFrame(TestContextParams());
  434. ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse(
  435. embedded_test_server_.GetURL("/webgl_presence.html").spec()));
  436. navigation_listener()->RunUntilLoaded();
  437. EXPECT_EQ(navigation_listener()->title(), "absent");
  438. }
  439. #if defined(ARCH_CPU_ARM_FAMILY)
  440. // TODO(crbug.com/1058247): Support Vulkan in tests on ARM64.
  441. #define MAYBE_VulkanWebEngineIntegrationTest \
  442. DISABLED_VulkanWebEngineIntegrationTest
  443. #else
  444. #define MAYBE_VulkanWebEngineIntegrationTest VulkanWebEngineIntegrationTest
  445. #endif
  446. class MAYBE_VulkanWebEngineIntegrationTest
  447. : public WebEngineIntegrationMediaTest {};
  448. TEST_F(MAYBE_VulkanWebEngineIntegrationTest,
  449. WebGLContextPresentWithVulkanFeature) {
  450. fuchsia::web::CreateContextParams create_params = TestContextParams();
  451. *create_params.mutable_features() |=
  452. fuchsia::web::ContextFeatureFlags::VULKAN;
  453. CreateContextAndFrame(std::move(create_params));
  454. ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse(
  455. embedded_test_server_.GetURL("/webgl_presence.html").spec()));
  456. navigation_listener()->RunUntilLoaded();
  457. EXPECT_EQ(navigation_listener()->title(), "present");
  458. }
  459. // Does not start WebEngine automatically as one of the tests requires manually
  460. // starting it.
  461. class WebEngineIntegrationCameraTest : public WebEngineIntegrationTestBase {
  462. protected:
  463. WebEngineIntegrationCameraTest() = default;
  464. void RunCameraTest(bool grant_permission);
  465. };
  466. void WebEngineIntegrationCameraTest::RunCameraTest(bool grant_permission) {
  467. fuchsia::web::CreateContextParams create_params = TestContextParams();
  468. media::FakeCameraDeviceWatcher fake_camera_device_watcher(
  469. filtered_service_directory().outgoing_directory());
  470. CreateContextAndFrame(std::move(create_params));
  471. if (grant_permission) {
  472. GrantPermission(
  473. fuchsia::web::PermissionType::CAMERA,
  474. embedded_test_server_.GetURL("/").DeprecatedGetOriginAsURL().spec());
  475. }
  476. const char* url =
  477. grant_permission ? "/camera.html" : "/camera.html?NoPermission";
  478. ASSERT_NO_FATAL_FAILURE(
  479. LoadUrlAndExpectResponse(embedded_test_server_.GetURL(url).spec()));
  480. navigation_listener()->RunUntilTitleEquals("ended");
  481. }
  482. TEST_F(WebEngineIntegrationCameraTest, CameraAccess_WithPermission) {
  483. StartWebEngine(base::CommandLine(base::CommandLine::NO_PROGRAM));
  484. RunCameraTest(/*grant_permission=*/true);
  485. }
  486. TEST_F(WebEngineIntegrationCameraTest, CameraAccess_WithoutPermission) {
  487. StartWebEngine(base::CommandLine(base::CommandLine::NO_PROGRAM));
  488. RunCameraTest(/*grant_permission=*/false);
  489. }
  490. TEST_F(WebEngineIntegrationCameraTest, CameraNoVideoCaptureProcess) {
  491. base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
  492. command_line.AppendSwitchASCII("disable-features", "MojoVideoCapture");
  493. StartWebEngine(std::move(command_line));
  494. RunCameraTest(/*grant_permission=*/true);
  495. }
  496. // Check that when the ContextFeatureFlag HARDWARE_VIDEO_DECODER is
  497. // provided that the CodecFactory service is connected to.
  498. TEST_F(MAYBE_VulkanWebEngineIntegrationTest,
  499. HardwareVideoDecoderFlag_Provided) {
  500. // Check that the CodecFactory service is requested.
  501. base::RunLoop codec_connected_run_loop;
  502. auto* outgoing_directory = filtered_service_directory().outgoing_directory();
  503. outgoing_directory->RemovePublicService<fuchsia::mediacodec::CodecFactory>();
  504. zx_status_t status = outgoing_directory->AddPublicService(
  505. fidl::InterfaceRequestHandler<fuchsia::mediacodec::CodecFactory>(
  506. [&codec_connected_run_loop](auto request) {
  507. codec_connected_run_loop.Quit();
  508. }));
  509. ZX_CHECK(status == ZX_OK, status) << "AddPublicService";
  510. // The VULKAN flag is required for hardware video decoders to be available.
  511. fuchsia::web::CreateContextParams create_params =
  512. ContextParamsWithAudioAndTestData();
  513. *create_params.mutable_features() |=
  514. fuchsia::web::ContextFeatureFlags::VULKAN |
  515. fuchsia::web::ContextFeatureFlags::HARDWARE_VIDEO_DECODER;
  516. CreateContextAndFrame(std::move(create_params));
  517. ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse(
  518. kAutoplayVp9OpusToEndUrl, CreateLoadUrlParamsWithUserActivation()));
  519. codec_connected_run_loop.Run();
  520. }
  521. // Check that the CodecFactory service is not requested when
  522. // HARDWARE_VIDEO_DECODER is not provided.
  523. // The video should use software decoders and still play.
  524. TEST_F(WebEngineIntegrationMediaTest, HardwareVideoDecoderFlag_NotProvided) {
  525. bool is_requested = false;
  526. auto* outgoing_directory = filtered_service_directory().outgoing_directory();
  527. outgoing_directory->RemovePublicService<fuchsia::mediacodec::CodecFactory>();
  528. zx_status_t status = outgoing_directory->AddPublicService(
  529. fidl::InterfaceRequestHandler<fuchsia::mediacodec::CodecFactory>(
  530. [&is_requested](auto request) { is_requested = true; }));
  531. ZX_CHECK(status == ZX_OK, status) << "AddPublicService";
  532. fuchsia::web::CreateContextParams create_params =
  533. ContextParamsWithAudioAndTestData();
  534. CreateContextAndFrame(std::move(create_params));
  535. ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse(
  536. kAutoplayVp9OpusToEndUrl, CreateLoadUrlParamsWithUserActivation()));
  537. navigation_listener()->RunUntilTitleEquals("ended");
  538. EXPECT_FALSE(is_requested);
  539. }