chromium/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.h"

#include <map>
#include <memory>
#include <string>
#include <vector>

#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "components/blocklist/opt_out_blocklist/opt_out_blocklist_data.h"
#include "components/blocklist/opt_out_blocklist/opt_out_blocklist_delegate.h"
#include "components/blocklist/opt_out_blocklist/opt_out_store.h"
#include "components/heavy_ad_intervention/heavy_ad_blocklist.h"
#include "components/heavy_ad_intervention/heavy_ad_features.h"
#include "components/page_load_metrics/browser/metrics_navigation_throttle.h"
#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
#include "components/page_load_metrics/browser/observers/ad_metrics/frame_tree_data.h"
#include "components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h"
#include "components/page_load_metrics/browser/page_load_metrics_memory_tracker.h"
#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
#include "components/page_load_metrics/browser/page_load_tracker.h"
#include "components/page_load_metrics/common/page_load_metrics_util.h"
#include "components/page_load_metrics/common/test/page_load_metrics_test_util.h"
#include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
#include "components/subresource_filter/content/browser/subresource_filter_test_harness.h"
#include "components/subresource_filter/core/common/load_policy.h"
#include "components/ukm/test_ukm_recorder.h"
#include "content/public/browser/global_request_id.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/navigation_throttle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/fake_local_frame.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_navigation_throttle.h"
#include "content/public/test/test_navigation_throttle_inserter.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/test_utils.h"
#include "content/public/test/web_contents_tester.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "net/base/host_port_pair.h"
#include "services/metrics/public/cpp/metrics_utils.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "third_party/abseil-cpp/absl/utility/utility.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/mojom/frame/frame.mojom.h"
#include "url/gurl.h"

NavigationSimulator;
RenderFrameHost;
RenderFrameHostTester;
TestNavigationThrottle;

namespace page_load_metrics {

namespace {

FrameTreeNodeId;

struct ExpectedFrameBytes {};

struct CreativeOriginTest {};

struct CreativeOriginTestWithThrottling {};

enum class ResourceCached {};
enum class FrameType {};

const base::TimeDelta kParseStartTime =;
const base::TimeDelta kCreativeEligibleToPaintTime =;
const base::TimeDelta kCreativeFCPTime =;
const base::TimeDelta kOtherFrameEligibleToPaintTime =;
const base::TimeDelta kOtherFrameFCPTime =;
const char kAdUrl[] =;
const char kOtherAdUrl[] =;
const char kNonAdUrl[] =;
const char kNonAdUrlSameOrigin[] =;
const char kAllowedUrl[] =;
const char kMemoryMainFrameMaxHistogramId[] =;
const char kMemoryUpdateCountHistogramId[] =;

const int kMaxHeavyAdNetworkBytes =;

// Calls PopulateRequiredTimingFields with |first_eligible_to_paint| and
// |first_contentful_paint| fields temporarily nullified.
void PopulateRequiredTimingFieldsExceptFEtPAndFCP(
    mojom::PageLoadTiming* inout_timing) {}

// Asynchronously cancels the navigation at WillProcessResponse. Before
// cancelling, simulates loading a main frame resource.
class ResourceLoadingCancellingThrottle
    : public content::TestNavigationThrottle {};

// Mock noise provider which always gives a supplied value of noise for the
// heavy ad intervention thresholds.
class MockNoiseProvider
    : public AdsPageLoadMetricsObserver::HeavyAdThresholdNoiseProvider {};

std::string SuffixedHistogram(const std::string& suffix) {}

// Verifies that the histograms match what is expected. Frames that should not
// be recorded (due to zero bytes and zero CPU usage) should be not be
// represented in |ad_frames|.
void TestHistograms(const base::HistogramTester& histograms,
                    const ukm::TestAutoSetUkmRecorder& ukm_recorder,
                    const std::vector<ExpectedFrameBytes>& ad_frames,
                    size_t non_ad_cached_kb,
                    size_t non_ad_uncached_kb) {}

// Waits for an error page for the heavy ad intervention to be navigated to.
class ErrorPageWaiter : public content::WebContentsObserver {};

// Mock frame remote. Processes calls to SendInterventionReport and waits
// for all pending messages to be sent.
class FrameRemoteTester : public content::FakeLocalFrame {};

}  // namespace

class AdsPageLoadMetricsObserverTest
    : public subresource_filter::SubresourceFilterTestHarness,
      public blocklist::OptOutBlocklistDelegate,
      public testing::WithParamInterface<bool> {};

INSTANTIATE_TEST_SUITE_P();

TEST_P(AdsPageLoadMetricsObserverTest, PageWithNoAds) {}

TEST_P(AdsPageLoadMetricsObserverTest, PageWithAds) {}

TEST_P(AdsPageLoadMetricsObserverTest, PageWithAdsButNoAdFrame) {}

TEST_P(AdsPageLoadMetricsObserverTest, AdFrameMimeTypeBytes) {}

TEST_P(AdsPageLoadMetricsObserverTest, ResourceBeforeAdFrameCommits) {}

// Test that the cross-origin ad subframe navigation metric works as it's
// supposed to, triggering a false addition with each ad that's in the same
// origin as the main page, and a true when when the ad has a separate origin.
TEST_P(AdsPageLoadMetricsObserverTest, AdsOriginStatusMetrics) {}

TEST_P(AdsPageLoadMetricsObserverTest, PageWithAdFrameThatRenavigates) {}

TEST_P(AdsPageLoadMetricsObserverTest, PageWithNonAdFrameThatRenavigatesToAd) {}

TEST_P(AdsPageLoadMetricsObserverTest, CountAbortedNavigation) {}

TEST_P(AdsPageLoadMetricsObserverTest, CountAbortedSecondNavigationForFrame) {}

TEST_P(AdsPageLoadMetricsObserverTest, TwoResourceLoadsBeforeCommit) {}

TEST_P(AdsPageLoadMetricsObserverTest, UntaggingAdFrame) {}

TEST_P(AdsPageLoadMetricsObserverTest, MainFrameResource) {}

TEST_P(AdsPageLoadMetricsObserverTest, NoBytesLoaded_NoHistogramsRecorded) {}

// Make sure that ads histograms aren't recorded if the tracker never commits
// (see https://crbug.com/723219).
TEST_P(AdsPageLoadMetricsObserverTest, NoHistogramWithoutCommit) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       SubresourceFilterDisabled_NoAdsDetected) {}

