web_runner_smoke_test.cc 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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/modular/cpp/fidl.h>
  5. #include <fuchsia/modular/cpp/fidl_test_base.h>
  6. #include <fuchsia/sys/cpp/fidl.h>
  7. #include <lib/sys/cpp/component_context.h>
  8. #include "base/bind.h"
  9. #include "base/fuchsia/process_context.h"
  10. #include "base/fuchsia/scoped_service_binding.h"
  11. #include "base/fuchsia/service_provider_impl.h"
  12. #include "base/test/task_environment.h"
  13. #include "base/threading/thread_task_runner_handle.h"
  14. #include "build/build_config.h"
  15. #include "net/test/embedded_test_server/embedded_test_server.h"
  16. #include "net/test/embedded_test_server/http_request.h"
  17. #include "net/test/embedded_test_server/http_response.h"
  18. #include "testing/gmock/include/gmock/gmock.h"
  19. #include "testing/gtest/include/gtest/gtest.h"
  20. using net::test_server::HttpRequest;
  21. using net::test_server::HttpResponse;
  22. namespace {
  23. class WebRunnerSmokeTest : public testing::Test {
  24. public:
  25. WebRunnerSmokeTest() = default;
  26. WebRunnerSmokeTest(const WebRunnerSmokeTest&) = delete;
  27. WebRunnerSmokeTest& operator=(const WebRunnerSmokeTest&) = delete;
  28. void SetUp() final {
  29. test_server_.RegisterRequestHandler(base::BindRepeating(
  30. &WebRunnerSmokeTest::HandleRequest, base::Unretained(this)));
  31. ASSERT_TRUE(test_server_.Start());
  32. service_provider_ = base::ServiceProviderImpl::CreateForOutgoingDirectory(
  33. &outgoing_directory_);
  34. }
  35. fuchsia::sys::LaunchInfo LaunchInfoWithServices() {
  36. auto services = fuchsia::sys::ServiceList::New();
  37. service_provider_->AddBinding(services->provider.NewRequest());
  38. fuchsia::sys::LaunchInfo launch_info;
  39. launch_info.additional_services = std::move(services);
  40. return launch_info;
  41. }
  42. std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
  43. GURL absolute_url = test_server_.GetURL(request.relative_url);
  44. if (absolute_url.path() == "/test.html") {
  45. EXPECT_FALSE(test_html_requested_);
  46. test_html_requested_ = true;
  47. auto http_response =
  48. std::make_unique<net::test_server::BasicHttpResponse>();
  49. http_response->set_code(net::HTTP_OK);
  50. http_response->set_content("<!doctype html><img src=\"/img.png\">");
  51. http_response->set_content_type("text/html");
  52. return http_response;
  53. } else if (absolute_url.path() == "/window_close.html") {
  54. auto http_response =
  55. std::make_unique<net::test_server::BasicHttpResponse>();
  56. http_response->set_code(net::HTTP_OK);
  57. http_response->set_content(
  58. "<!doctype html><script>window.close();</script>");
  59. http_response->set_content_type("text/html");
  60. return http_response;
  61. } else if (absolute_url.path() == "/img.png") {
  62. EXPECT_FALSE(test_image_requested_);
  63. test_image_requested_ = true;
  64. // All done!
  65. run_loop_.Quit();
  66. }
  67. return nullptr;
  68. }
  69. protected:
  70. bool test_html_requested_ = false;
  71. bool test_image_requested_ = false;
  72. base::test::SingleThreadTaskEnvironment task_environment_{
  73. base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
  74. sys::OutgoingDirectory outgoing_directory_;
  75. std::unique_ptr<base::ServiceProviderImpl> service_provider_;
  76. net::EmbeddedTestServer test_server_;
  77. base::RunLoop run_loop_;
  78. };
  79. // Verify that the Component loads and fetches the desired page.
  80. // TODO(https://crbug.com/1073823): Flakes due to raciness between test
  81. // completion and GPU process failure on bots which lack GPU emulation.
  82. #if defined(ARCH_CPU_ARM64)
  83. #define MAYBE_RequestHtmlAndImage DISABLED_RequestHtmlAndImage
  84. #else
  85. #define MAYBE_RequestHtmlAndImage RequestHtmlAndImage
  86. #endif
  87. TEST_F(WebRunnerSmokeTest, MAYBE_RequestHtmlAndImage) {
  88. fuchsia::sys::LaunchInfo launch_info = LaunchInfoWithServices();
  89. launch_info.url = test_server_.GetURL("/test.html").spec();
  90. auto launcher = base::ComponentContextForProcess()
  91. ->svc()
  92. ->Connect<fuchsia::sys::Launcher>();
  93. fuchsia::sys::ComponentControllerSyncPtr controller;
  94. launcher->CreateComponent(std::move(launch_info), controller.NewRequest());
  95. run_loop_.Run();
  96. EXPECT_TRUE(test_html_requested_);
  97. EXPECT_TRUE(test_image_requested_);
  98. }
  99. // Verify that the Component can be terminated via the Lifecycle API.
  100. TEST_F(WebRunnerSmokeTest, LifecycleTerminate) {
  101. fidl::InterfaceHandle<fuchsia::io::Directory> directory;
  102. fuchsia::sys::LaunchInfo launch_info = LaunchInfoWithServices();
  103. launch_info.url = test_server_.GetURL("/test.html").spec();
  104. launch_info.directory_request = directory.NewRequest().TakeChannel();
  105. auto launcher = base::ComponentContextForProcess()
  106. ->svc()
  107. ->Connect<fuchsia::sys::Launcher>();
  108. fuchsia::sys::ComponentControllerPtr controller;
  109. launcher->CreateComponent(std::move(launch_info), controller.NewRequest());
  110. sys::ServiceDirectory component_services(std::move(directory));
  111. auto lifecycle = component_services.Connect<fuchsia::modular::Lifecycle>();
  112. ASSERT_TRUE(lifecycle);
  113. // Terminate() the component, and expect that |controller| disconnects us.
  114. base::RunLoop loop;
  115. controller.set_error_handler(
  116. [quit_loop = loop.QuitClosure()](zx_status_t status) {
  117. EXPECT_EQ(status, ZX_ERR_PEER_CLOSED);
  118. quit_loop.Run();
  119. });
  120. lifecycle->Terminate();
  121. loop.Run();
  122. EXPECT_FALSE(controller);
  123. }
  124. // Verify that if the Frame disconnects, the Component tears down.
  125. TEST_F(WebRunnerSmokeTest, ComponentExitOnFrameClose) {
  126. fuchsia::sys::LaunchInfo launch_info = LaunchInfoWithServices();
  127. launch_info.url = test_server_.GetURL("/window_close.html").spec();
  128. auto launcher = base::ComponentContextForProcess()
  129. ->svc()
  130. ->Connect<fuchsia::sys::Launcher>();
  131. fuchsia::sys::ComponentControllerPtr controller;
  132. launcher->CreateComponent(std::move(launch_info), controller.NewRequest());
  133. // Script in the page will execute window.close(), which should teardown the
  134. // Component, causing |controller| to be disconnected.
  135. base::RunLoop loop;
  136. controller.set_error_handler(
  137. [quit_loop = loop.QuitClosure()](zx_status_t status) {
  138. EXPECT_EQ(status, ZX_ERR_PEER_CLOSED);
  139. quit_loop.Run();
  140. });
  141. loop.Run();
  142. EXPECT_FALSE(controller);
  143. }
  144. class MockModuleContext
  145. : public fuchsia::modular::testing::ModuleContext_TestBase {
  146. public:
  147. MockModuleContext() = default;
  148. MockModuleContext(const MockModuleContext&) = delete;
  149. MockModuleContext& operator=(const MockModuleContext&) = delete;
  150. ~MockModuleContext() override = default;
  151. MOCK_METHOD0(RemoveSelfFromStory, void());
  152. void NotImplemented_(const std::string& name) override {
  153. NOTIMPLEMENTED() << name;
  154. }
  155. };
  156. // Verify that Modular's RemoveSelfFromStory() is called on teardown.
  157. TEST_F(WebRunnerSmokeTest, RemoveSelfFromStoryOnFrameClose) {
  158. fuchsia::sys::LaunchInfo launch_info = LaunchInfoWithServices();
  159. launch_info.url = test_server_.GetURL("/window_close.html").spec();
  160. MockModuleContext module_context;
  161. EXPECT_CALL(module_context, RemoveSelfFromStory);
  162. base::ScopedServiceBinding<fuchsia::modular::ModuleContext> binding(
  163. &outgoing_directory_, &module_context);
  164. launch_info.additional_services->names.emplace_back(
  165. fuchsia::modular::ModuleContext::Name_);
  166. auto launcher = base::ComponentContextForProcess()
  167. ->svc()
  168. ->Connect<fuchsia::sys::Launcher>();
  169. fuchsia::sys::ComponentControllerPtr controller;
  170. launcher->CreateComponent(std::move(launch_info), controller.NewRequest());
  171. // Script in the page will execute window.close(), which should teardown the
  172. // Component, causing |controller| to be disconnected.
  173. base::RunLoop loop;
  174. controller.set_error_handler(
  175. [quit_loop = loop.QuitClosure()](zx_status_t status) {
  176. EXPECT_EQ(status, ZX_ERR_PEER_CLOSED);
  177. quit_loop.Run();
  178. });
  179. loop.Run();
  180. EXPECT_FALSE(controller);
  181. // Spin the loop again to ensure that RemoveSelfFromStory is processed.
  182. base::RunLoop().RunUntilIdle();
  183. }
  184. } // anonymous namespace