Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(559)

Unified Diff: content/browser/frame_host/render_frame_host_impl_browsertest.cc

Issue 2738943002: Move beforeunload hang timer duties to its own timer. (Closed)
Patch Set: better test Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/frame_host/render_frame_host_impl_browsertest.cc
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
index 6547788162e29da908890e6a50eea3035d1c3ede..5f467554e62c1979c685e02fcf56874736d739e0 100644
--- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -6,9 +6,12 @@
#include "base/macros.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/frame_messages.h"
+#include "content/public/browser/javascript_dialog_manager.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_client.h"
+#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/test_utils.h"
@@ -156,4 +159,126 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
SetBrowserClientForTesting(old_client);
}
+namespace {
+
+class TestJavaScriptDialogManager : public JavaScriptDialogManager,
+ public WebContentsDelegate {
+ public:
+ TestJavaScriptDialogManager() : message_loop_runner_(new MessageLoopRunner) {}
+ ~TestJavaScriptDialogManager() override {}
+
+ void Wait() {
+ message_loop_runner_->Run();
+ message_loop_runner_ = new MessageLoopRunner;
+ }
+
+ DialogClosedCallback& callback() { return callback_; }
+
+ // WebContentsDelegate
+
+ JavaScriptDialogManager* GetJavaScriptDialogManager(
+ WebContents* source) override {
+ return this;
+ }
+
+ // JavaScriptDialogManager
+
+ void RunJavaScriptDialog(WebContents* web_contents,
+ const GURL& origin_url,
+ JavaScriptDialogType dialog_type,
+ const base::string16& message_text,
+ const base::string16& default_prompt_text,
+ const DialogClosedCallback& callback,
+ bool* did_suppress_message) override {}
+
+ void RunBeforeUnloadDialog(WebContents* web_contents,
+ bool is_reload,
+ const DialogClosedCallback& callback) override {
+ callback_ = callback;
+ message_loop_runner_->Quit();
+ }
+
+ bool HandleJavaScriptDialog(WebContents* web_contents,
+ bool accept,
+ const base::string16* prompt_override) override {
+ return true;
+ }
+
+ void CancelDialogs(WebContents* web_contents, bool reset_state) override {}
+
+ private:
+ DialogClosedCallback callback_;
+
+ // The MessageLoopRunner used to spin the message loop.
+ scoped_refptr<MessageLoopRunner> message_loop_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestJavaScriptDialogManager);
+};
+
+class DropBeforeUnloadACKFilter : public BrowserMessageFilter {
+ public:
+ DropBeforeUnloadACKFilter() : BrowserMessageFilter(FrameMsgStart) {}
+
+ protected:
+ ~DropBeforeUnloadACKFilter() override {}
+
+ private:
+ // BrowserMessageFilter:
+ bool OnMessageReceived(const IPC::Message& message) override {
+ return message.type() == FrameHostMsg_BeforeUnload_ACK::ID;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(DropBeforeUnloadACKFilter);
+};
+
+} // namespace
+
+// Tests that a beforeunload dialog in an iframe doesn't stop the beforeunload
+// timer of a parent frame.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+ IframeBeforeUnloadParentHang) {
+ WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
+ TestJavaScriptDialogManager dialog_manager;
+ wc->SetDelegate(&dialog_manager);
+
+ EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
+ // Make an iframe with a beforeunload handler.
+ std::string script =
+ "var iframe = document.createElement('iframe');"
+ "document.body.appendChild(iframe);"
+ "iframe.contentWindow.onbeforeunload=function(e){return 'x'};";
+ EXPECT_TRUE(content::ExecuteScript(wc, script));
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ // Force a process switch by going to a privileged page. The beforeunload
+ // timer will be started on the top-level frame but will be paused while the
+ // beforeunload dialog is shown by the subframe.
+ GURL web_ui_page(std::string(kChromeUIScheme) + "://" +
+ std::string(kChromeUIGpuHost));
+ shell()->LoadURL(web_ui_page);
+ dialog_manager.Wait();
+
+ RenderFrameHostImpl* main_frame =
+ static_cast<RenderFrameHostImpl*>(wc->GetMainFrame());
+ EXPECT_TRUE(main_frame->is_waiting_for_beforeunload_ack());
+
+ // Set up a filter to make sure that when the dialog is answered below and the
+ // renderer sends the beforeunload ACK, it gets... ahem... lost.
+ scoped_refptr<DropBeforeUnloadACKFilter> filter =
+ new DropBeforeUnloadACKFilter();
+ main_frame->GetProcess()->AddFilter(filter.get());
+
+ // Answer the dialog.
+ dialog_manager.callback().Run(true, base::string16());
+
+ // There will be no beforeunload ACK, so if the beforeunload ACK timer isn't
+ // functioning then the navigation will hang forever and this test will time
+ // out. If this waiting for the load stop works, this test won't time out.
+ EXPECT_TRUE(WaitForLoadStop(wc));
+ EXPECT_EQ(web_ui_page, wc->GetLastCommittedURL());
+
+ wc->SetDelegate(nullptr);
+ wc->SetJavaScriptDialogManagerForTesting(nullptr);
+}
+
} // namespace content
« no previous file with comments | « content/browser/frame_host/render_frame_host_impl.cc ('k') | content/browser/renderer_host/render_widget_host_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698