// Frames that are disallowed (and filtered) by the subresource filter should
// not be counted.
TEST_P(AdsPageLoadMetricsObserverTest, FilterAds_DoNotLogMetrics) {}

// Per-frame histograms recorded when root ad frame is destroyed.
TEST_P(AdsPageLoadMetricsObserverTest,
       FrameDestroyed_PerFrameHistogramsLogged) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       FrameAbortsCommitMatchingAllowedRule_FrameTracked) {}

// Tests that a non ad frame that is deleted does not cause any unspecified
// behavior (see https://crbug.com/973954).
TEST_P(AdsPageLoadMetricsObserverTest, NonAdFrameDestroyed_FrameDeleted) {}

// Tests that main frame ad bytes are recorded correctly.
TEST_P(AdsPageLoadMetricsObserverTest, MainFrameAdBytesRecorded) {}

// Tests that memory cache ad bytes are recorded correctly.
TEST_P(AdsPageLoadMetricsObserverTest, MemoryCacheAdBytesRecorded) {}

// UKM metrics for ad page load are recorded correctly.
// TODO(crbug.com/40669132) test is flaky on bots.
TEST_P(AdsPageLoadMetricsObserverTest, AdPageLoadUKM) {}

TEST_P(AdsPageLoadMetricsObserverTest, ZeroBytesZeroCpuUseFrame_NotRecorded) {}

TEST_P(AdsPageLoadMetricsObserverTest, ZeroBytesNonZeroCpuFrame_Recorded) {}

TEST_P(AdsPageLoadMetricsObserverTest, TestCpuTimingMetricsWindowUnactivated) {}

TEST_P(AdsPageLoadMetricsObserverTest, AdDensityDistributionMoments) {}

TEST_P(AdsPageLoadMetricsObserverTest, AdDensityOnPageWithoutAdBytes) {}

TEST_P(AdsPageLoadMetricsObserverTest, TestCpuTimingMetricsWindowedActivated) {}

TEST_P(AdsPageLoadMetricsObserverTest, TestCpuTimingMetricsNoActivation) {}

TEST_P(AdsPageLoadMetricsObserverTest, TestCpuTimingMetricsOnActivation) {}

// Tests that creative origin status is computed as intended, i.e. as the origin
// status of the frame in the ad frame tree that has its first contentful paint
// occur first.
TEST_P(AdsPageLoadMetricsObserverTest, CreativeOriginStatus) {}

