Index: content/test/navigation_simulator_unittest.cc |
diff --git a/content/test/navigation_simulator_unittest.cc b/content/test/navigation_simulator_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6e36bc2c5cbe59d58d4053d05cc6735a8a1d4fc0 |
--- /dev/null |
+++ b/content/test/navigation_simulator_unittest.cc |
@@ -0,0 +1,162 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/public/test/navigation_simulator.h" |
+ |
+#include "base/memory/weak_ptr.h" |
+#include "base/run_loop.h" |
+#include "content/public/browser/navigation_handle.h" |
+#include "content/public/browser/navigation_throttle.h" |
+#include "content/test/test_render_frame_host.h" |
+#include "content/test/test_web_contents.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace content { |
+ |
+enum CancelTime { |
+ WILL_SEND_REQUEST, |
+ WILL_REDIRECT_REQUEST, |
+ WILL_PROCESS_RESPONSE, |
+ NEVER, |
+}; |
+ |
+enum ResultSynchrony { |
+ SYNCHRONOUS, |
+ ASYNCHRONOUS, |
+}; |
+ |
+std::string CancelTimeToString(CancelTime cancel_time) { |
+ switch (cancel_time) { |
+ case WILL_SEND_REQUEST: |
+ return "WILL_SEND_REQUEST"; |
+ case WILL_REDIRECT_REQUEST: |
+ return "WILL_REDIRECT_REQUEST"; |
+ case WILL_PROCESS_RESPONSE: |
+ return "WILL_PROCESS_RESPONSE"; |
+ case NEVER: |
+ return "NEVER"; |
+ } |
+ NOTREACHED(); |
+ return ""; |
+} |
+ |
+std::string ResultSynchronyToString(ResultSynchrony sync) { |
+ return sync == SYNCHRONOUS ? "SYNCHRONOUS" : "ASYNCHRONOUS"; |
+} |
+ |
+class CancellingNavigationThrottle : public NavigationThrottle { |
+ public: |
+ CancellingNavigationThrottle(NavigationHandle* handle, |
+ CancelTime cancel_time, |
+ ResultSynchrony sync) |
+ : NavigationThrottle(handle), |
+ cancel_time_(cancel_time), |
+ sync_(sync), |
+ weak_ptr_factory_(this) {} |
+ |
+ ~CancellingNavigationThrottle() override {} |
+ |
+ NavigationThrottle::ThrottleCheckResult WillStartRequest() override { |
+ return ProcessState(cancel_time_ == WILL_SEND_REQUEST); |
+ } |
+ |
+ NavigationThrottle::ThrottleCheckResult WillRedirectRequest() override { |
+ return ProcessState(cancel_time_ == WILL_REDIRECT_REQUEST); |
+ } |
+ |
+ NavigationThrottle::ThrottleCheckResult WillProcessResponse() override { |
+ return ProcessState(cancel_time_ == WILL_PROCESS_RESPONSE); |
+ } |
+ |
+ NavigationThrottle::ThrottleCheckResult ProcessState(bool should_cancel) { |
+ if (sync_ == ASYNCHRONOUS) { |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ base::Bind(&CancellingNavigationThrottle::MaybeCancel, |
+ weak_ptr_factory_.GetWeakPtr(), should_cancel)); |
+ return NavigationThrottle::DEFER; |
+ } |
+ return should_cancel ? NavigationThrottle::CANCEL |
+ : NavigationThrottle::PROCEED; |
+ } |
+ |
+ void MaybeCancel(bool cancel) { |
+ if (cancel) |
+ navigation_handle()->CancelDeferredNavigation(NavigationThrottle::CANCEL); |
+ else |
+ navigation_handle()->Resume(); |
+ } |
+ |
+ const CancelTime cancel_time_; |
+ const ResultSynchrony sync_; |
+ base::WeakPtrFactory<CancellingNavigationThrottle> weak_ptr_factory_; |
+}; |
+ |
+class NavigationSimulatorTest : public RenderViewHostImplTestHarness, |
+ public WebContentsObserver, |
+ public testing::WithParamInterface< |
+ std::tuple<CancelTime, ResultSynchrony>> { |
+ public: |
+ void SetUp() override { |
+ RenderViewHostImplTestHarness::SetUp(); |
+ contents()->GetMainFrame()->InitializeRenderFrameIfNeeded(); |
+ Observe(RenderViewHostImplTestHarness::web_contents()); |
+ std::tie(cancel_time_, sync_) = GetParam(); |
+ simulator_ = NavigationSimulator::CreateRendererInitiated( |
+ GURL("https://example.test"), main_rfh()); |
+ } |
+ |
+ void DidStartNavigation(content::NavigationHandle* handle) override { |
+ handle->RegisterThrottleForTesting( |
+ base::MakeUnique<CancellingNavigationThrottle>(handle, cancel_time_, |
+ sync_)); |
+ } |
+ |
+ // Returns true if the request has been cancelled. |
+ bool ExpectResult(NavigationThrottle::ThrottleCheckResult sync_result, |
+ bool should_cancel) { |
+ NavigationThrottle::ThrottleCheckResult result = sync_result; |
+ if (sync_ == ASYNCHRONOUS) { |
+ EXPECT_EQ(NavigationThrottle::DEFER, sync_result); |
+ result = simulator_->WaitForThrottleChecksComplete(); |
+ } |
+ EXPECT_EQ(should_cancel ? NavigationThrottle::CANCEL |
+ : NavigationThrottle::PROCEED, |
+ result); |
+ return should_cancel; |
+ } |
+ |
+ CancelTime cancel_time_; |
+ ResultSynchrony sync_; |
+ std::unique_ptr<NavigationSimulator> simulator_; |
+}; |
+ |
+// Stress test the navigation simulator by having a navigation throttle cancel |
+// the navigation at various points in the flow, both synchronously and |
+// asynchronously. |
+TEST_P(NavigationSimulatorTest, Cancel) { |
+ SCOPED_TRACE(::testing::Message() |
+ << "CancelTime: " << CancelTimeToString(cancel_time_) |
+ << " ResultSynchrony: " << ResultSynchronyToString(sync_)); |
+ if (ExpectResult(simulator_->Start(), cancel_time_ == WILL_SEND_REQUEST)) |
+ return; |
+ if (ExpectResult(simulator_->Redirect(GURL("https://example.test/redirect")), |
+ cancel_time_ == WILL_REDIRECT_REQUEST)) |
+ return; |
+ ExpectResult(simulator_->Commit(), cancel_time_ == WILL_PROCESS_RESPONSE); |
+} |
+ |
+INSTANTIATE_TEST_CASE_P( |
+ CancelMethod, |
+ NavigationSimulatorTest, |
+ ::testing::Values(std::make_tuple(WILL_SEND_REQUEST, SYNCHRONOUS), |
+ std::make_tuple(WILL_SEND_REQUEST, ASYNCHRONOUS), |
+ std::make_tuple(WILL_REDIRECT_REQUEST, SYNCHRONOUS), |
+ std::make_tuple(WILL_REDIRECT_REQUEST, ASYNCHRONOUS), |
+ std::make_tuple(WILL_PROCESS_RESPONSE, SYNCHRONOUS), |
+ std::make_tuple(WILL_PROCESS_RESPONSE, ASYNCHRONOUS), |
+ std::make_tuple(NEVER, SYNCHRONOUS), |
+ std::make_tuple(NEVER, ASYNCHRONOUS))); |
+ |
+} // namespace content |