web_message_browsertest.cc 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // Copyright 2020 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 "weblayer/public/js_communication/web_message.h"
  5. #include "base/callback.h"
  6. #include "base/memory/raw_ptr.h"
  7. #include "base/run_loop.h"
  8. #include "base/strings/utf_string_conversions.h"
  9. #include "base/test/scoped_feature_list.h"
  10. #include "content/public/common/content_features.h"
  11. #include "net/dns/mock_host_resolver.h"
  12. #include "weblayer/public/js_communication/web_message.h"
  13. #include "weblayer/public/js_communication/web_message_host.h"
  14. #include "weblayer/public/js_communication/web_message_host_factory.h"
  15. #include "weblayer/public/js_communication/web_message_reply_proxy.h"
  16. #include "weblayer/public/navigation.h"
  17. #include "weblayer/public/navigation_controller.h"
  18. #include "weblayer/public/tab.h"
  19. #include "weblayer/shell/browser/shell.h"
  20. #include "weblayer/test/weblayer_browser_test.h"
  21. #include "weblayer/test/weblayer_browser_test_utils.h"
  22. namespace weblayer {
  23. namespace {
  24. class WebMessageHostImpl;
  25. WebMessageHostImpl* current_connection = nullptr;
  26. // WebMessageHost implementation that records contents of OnPostMessage().
  27. class WebMessageHostImpl : public WebMessageHost {
  28. public:
  29. WebMessageHostImpl(base::RepeatingClosure quit_closure,
  30. const std::string& origin_string,
  31. bool is_main_frame,
  32. WebMessageReplyProxy* proxy)
  33. : quit_closure_(quit_closure), proxy_(proxy) {
  34. current_connection = this;
  35. }
  36. ~WebMessageHostImpl() override {
  37. if (current_connection == this)
  38. current_connection = nullptr;
  39. }
  40. int back_forward_cache_state_changed_call_count() const {
  41. return back_forward_cache_state_changed_call_count_;
  42. }
  43. void WaitForBackForwardStateToBe(bool value) {
  44. if (value == proxy_->IsInBackForwardCache())
  45. return;
  46. expected_back_forward_value_ = value;
  47. state_changed_run_loop_ = std::make_unique<base::RunLoop>();
  48. state_changed_run_loop_->Run();
  49. state_changed_run_loop_.reset();
  50. }
  51. WebMessageReplyProxy* proxy() { return proxy_; }
  52. std::vector<std::u16string>& messages() { return messages_; }
  53. // WebMessageHost:
  54. void OnPostMessage(std::unique_ptr<WebMessage> message) override {
  55. messages_.push_back(std::move(message->message));
  56. if (++call_count_ == 1) {
  57. // First time called, send a message to the page.
  58. std::unique_ptr<WebMessage> m2 = std::make_unique<WebMessage>();
  59. m2->message = u"from c++";
  60. proxy_->PostWebMessage(std::move(m2));
  61. } else {
  62. // On subsequent calls quit.
  63. quit_closure_.Run();
  64. }
  65. }
  66. void OnBackForwardCacheStateChanged() override {
  67. ++back_forward_cache_state_changed_call_count_;
  68. if (state_changed_run_loop_ &&
  69. expected_back_forward_value_ == proxy_->IsInBackForwardCache()) {
  70. state_changed_run_loop_->Quit();
  71. }
  72. }
  73. private:
  74. int call_count_ = 0;
  75. int back_forward_cache_state_changed_call_count_ = 0;
  76. base::RepeatingClosure quit_closure_;
  77. raw_ptr<WebMessageReplyProxy> proxy_;
  78. std::vector<std::u16string> messages_;
  79. bool expected_back_forward_value_ = false;
  80. std::unique_ptr<base::RunLoop> state_changed_run_loop_;
  81. };
  82. // WebMessageHostFactory implementation that creates WebMessageHostImpl.
  83. class WebMessageHostFactoryImpl : public WebMessageHostFactory {
  84. public:
  85. explicit WebMessageHostFactoryImpl(base::RepeatingClosure quit_closure)
  86. : quit_closure_(quit_closure) {}
  87. ~WebMessageHostFactoryImpl() override = default;
  88. // WebMessageHostFactory:
  89. std::unique_ptr<WebMessageHost> CreateHost(
  90. const std::string& origin_string,
  91. bool is_main_frame,
  92. WebMessageReplyProxy* proxy) override {
  93. return std::make_unique<WebMessageHostImpl>(quit_closure_, origin_string,
  94. is_main_frame, proxy);
  95. }
  96. private:
  97. base::RepeatingClosure quit_closure_;
  98. };
  99. } // namespace
  100. using WebMessageTest = WebLayerBrowserTest;
  101. IN_PROC_BROWSER_TEST_F(WebMessageTest, SendAndReceive) {
  102. EXPECT_TRUE(embedded_test_server()->Start());
  103. base::RunLoop run_loop;
  104. shell()->tab()->AddWebMessageHostFactory(
  105. std::make_unique<WebMessageHostFactoryImpl>(run_loop.QuitClosure()), u"x",
  106. {"*"});
  107. // web_message_test.html posts a message immediately.
  108. shell()->tab()->GetNavigationController()->Navigate(
  109. embedded_test_server()->GetURL("/web_message_test.html"));
  110. run_loop.Run();
  111. // There should be two messages. The one from the page, and the ack triggered
  112. // when WebMessageHostImpl calls PostMessage().
  113. ASSERT_TRUE(current_connection);
  114. ASSERT_EQ(2u, current_connection->messages().size());
  115. EXPECT_EQ(u"from page", current_connection->messages()[0]);
  116. EXPECT_EQ(u"bouncing from c++", current_connection->messages()[1]);
  117. // WebLayer's Page has no functions, verify it can be requested.
  118. current_connection->proxy()->GetPage();
  119. }
  120. // Ensures that a listener removed from a post message works.
  121. IN_PROC_BROWSER_TEST_F(WebMessageTest, RemoveFromReceive) {
  122. EXPECT_TRUE(embedded_test_server()->Start());
  123. base::RunLoop run_loop;
  124. shell()->tab()->AddWebMessageHostFactory(
  125. std::make_unique<WebMessageHostFactoryImpl>(run_loop.QuitClosure()), u"x",
  126. {"*"});
  127. // web_message_test.html posts a message immediately.
  128. shell()->tab()->GetNavigationController()->Navigate(
  129. embedded_test_server()->GetURL("/web_message_test2.html"));
  130. run_loop.Run();
  131. // There should be two messages. The one from the page, and the ack triggered
  132. // when WebMessageHostImpl calls PostMessage().
  133. ASSERT_TRUE(current_connection);
  134. ASSERT_EQ(2u, current_connection->messages().size());
  135. EXPECT_EQ(u"from page", current_connection->messages()[0]);
  136. EXPECT_EQ(u"bouncing from c++", current_connection->messages()[1]);
  137. // WebLayer's Page has no functions, verify it can be requested.
  138. current_connection->proxy()->GetPage();
  139. }
  140. class WebMessageTestWithBfCache : public WebLayerBrowserTest {
  141. public:
  142. // WebLayerBrowserTest:
  143. void SetUp() override {
  144. scoped_feature_list_.InitWithFeaturesAndParameters(
  145. {{features::kBackForwardCache,
  146. {// Set a very long TTL before expiration (longer than the test
  147. // timeout) so tests that are expecting deletion don't pass when
  148. // they shouldn't.
  149. {"TimeToLiveInBackForwardCacheInSeconds", "3600"}}}},
  150. // Allow BackForwardCache for all devices regardless of their memory.
  151. {features::kBackForwardCacheMemoryControls});
  152. WebLayerBrowserTest::SetUp();
  153. }
  154. void SetUpOnMainThread() override {
  155. WebLayerBrowserTest::SetUpOnMainThread();
  156. host_resolver()->AddRule("*", "127.0.0.1");
  157. }
  158. private:
  159. base::test::ScopedFeatureList scoped_feature_list_;
  160. };
  161. IN_PROC_BROWSER_TEST_F(WebMessageTestWithBfCache, Basic) {
  162. ASSERT_TRUE(embedded_test_server()->Start());
  163. GURL url1(embedded_test_server()->GetURL("a.com", "/web_message_test.html"));
  164. base::RunLoop run_loop;
  165. shell()->tab()->AddWebMessageHostFactory(
  166. std::make_unique<WebMessageHostFactoryImpl>(run_loop.QuitClosure()), u"x",
  167. {"http://a.com:" + url1.port()});
  168. auto* navigation_controller = shell()->tab()->GetNavigationController();
  169. navigation_controller->Navigate(url1);
  170. run_loop.Run();
  171. // A WebMessageHostImpl should be created, and it should not be in the cache.
  172. WebMessageHostImpl* web_message_host = current_connection;
  173. ASSERT_TRUE(web_message_host);
  174. EXPECT_FALSE(web_message_host->proxy()->IsInBackForwardCache());
  175. EXPECT_EQ(0, web_message_host->back_forward_cache_state_changed_call_count());
  176. Page* original_page = &(web_message_host->proxy()->GetPage());
  177. // Navigate to a new host. The old page should go into the cache.
  178. OneShotNavigationObserver observer1(shell());
  179. navigation_controller->Navigate(
  180. embedded_test_server()->GetURL("b.com", "/simple_page.html"));
  181. observer1.WaitForNavigation();
  182. EXPECT_TRUE(observer1.completed());
  183. ASSERT_EQ(current_connection, web_message_host);
  184. web_message_host->WaitForBackForwardStateToBe(true);
  185. EXPECT_EQ(1, web_message_host->back_forward_cache_state_changed_call_count());
  186. // Navigate back.
  187. OneShotNavigationObserver observer2(shell());
  188. navigation_controller->GoBack();
  189. observer2.WaitForNavigation();
  190. web_message_host->WaitForBackForwardStateToBe(false);
  191. EXPECT_EQ(2, web_message_host->back_forward_cache_state_changed_call_count());
  192. EXPECT_EQ(original_page, &(web_message_host->proxy()->GetPage()));
  193. }
  194. } // namespace weblayer