// Tests that creative origin status with throttling is computed as intended,
// i.e. as the origin status of the frame in the ad frame tree that has its
// first contentful paint occur first, with throttling status determined by
// whether or not at least one frame in the ad frame tree was unthrottled.
TEST_P(AdsPageLoadMetricsObserverTest, CreativeOriginStatusWithThrottling) {}

// Tests that even when the intervention is not enabled, we still record the
// computed heavy ad types for ad frames
TEST_P(AdsPageLoadMetricsObserverTest, HeavyAdFeatureOff_UMARecorded) {}

TEST_P(AdsPageLoadMetricsObserverTest, HeavyAdNetworkUsage_InterventionFired) {}

// Test that when the page is hidden and the app enters the background, that we
// record histograms, but continue to monitor for CPU heavy ad interventions.
TEST_P(AdsPageLoadMetricsObserverTest, HeavyAdCpuInterventionInBackground) {}

// Test that when the page is hidden and the app enters the background, that we
// record histograms, but continue to monitor for network heavy ad
// interventions.
TEST_P(AdsPageLoadMetricsObserverTest,
       HeavyAdNetworkInterventionInBackgrounded) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       HeavyAdNetworkUsageWithNoise_InterventionFired) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       HeavyAdNetworkUsageLessThanNoisedThreshold_NotFired) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       HeavyAdNetworkUsageLessThanNoisedThreshold_CpuTriggers) {}

TEST_P(AdsPageLoadMetricsObserverTest, HeavyAdTotalCpuUsage_InterventionFired) {}

TEST_P(AdsPageLoadMetricsObserverTest, HeavyAdPeakCpuUsage_InterventionFired) {}

TEST_P(AdsPageLoadMetricsObserverTest, HeavyAdFeatureDisabled_NotFired) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       HeavyAdWithUserGesture_NotConsideredHeavy) {}

// Tests that each configurable unload policy allows the intervention to trigger
// on the correct frames.
TEST_P(AdsPageLoadMetricsObserverTest, HeavyAdPolicyProvided) {}

// Verifies when a user reloads a page with a heavy ad we log it to metrics.
TEST_P(AdsPageLoadMetricsObserverTest, HeavyAdPageReload_MetricsRecorded) {}

// Verifies when a user reloads a page we do not trigger the heavy ad
// intevention.
TEST_P(AdsPageLoadMetricsObserverTest, HeavyAdPageReload_InterventionIgnored) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       HeavyAdPageReloadPrivacyMitigationsDisabled_InterventionAllowed) {}

TEST_P(AdsPageLoadMetricsObserverTest, HeavyAdBlocklistFull_NotFired) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       HeavyAdBlocklistDisabled_InterventionNotBlocked) {}

TEST_P(AdsPageLoadMetricsObserverTest, HeavyAdBlocklist_InterventionReported) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       HeavyAdReportingOnly_ReportSentNoUnload) {}

TEST_P(AdsPageLoadMetricsObserverTest, NoFirstContentfulPaint_NotRecorded) {}

TEST_P(AdsPageLoadMetricsObserverTest, FirstContentfulPaint_Recorded) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       FirstContentfulPaintPostDeviceAuction_Recorded) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       FirstContentfulPaintPostServerAuction_Recorded) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       FirstContentfulPaintPostAbortedOnDeviceAuction_NotRecorded) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       FirstContentfulPaintPostServerAndDeviceAuction_Recorded) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       FirstContentfulPaintOneServerAuctionAndOneDeviceAuction_Recorded) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       MultipleFirstContentfulPaintsInAdWithInOrderIPCs_EarliestUsed) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       MultipleFirstContentfulPaintsInAdWithOutOfOrderIPCs_EarliestUsed) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       MultipleAdFramesWithFirstContentfulPaint) {}

TEST_P(AdsPageLoadMetricsObserverTest,
       FirstContentfulPaintNoAdRootPainted_Recorded) {}

class AdsMemoryMeasurementTest : public AdsPageLoadMetricsObserverTest {};

INSTANTIATE_TEST_SUITE_P();

TEST_P(AdsMemoryMeasurementTest, SingleAdFrame_MaxMemoryBytesRecorded) {}

TEST_P(AdsMemoryMeasurementTest, MultiAdFramesNested_MaxMemoryBytesRecorded) {}

TEST_P(AdsMemoryMeasurementTest,
       MultiAdFramesNonNested_MaxMemoryBytesRecorded) {}

TEST_P(AdsMemoryMeasurementTest, MainFrame_MaxMemoryBytesRecorded) {}

}  // namespace page_load_metrics