| // 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/core/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 |