blob: 19cc831b089d3554a6d69728f2f6f6637eeb72c1 [file] [log] [blame]
// Copyright 2021 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.
#ifndef CONTENT_BROWSER_BACK_FORWARD_CACHE_BROWSERTEST_H_
#define CONTENT_BROWSER_BACK_FORWARD_CACHE_BROWSERTEST_H_
#include <memory>
#include "base/compiler_specific.h"
#include "base/feature_list.h"
#include "base/hash/hash.h"
#include "base/test/scoped_feature_list.h"
#include "components/ukm/test_ukm_recorder.h"
#include "content/browser/renderer_host/page_lifecycle_state_manager.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/renderer_host/render_frame_host_manager.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_mock_cert_verifier.h"
#include "content/test/content_browser_test_utils_internal.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace content {
using NotRestoredReasons =
BackForwardCacheCanStoreDocumentResult::NotRestoredReasons;
using NotRestoredReason = BackForwardCacheMetrics::NotRestoredReason;
// Match RenderFrameHostImpl* that are in the BackForwardCache.
MATCHER(InBackForwardCache, "") {
return arg->IsInBackForwardCache();
}
// Match RenderFrameDeletedObserver* which observed deletion of the RenderFrame.
MATCHER(Deleted, "") {
return arg->deleted();
}
// Helper function to pass an initializer list to the EXPECT_THAT macro. This is
// indeed the identity function.
std::initializer_list<RenderFrameHostImpl*> Elements(
std::initializer_list<RenderFrameHostImpl*> t);
namespace {
// hash for std::unordered_map.
struct FeatureHash {
size_t operator()(base::Feature feature) const {
return base::FastHash(feature.name);
}
};
// compare operator for std::unordered_map.
struct FeatureEqualOperator {
bool operator()(base::Feature feature1, base::Feature feature2) const {
return std::strcmp(feature1.name, feature2.name) == 0;
}
};
} // namespace
// Test about the BackForwardCache.
class BackForwardCacheBrowserTest
: public ContentBrowserTest,
public WebContentsObserver,
public BackForwardCacheMetrics::TestObserver {
public:
BackForwardCacheBrowserTest();
~BackForwardCacheBrowserTest() override;
// TestObserver:
void NotifyNotRestoredReasons(
std::unique_ptr<BackForwardCacheCanStoreTreeResult> tree_result) override;
protected:
using UkmMetrics = ukm::TestUkmRecorder::HumanReadableUkmMetrics;
// Disables checking metrics that are recorded recardless of the domains. By
// default, this class' Expect* function checks the metrics both for the
// specific domain and for all domains at the same time. In the case when the
// test results need to be different, call this function.
void DisableCheckingMetricsForAllSites();
void SetUpCommandLine(base::CommandLine* command_line) override;
void SetUpInProcessBrowserTestFixture() override;
void TearDownInProcessBrowserTestFixture() override;
void SetupFeaturesAndParameters();
void EnableFeatureAndSetParams(base::Feature feature,
std::string param_name,
std::string param_value);
void DisableFeature(base::Feature feature);
void SetUpOnMainThread() override;
void TearDownOnMainThread() override;
WebContentsImpl* web_contents() const;
RenderFrameHostImpl* current_frame_host();
RenderFrameHostManager* render_frame_host_manager();
std::string DepictFrameTree(FrameTreeNode* node);
bool HistogramContainsIntValue(base::HistogramBase::Sample sample,
std::vector<base::Bucket> histogram_values);
// Tests that the observed outcomes match the current expected outcomes
// without adding any new expected outcomes.
void ExpectOutcomeDidNotChange(base::Location location);
void ExpectRestored(base::Location location);
void ExpectNotRestored(
std::vector<BackForwardCacheMetrics::NotRestoredReason> not_restored,
std::vector<blink::scheduler::WebSchedulerTrackedFeature> block_listed,
const std::vector<ShouldSwapBrowsingInstance>& not_swapped,
const std::vector<BackForwardCache::DisabledReason>&
disabled_for_render_frame_host,
const std::vector<uint64_t>& disallow_activation,
base::Location location);
void ExpectNotRestoredDidNotChange(base::Location location);
void ExpectBlocklistedFeature(
blink::scheduler::WebSchedulerTrackedFeature feature,
base::Location location);
void ExpectBrowsingInstanceNotSwappedReason(ShouldSwapBrowsingInstance reason,
base::Location location);
void ExpectEvictedAfterCommitted(
std::vector<BackForwardCacheMetrics::EvictedAfterDocumentRestoredReason>
reasons,
base::Location location);
void EvictByJavaScript(RenderFrameHostImpl* rfh);
void StartRecordingEvents(RenderFrameHostImpl* rfh);
void MatchEventList(RenderFrameHostImpl* rfh,
base::ListValue list,
base::Location location = base::Location::Current());
// Creates a minimal HTTPS server, accessible through https_server().
// Returns a pointer to the server.
net::EmbeddedTestServer* CreateHttpsServer();
net::EmbeddedTestServer* https_server();
void ExpectTotalCount(base::StringPiece name,
base::HistogramBase::Count count);
template <typename T>
void ExpectBucketCount(base::StringPiece name,
T sample,
base::HistogramBase::Count expected_count) {
histogram_tester_.ExpectBucketCount(name, sample, expected_count);
}
// Do not fail this test if a message from a renderer arrives at the browser
// for a cached page.
void DoNotFailForUnexpectedMessagesWhileCached();
// Navigates to a page at |page_url| with an img element with src set to
// "image.png".
RenderFrameHostImpl* NavigateToPageWithImage(const GURL& page_url);
void AcquireKeyboardLock(RenderFrameHostImpl* rfh);
void ReleaseKeyboardLock(RenderFrameHostImpl* rfh);
// Start a navigation to |url| but block it on an error. If |history_offset|
// is not 0, then the navigation will be a history navigation and this will
// assert that the URL after navigation is |url|.
void NavigateAndBlock(GURL url, int history_offset);
static testing::Matcher<BackForwardCacheCanStoreDocumentResult>
MatchesDocumentResult(testing::Matcher<NotRestoredReasons> not_stored,
BlockListedFeatures block_listed);
// Access the tree result of NotRestoredReason for the last main frame
// navigation.
BackForwardCacheCanStoreTreeResult* GetTreeResult() {
return tree_result_.get();
}
void InstallUnloadHandlerOnMainFrame();
void InstallUnloadHandlerOnSubFrame();
EvalJsResult GetUnloadRunCount();
bool IsUnloadAllowedToEnterBackForwardCache();
base::HistogramTester histogram_tester_;
bool same_site_back_forward_cache_enabled_ = true;
bool skip_same_site_if_unload_exists_ = false;
const int kMaxBufferedBytesPerProcess = 10000;
const base::TimeDelta kGracePeriodToFinishLoading = base::Seconds(5);
private:
void AddSampleToBuckets(std::vector<base::Bucket>* buckets,
base::HistogramBase::Sample sample);
// Adds a new outcome to the set of expected outcomes (restored or not) and
// tests that it occurred.
void ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome outcome,
base::Location location);
void ExpectReasons(
std::vector<BackForwardCacheMetrics::NotRestoredReason> not_restored,
std::vector<blink::scheduler::WebSchedulerTrackedFeature> block_listed,
const std::vector<ShouldSwapBrowsingInstance>& not_swapped,
const std::vector<BackForwardCache::DisabledReason>&
disabled_for_render_frame_host,
const std::vector<uint64_t>& disallow_activation,
base::Location location);
void ExpectNotRestoredReasons(
std::vector<BackForwardCacheMetrics::NotRestoredReason> reasons,
base::Location location);
void ExpectBlocklistedFeatures(
std::vector<blink::scheduler::WebSchedulerTrackedFeature> features,
base::Location location);
void ExpectDisabledWithReasons(
const std::vector<BackForwardCache::DisabledReason>& reasons,
base::Location location);
void ExpectDisallowActivationReasons(const std::vector<uint64_t>& reasons,
base::Location location);
void ExpectBrowsingInstanceNotSwappedReasons(
const std::vector<ShouldSwapBrowsingInstance>& reasons,
base::Location location);
content::ContentMockCertVerifier mock_cert_verifier_;
base::test::ScopedFeatureList feature_list_;
FrameTreeVisualizer visualizer_;
std::vector<base::Bucket> expected_outcomes_;
std::vector<base::Bucket> expected_not_restored_;
std::vector<base::Bucket> expected_blocklisted_features_;
std::vector<base::Bucket> expected_disabled_reasons_;
std::vector<base::Bucket> expected_disallow_activation_reasons_;
std::vector<base::Bucket> expected_browsing_instance_not_swapped_reasons_;
std::vector<base::Bucket> expected_eviction_after_committing_;
std::unique_ptr<net::EmbeddedTestServer> https_server_;
std::unordered_map<base::Feature,
std::map<std::string, std::string>,
FeatureHash,
FeatureEqualOperator>
features_with_params_;
std::vector<base::Feature> disabled_features_;
std::vector<UkmMetrics> expected_ukm_outcomes_;
std::vector<UkmMetrics> expected_ukm_not_restored_reasons_;
std::unique_ptr<ukm::TestAutoSetUkmRecorder> ukm_recorder_;
// Store the tree result of NotRestoredReasons for the last main frame
// navigation.
std::unique_ptr<BackForwardCacheCanStoreTreeResult> tree_result_;
// Indicates whether metrics for all sites regardless of the domains are
// checked or not.
bool check_all_sites_ = true;
// Whether we should fail the test if a message arrived at the browser from a
// renderer for a bfcached page.
bool fail_for_unexpected_messages_while_cached_ = true;
};
[[nodiscard]] bool WaitForDOMContentLoaded(RenderFrameHostImpl* rfh);
class HighCacheSizeBackForwardCacheBrowserTest
: public BackForwardCacheBrowserTest {
protected:
void SetUpCommandLine(base::CommandLine* command_line) override;
// The number of pages the BackForwardCache can hold per tab.
// The number 5 was picked since Android ASAN trybot failed to keep more than
// 6 pages in memory.
const size_t kBackForwardCacheSize = 5;
};
// An implementation of PageLifecycleStateManager::TestDelegate for testing.
class PageLifecycleStateManagerTestDelegate
: public PageLifecycleStateManager::TestDelegate {
public:
explicit PageLifecycleStateManagerTestDelegate(
PageLifecycleStateManager* manager);
~PageLifecycleStateManagerTestDelegate() override;
// Waits for the renderer finishing to set the state of being in back/forward
// cache.
void WaitForInBackForwardCacheAck();
void OnStoreInBackForwardCacheSent(base::OnceClosure cb);
void OnDisableJsEvictionSent(base::OnceClosure cb);
void OnRestoreFromBackForwardCacheSent(base::OnceClosure cb);
private:
// PageLifecycleStateManager::TestDelegate:
void OnLastAcknowledgedStateChanged(
const blink::mojom::PageLifecycleState& old_state,
const blink::mojom::PageLifecycleState& new_state) override;
void OnUpdateSentToRenderer(
const blink::mojom::PageLifecycleState& new_state) override;
void OnDeleted() override;
raw_ptr<PageLifecycleStateManager> manager_;
base::OnceClosure store_in_back_forward_cache_sent_;
base::OnceClosure store_in_back_forward_cache_ack_received_;
base::OnceClosure restore_from_back_forward_cache_sent_;
base::OnceClosure disable_eviction_sent_;
};
// Gets the value of a key in local storage by evaluating JS.
EvalJsResult GetLocalStorage(RenderFrameHostImpl* rfh, std::string key);
} // namespace content
#endif // CONTENT_BROWSER_BACK_FORWARD_CACHE_BROWSERTEST_H_