blob: dc285e43e44bb8a4b51d0a9ece8deca8f4356b94 [file] [log] [blame]
// 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 "components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "components/subresource_filter/content/browser/async_document_subresource_filter.h"
#include "components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.h"
#include "components/subresource_filter/core/common/scoped_timers.h"
#include "components/subresource_filter/core/common/test_ruleset_creator.h"
#include "components/subresource_filter/core/common/test_ruleset_utils.h"
#include "components/subresource_filter/mojom/subresource_filter.mojom.h"
#include "components/url_pattern_index/proto/rules.pb.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_renderer_host.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace subresource_filter {
namespace {
// Histogram name on thread timers. Please, use |ExpectThreadTimers| for
// expectation calls corrections.
constexpr char kActivationCPU[] =
"SubresourceFilter.DocumentLoad.Activation.CPUDuration";
int ExpectThreadTimers(int expected) {
return ScopedThreadTimers::IsSupported() ? expected : 0;
}
} // namespace
namespace proto = url_pattern_index::proto;
// The tests are parameterized by a bool which enables speculative main frame
// activation computation in DRYRUN mode. In practice, this will correspond to
// the kAdTagging feature.
class ActivationStateComputingNavigationThrottleTest
: public content::RenderViewHostTestHarness,
public content::WebContentsObserver,
public ::testing::WithParamInterface<bool> {
public:
ActivationStateComputingNavigationThrottleTest()
: simple_task_runner_(base::MakeRefCounted<base::TestSimpleTaskRunner>()),
dryrun_speculation_(GetParam()) {}
~ActivationStateComputingNavigationThrottleTest() override {}
void SetUp() override {
content::RenderViewHostTestHarness::SetUp();
NavigateAndCommit(GURL("https://example.first"));
InitializeRuleset();
Observe(RenderViewHostTestHarness::web_contents());
}
void TearDown() override {
ruleset_handle_.reset();
dealer_handle_.reset();
// The various ruleset classes post tasks to delete their blocking task
// runners. Make sure that happens now to avoid test-only leaks.
base::RunLoop().RunUntilIdle();
simple_task_runner()->RunUntilIdle();
content::RenderViewHostTestHarness::TearDown();
}
void InitializeRuleset() {
std::vector<proto::UrlRule> rules;
rules.push_back(testing::CreateWhitelistRuleForDocument(
"whitelisted.com", proto::ACTIVATION_TYPE_DOCUMENT,
{"allow-child-to-be-whitelisted.com",
"whitelisted-generic-with-disabled-child.com"}));
rules.push_back(testing::CreateWhitelistRuleForDocument(
"whitelisted-generic.com", proto::ACTIVATION_TYPE_GENERICBLOCK,
{"allow-child-to-be-whitelisted.com"}));
rules.push_back(testing::CreateWhitelistRuleForDocument(
"whitelisted-generic-with-disabled-child.com",
proto::ACTIVATION_TYPE_GENERICBLOCK,
{"allow-child-to-be-whitelisted.com"}));
rules.push_back(testing::CreateWhitelistRuleForDocument(
"whitelisted-always.com", proto::ACTIVATION_TYPE_DOCUMENT));
ASSERT_NO_FATAL_FAILURE(test_ruleset_creator_.CreateRulesetWithRules(
rules, &test_ruleset_pair_));
// Make the blocking task runner run on the current task runner for the
// tests, to ensure that the NavigationSimulator properly runs all necessary
// tasks while waiting for throttle checks to finish.
InitializeRulesetHandles(base::SequencedTaskRunnerHandle::Get());
}
void NavigateAndCommitMainFrameWithPageActivationState(
const GURL& document_url,
const mojom::ActivationLevel& level) {
mojom::ActivationState state;
state.activation_level = level;
CreateTestNavigationForMainFrame(document_url);
SimulateStartAndExpectToProceed();
NotifyPageActivation(state);
SimulateCommitAndExpectToProceed();
}
void CreateTestNavigationForMainFrame(const GURL& first_url) {
navigation_simulator_ =
content::NavigationSimulator::CreateRendererInitiated(first_url,
main_rfh());
}
void CreateSubframeAndInitTestNavigation(
const GURL& first_url,
content::RenderFrameHost* parent,
const mojom::ActivationState& parent_activation_state) {
ASSERT_TRUE(parent);
parent_activation_state_ = parent_activation_state;
content::RenderFrameHost* navigating_subframe =
content::RenderFrameHostTester::For(parent)->AppendChild("subframe");
navigation_simulator_ =
content::NavigationSimulator::CreateRendererInitiated(
first_url, navigating_subframe);
}
void SimulateStartAndExpectToProceed() {
ASSERT_TRUE(navigation_simulator_);
navigation_simulator_->Start();
EXPECT_EQ(content::NavigationThrottle::PROCEED,
navigation_simulator_->GetLastThrottleCheckResult());
}
void SimulateRedirectAndExpectToProceed(const GURL& new_url) {
navigation_simulator_->Redirect(new_url);
EXPECT_EQ(content::NavigationThrottle::PROCEED,
navigation_simulator_->GetLastThrottleCheckResult());
}
void SimulateCommitAndExpectToProceed() {
navigation_simulator_->Commit();
EXPECT_EQ(content::NavigationThrottle::PROCEED,
navigation_simulator_->GetLastThrottleCheckResult());
}
void InitializeRulesetHandles(
scoped_refptr<base::SequencedTaskRunner> ruleset_task_runner) {
dealer_handle_ = std::make_unique<VerifiedRulesetDealer::Handle>(
std::move(ruleset_task_runner));
dealer_handle_->TryOpenAndSetRulesetFile(test_ruleset_pair_.indexed.path,
/*expected_checksum=*/0,
base::DoNothing());
ruleset_handle_ =
std::make_unique<VerifiedRuleset::Handle>(dealer_handle_.get());
}
void NotifyPageActivation(mojom::ActivationState state) {
test_throttle_->NotifyPageActivationWithRuleset(ruleset_handle_.get(),
state);
}
mojom::ActivationState last_activation_state() {
EXPECT_TRUE(last_activation_state_.has_value());
return last_activation_state_.value_or(mojom::ActivationState());
}
content::RenderFrameHost* last_committed_frame_host() {
return last_committed_frame_host_;
}
scoped_refptr<base::TestSimpleTaskRunner> simple_task_runner() {
return simple_task_runner_;
}
void set_parent_activation_state(const mojom::ActivationState& state) {
parent_activation_state_ = state;
}
protected:
// content::WebContentsObserver:
void DidStartNavigation(
content::NavigationHandle* navigation_handle) override {
std::unique_ptr<ActivationStateComputingNavigationThrottle> throttle =
navigation_handle->IsInMainFrame()
? ActivationStateComputingNavigationThrottle::CreateForMainFrame(
navigation_handle)
: ActivationStateComputingNavigationThrottle::CreateForSubframe(
navigation_handle, ruleset_handle_.get(),
parent_activation_state_.value());
if (navigation_handle->IsInMainFrame() && dryrun_speculation_) {
mojom::ActivationState dryrun_state;
dryrun_state.activation_level = mojom::ActivationLevel::kDryRun;
throttle->NotifyPageActivationWithRuleset(ruleset_handle_.get(),
dryrun_state);
}
test_throttle_ = throttle.get();
navigation_handle->RegisterThrottleForTesting(std::move(throttle));
}
void ReadyToCommitNavigation(
content::NavigationHandle* navigation_handle) override {
if (!test_throttle_)
return;
ASSERT_EQ(navigation_handle, test_throttle_->navigation_handle());
if (test_throttle_->filter())
test_throttle_->WillSendActivationToRenderer();
if (auto filter = test_throttle_->ReleaseFilter()) {
EXPECT_NE(mojom::ActivationLevel::kDisabled,
filter->activation_state().activation_level);
last_activation_state_ = filter->activation_state();
} else {
last_activation_state_ = mojom::ActivationState();
}
}
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override {
if (!test_throttle_)
return;
last_committed_frame_host_ = navigation_handle->GetRenderFrameHost();
test_throttle_ = nullptr;
}
bool dryrun_speculation() const { return dryrun_speculation_; }
private:
testing::TestRulesetCreator test_ruleset_creator_;
testing::TestRulesetPair test_ruleset_pair_;
std::unique_ptr<VerifiedRulesetDealer::Handle> dealer_handle_;
std::unique_ptr<VerifiedRuleset::Handle> ruleset_handle_;
std::unique_ptr<content::NavigationSimulator> navigation_simulator_;
scoped_refptr<base::TestSimpleTaskRunner> simple_task_runner_;
// Owned by the current navigation.
ActivationStateComputingNavigationThrottle* test_throttle_;
base::Optional<mojom::ActivationState> last_activation_state_;
base::Optional<mojom::ActivationState> parent_activation_state_;
// Needed for potential cross process navigations which swap hosts.
content::RenderFrameHost* last_committed_frame_host_ = nullptr;
bool dryrun_speculation_;
DISALLOW_COPY_AND_ASSIGN(ActivationStateComputingNavigationThrottleTest);
};
typedef ActivationStateComputingNavigationThrottleTest
ActivationStateComputingThrottleMainFrameTest;
typedef ActivationStateComputingNavigationThrottleTest
ActivationStateComputingThrottleSubFrameTest;
TEST_P(ActivationStateComputingThrottleMainFrameTest, Activate) {
NavigateAndCommitMainFrameWithPageActivationState(
GURL("http://example.test/"), mojom::ActivationLevel::kEnabled);
mojom::ActivationState state = last_activation_state();
EXPECT_EQ(mojom::ActivationLevel::kEnabled, state.activation_level);
EXPECT_FALSE(state.filtering_disabled_for_document);
}
TEST_P(ActivationStateComputingThrottleMainFrameTest,
NoPageActivationNotification_NoActivation) {
CreateTestNavigationForMainFrame(GURL("http://example.test/"));
SimulateStartAndExpectToProceed();
SimulateRedirectAndExpectToProceed(GURL("http://example.test/?v=1"));
// Never send NotifyPageActivation.
SimulateCommitAndExpectToProceed();
mojom::ActivationState state = last_activation_state();
EXPECT_EQ(mojom::ActivationLevel::kDisabled, state.activation_level);
}
TEST_P(ActivationStateComputingThrottleMainFrameTest,
WhitelistDoesNotApply_CausesActivation) {
NavigateAndCommitMainFrameWithPageActivationState(
GURL("http://allow-child-to-be-whitelisted.com/"),
mojom::ActivationLevel::kEnabled);
NavigateAndCommitMainFrameWithPageActivationState(
GURL("http://whitelisted.com/"), mojom::ActivationLevel::kEnabled);
mojom::ActivationState state = last_activation_state();
EXPECT_FALSE(state.filtering_disabled_for_document);
EXPECT_FALSE(state.generic_blocking_rules_disabled);
EXPECT_EQ(mojom::ActivationLevel::kEnabled, state.activation_level);
}
TEST_P(ActivationStateComputingThrottleMainFrameTest,
Whitelisted_DisablesFiltering) {
NavigateAndCommitMainFrameWithPageActivationState(
GURL("http://whitelisted-always.com/"), mojom::ActivationLevel::kEnabled);
mojom::ActivationState state = last_activation_state();
EXPECT_TRUE(state.filtering_disabled_for_document);
EXPECT_FALSE(state.generic_blocking_rules_disabled);
EXPECT_EQ(mojom::ActivationLevel::kEnabled, state.activation_level);
}
TEST_P(ActivationStateComputingThrottleSubFrameTest, Activate) {
NavigateAndCommitMainFrameWithPageActivationState(
GURL("http://example.test/"), mojom::ActivationLevel::kEnabled);
CreateSubframeAndInitTestNavigation(GURL("http://example.child/"),
last_committed_frame_host(),
last_activation_state());
SimulateStartAndExpectToProceed();
SimulateRedirectAndExpectToProceed(GURL("http://example.child/?v=1"));
SimulateCommitAndExpectToProceed();
mojom::ActivationState state = last_activation_state();
EXPECT_EQ(mojom::ActivationLevel::kEnabled, state.activation_level);
EXPECT_FALSE(state.filtering_disabled_for_document);
EXPECT_FALSE(state.generic_blocking_rules_disabled);
}
TEST_P(ActivationStateComputingThrottleSubFrameTest,
WhitelistDoesNotApply_CausesActivation) {
NavigateAndCommitMainFrameWithPageActivationState(
GURL("http://disallows-child-to-be-whitelisted.com/"),
mojom::ActivationLevel::kEnabled);
CreateSubframeAndInitTestNavigation(GURL("http://whitelisted.com/"),
last_committed_frame_host(),
last_activation_state());
SimulateStartAndExpectToProceed();
SimulateCommitAndExpectToProceed();
mojom::ActivationState state = last_activation_state();
EXPECT_EQ(mojom::ActivationLevel::kEnabled, state.activation_level);
EXPECT_FALSE(state.filtering_disabled_for_document);
EXPECT_FALSE(state.generic_blocking_rules_disabled);
}
TEST_P(ActivationStateComputingThrottleSubFrameTest,
Whitelisted_DisableDocumentFiltering) {
NavigateAndCommitMainFrameWithPageActivationState(
GURL("http://allow-child-to-be-whitelisted.com/"),
mojom::ActivationLevel::kEnabled);
CreateSubframeAndInitTestNavigation(GURL("http://whitelisted.com/"),
last_committed_frame_host(),
last_activation_state());
SimulateStartAndExpectToProceed();
SimulateCommitAndExpectToProceed();
mojom::ActivationState state = last_activation_state();
EXPECT_TRUE(state.filtering_disabled_for_document);
EXPECT_FALSE(state.generic_blocking_rules_disabled);
EXPECT_EQ(mojom::ActivationLevel::kEnabled, state.activation_level);
}
TEST_P(ActivationStateComputingThrottleSubFrameTest,
Whitelisted_DisablesGenericRules) {
NavigateAndCommitMainFrameWithPageActivationState(
GURL("http://allow-child-to-be-whitelisted.com/"),
mojom::ActivationLevel::kEnabled);
CreateSubframeAndInitTestNavigation(GURL("http://whitelisted-generic.com/"),
last_committed_frame_host(),
last_activation_state());
SimulateStartAndExpectToProceed();
SimulateCommitAndExpectToProceed();
mojom::ActivationState state = last_activation_state();
EXPECT_FALSE(state.filtering_disabled_for_document);
EXPECT_TRUE(state.generic_blocking_rules_disabled);
EXPECT_EQ(mojom::ActivationLevel::kEnabled, state.activation_level);
}
TEST_P(ActivationStateComputingThrottleSubFrameTest, DryRunIsPropagated) {
NavigateAndCommitMainFrameWithPageActivationState(
GURL("http://example.test/"), mojom::ActivationLevel::kDryRun);
EXPECT_EQ(mojom::ActivationLevel::kDryRun,
last_activation_state().activation_level);
CreateSubframeAndInitTestNavigation(GURL("http://example.child/"),
last_committed_frame_host(),
last_activation_state());
SimulateStartAndExpectToProceed();
SimulateRedirectAndExpectToProceed(GURL("http://example.child/?v=1"));
SimulateCommitAndExpectToProceed();
mojom::ActivationState state = last_activation_state();
EXPECT_EQ(mojom::ActivationLevel::kDryRun, state.activation_level);
EXPECT_FALSE(state.filtering_disabled_for_document);
EXPECT_FALSE(state.generic_blocking_rules_disabled);
}
TEST_P(ActivationStateComputingThrottleSubFrameTest,
DryRunWithLoggingIsPropagated) {
mojom::ActivationState page_state;
page_state.activation_level = mojom::ActivationLevel::kDryRun;
page_state.enable_logging = true;
CreateTestNavigationForMainFrame(GURL("http://example.test/"));
SimulateStartAndExpectToProceed();
NotifyPageActivation(page_state);
SimulateCommitAndExpectToProceed();
EXPECT_EQ(mojom::ActivationLevel::kDryRun,
last_activation_state().activation_level);
CreateSubframeAndInitTestNavigation(GURL("http://example.child/"),
last_committed_frame_host(),
last_activation_state());
SimulateStartAndExpectToProceed();
SimulateRedirectAndExpectToProceed(GURL("http://example.child/?v=1"));
SimulateCommitAndExpectToProceed();
mojom::ActivationState state = last_activation_state();
EXPECT_EQ(mojom::ActivationLevel::kDryRun, state.activation_level);
EXPECT_TRUE(state.enable_logging);
EXPECT_FALSE(state.filtering_disabled_for_document);
EXPECT_FALSE(state.generic_blocking_rules_disabled);
}
TEST_P(ActivationStateComputingThrottleSubFrameTest, DisabledStatePropagated) {
NavigateAndCommitMainFrameWithPageActivationState(
GURL("http://allow-child-to-be-whitelisted.com/"),
mojom::ActivationLevel::kEnabled);
CreateSubframeAndInitTestNavigation(GURL("http://whitelisted.com"),
last_committed_frame_host(),
last_activation_state());
SimulateStartAndExpectToProceed();
SimulateCommitAndExpectToProceed();
CreateSubframeAndInitTestNavigation(GURL("http://example.test/"),
last_committed_frame_host(),
last_activation_state());
SimulateStartAndExpectToProceed();
SimulateCommitAndExpectToProceed();
mojom::ActivationState state = last_activation_state();
EXPECT_EQ(mojom::ActivationLevel::kEnabled, state.activation_level);
EXPECT_TRUE(state.filtering_disabled_for_document);
EXPECT_FALSE(state.generic_blocking_rules_disabled);
}
TEST_P(ActivationStateComputingThrottleSubFrameTest, DisabledStatePropagated2) {
NavigateAndCommitMainFrameWithPageActivationState(
GURL("http://allow-child-to-be-whitelisted.com/"),
mojom::ActivationLevel::kEnabled);
CreateSubframeAndInitTestNavigation(
GURL("http://whitelisted-generic-with-disabled-child.com/"),
last_committed_frame_host(), last_activation_state());
SimulateStartAndExpectToProceed();
SimulateCommitAndExpectToProceed();
mojom::ActivationState state = last_activation_state();
EXPECT_FALSE(state.filtering_disabled_for_document);
EXPECT_TRUE(state.generic_blocking_rules_disabled);
CreateSubframeAndInitTestNavigation(GURL("http://whitelisted.com/"),
last_committed_frame_host(),
last_activation_state());
SimulateStartAndExpectToProceed();
SimulateCommitAndExpectToProceed();
state = last_activation_state();
EXPECT_EQ(mojom::ActivationLevel::kEnabled, state.activation_level);
EXPECT_TRUE(state.filtering_disabled_for_document);
EXPECT_TRUE(state.generic_blocking_rules_disabled);
}
TEST_P(ActivationStateComputingThrottleSubFrameTest, DelayMetrics) {
base::HistogramTester histogram_tester;
NavigateAndCommitMainFrameWithPageActivationState(
GURL("http://example.test/"), mojom::ActivationLevel::kEnabled);
mojom::ActivationState state = last_activation_state();
EXPECT_EQ(mojom::ActivationLevel::kEnabled, state.activation_level);
EXPECT_FALSE(state.filtering_disabled_for_document);
const char kActivationDelay[] =
"SubresourceFilter.DocumentLoad.ActivationComputingDelay";
const char kActivationDelayMainFrame[] =
"SubresourceFilter.DocumentLoad.ActivationComputingDelay.MainFrame";
histogram_tester.ExpectTotalCount(kActivationDelay, 1);
histogram_tester.ExpectTotalCount(kActivationDelayMainFrame, 1);
// Subframe activation should not log main frame metrics.
CreateSubframeAndInitTestNavigation(GURL("http://example.test/"),
last_committed_frame_host(),
last_activation_state());
SimulateStartAndExpectToProceed();
SimulateCommitAndExpectToProceed();
histogram_tester.ExpectTotalCount(kActivationDelay, 2);
histogram_tester.ExpectTotalCount(kActivationDelayMainFrame, 1);
// No page activation should imply no delay.
CreateTestNavigationForMainFrame(GURL("http://example.test2/"));
SimulateStartAndExpectToProceed();
SimulateCommitAndExpectToProceed();
state = last_activation_state();
EXPECT_EQ(dryrun_speculation() ? mojom::ActivationLevel::kDryRun
: mojom::ActivationLevel::kDisabled,
state.activation_level);
int extra_activation = dryrun_speculation() ? 1 : 0;
histogram_tester.ExpectTotalCount(kActivationDelay, 2 + extra_activation);
histogram_tester.ExpectTotalCount(kActivationDelayMainFrame,
1 + extra_activation);
}
TEST_P(ActivationStateComputingThrottleSubFrameTest, Speculation) {
// Use the activation performance metric as a proxy for how many times
// activation computation occurred.
base::HistogramTester main_histogram_tester;
// Main frames don't do speculative lookups, a navigation commit should only
// trigger a single ruleset lookup.
CreateTestNavigationForMainFrame(GURL("http://example.test/"));
SimulateStartAndExpectToProceed();
base::RunLoop().RunUntilIdle();
int main_frame_checks = dryrun_speculation() ? 1 : 0;
main_histogram_tester.ExpectTotalCount(kActivationCPU,
ExpectThreadTimers(main_frame_checks));
SimulateRedirectAndExpectToProceed(GURL("http://example.test2/"));
base::RunLoop().RunUntilIdle();
main_frame_checks += dryrun_speculation() ? 1 : 0;
main_histogram_tester.ExpectTotalCount(kActivationCPU,
ExpectThreadTimers(main_frame_checks));
mojom::ActivationState state;
state.activation_level = mojom::ActivationLevel::kEnabled;
NotifyPageActivation(state);
SimulateCommitAndExpectToProceed();
main_frame_checks += dryrun_speculation() ? 0 : 1;
main_histogram_tester.ExpectTotalCount(kActivationCPU,
ExpectThreadTimers(main_frame_checks));
base::HistogramTester sub_histogram_tester;
CreateSubframeAndInitTestNavigation(GURL("http://example.test/"),
last_committed_frame_host(),
last_activation_state());
// For subframes, do a ruleset lookup at the start and every redirect.
SimulateStartAndExpectToProceed();
base::RunLoop().RunUntilIdle();
sub_histogram_tester.ExpectTotalCount(kActivationCPU, ExpectThreadTimers(1));
SimulateRedirectAndExpectToProceed(GURL("http://example.test2/"));
base::RunLoop().RunUntilIdle();
sub_histogram_tester.ExpectTotalCount(kActivationCPU, ExpectThreadTimers(2));
// No ruleset lookup required at commit because we've already checked the
// latest URL.
SimulateCommitAndExpectToProceed();
sub_histogram_tester.ExpectTotalCount(kActivationCPU, ExpectThreadTimers(2));
}
TEST_P(ActivationStateComputingThrottleSubFrameTest, SpeculationWithDelay) {
InitializeRulesetHandles(simple_task_runner());
// Use the activation performance metric as a proxy for how many times
// activation computation occurred.
base::HistogramTester main_histogram_tester;
// Main frames will do speculative lookup only in some cases.
auto simulator = content::NavigationSimulator::CreateRendererInitiated(
GURL("http://example.test/"), main_rfh());
simulator->SetAutoAdvance(false);
simulator->Start();
EXPECT_FALSE(simulator->IsDeferred());
main_histogram_tester.ExpectTotalCount(kActivationCPU, 0);
simulator->Redirect(GURL("http://example.test2/"));
EXPECT_FALSE(simulator->IsDeferred());
main_histogram_tester.ExpectTotalCount(kActivationCPU, 0);
mojom::ActivationState state;
state.activation_level = mojom::ActivationLevel::kEnabled;
NotifyPageActivation(state);
simulator->ReadyToCommit();
EXPECT_TRUE(simulator->IsDeferred());
EXPECT_LT(0u, simple_task_runner()->NumPendingTasks());
simple_task_runner()->RunPendingTasks();
// If speculation was enabled for this test, will do a lookup at start and
// redirect.
main_histogram_tester.ExpectTotalCount(
kActivationCPU, ExpectThreadTimers(dryrun_speculation() ? 2 : 1));
simulator->Wait();
EXPECT_FALSE(simulator->IsDeferred());
EXPECT_EQ(content::NavigationThrottle::PROCEED,
simulator->GetLastThrottleCheckResult());
simulator->Commit();
base::HistogramTester sub_histogram_tester;
auto subframe_simulator =
content::NavigationSimulator::CreateRendererInitiated(
GURL("http://example.test"),
content::RenderFrameHostTester::For(main_rfh())
->AppendChild("subframe"));
subframe_simulator->SetAutoAdvance(false);
set_parent_activation_state(last_activation_state());
// Simulate slow ruleset checks for the subframe, these should not delay the
// navigation until commit time.
subframe_simulator->Start();
EXPECT_FALSE(subframe_simulator->IsDeferred());
sub_histogram_tester.ExpectTotalCount(kActivationCPU, 0);
// Calling redirect should ensure that the throttle does not receive the
// results of the check, but the task to actually perform the check will still
// happen.
subframe_simulator->Redirect(GURL("http://example.test2/"));
EXPECT_FALSE(subframe_simulator->IsDeferred());
sub_histogram_tester.ExpectTotalCount(kActivationCPU, 0);
// Finish the checks dispatched in the start and redirect phase when the
// navigation is ready to commit.
subframe_simulator->ReadyToCommit();
EXPECT_TRUE(subframe_simulator->IsDeferred());
EXPECT_LT(0u, simple_task_runner()->NumPendingTasks());
simple_task_runner()->RunPendingTasks();
subframe_simulator->Wait();
EXPECT_FALSE(subframe_simulator->IsDeferred());
EXPECT_EQ(content::NavigationThrottle::PROCEED,
simulator->GetLastThrottleCheckResult());
sub_histogram_tester.ExpectTotalCount(kActivationCPU, ExpectThreadTimers(2));
}
INSTANTIATE_TEST_CASE_P(,
ActivationStateComputingNavigationThrottleTest,
::testing::Values(true, false));
INSTANTIATE_TEST_CASE_P(,
ActivationStateComputingThrottleSubFrameTest,
::testing::Values(true, false));
} // namespace subresource_filter