blob: a95e2cdcbdc573056169151f2c7ed8583ca0a150 [file] [log] [blame]
// Copyright 2019 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 "chrome/browser/performance_manager/observers/isolation_context_metrics.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "chrome/browser/performance_manager/graph/frame_node_impl.h"
#include "chrome/browser/performance_manager/graph/page_node_impl.h"
#include "chrome/browser/performance_manager/graph/process_node_impl.h"
#include "chrome/browser/performance_manager/test_support/graph_test_harness.h"
namespace performance_manager {
class TestIsolationContextMetrics : public IsolationContextMetrics {
public:
TestIsolationContextMetrics() = default;
~TestIsolationContextMetrics() override = default;
void OnReportingTimerFired() override {
IsolationContextMetrics::OnReportingTimerFired();
if (on_reporting_timer_fired_closure_)
on_reporting_timer_fired_closure_.Run();
}
// Expose some things for testing.
using IsolationContextMetrics::browsing_instance_data_;
using IsolationContextMetrics::BrowsingInstanceData;
using IsolationContextMetrics::BrowsingInstanceDataState;
using IsolationContextMetrics::GetBrowsingInstanceDataState;
using IsolationContextMetrics::GetProcessDataState;
using IsolationContextMetrics::kBrowsingInstanceDataByPageTimeHistogramName;
using IsolationContextMetrics::kBrowsingInstanceDataByTimeHistogramName;
using IsolationContextMetrics::kFramesPerRendererByTimeHistogram;
using IsolationContextMetrics::kProcessDataByProcessHistogramName;
using IsolationContextMetrics::kProcessDataByTimeHistogramName;
using IsolationContextMetrics::kReportingInterval;
using IsolationContextMetrics::kSiteInstancesPerRendererByTimeHistogram;
using IsolationContextMetrics::ProcessData;
using IsolationContextMetrics::ProcessDataState;
// This closure will be invoked when OnReportingTimerFired. Allows the timer
// to be exercised under tests.
base::RepeatingClosure on_reporting_timer_fired_closure_;
};
class IsolationContextMetricsTest : public GraphTestHarness {
public:
IsolationContextMetricsTest()
: GraphTestHarness(
base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED,
base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
~IsolationContextMetricsTest() override = default;
// Bring some types into the namespace for convenience.
using ProcessData = TestIsolationContextMetrics::ProcessData;
using ProcessDataState = TestIsolationContextMetrics::ProcessDataState;
using BrowsingInstanceData =
TestIsolationContextMetrics::BrowsingInstanceData;
using BrowsingInstanceDataState =
TestIsolationContextMetrics::BrowsingInstanceDataState;
// Browsing instance IDs.
static constexpr int32_t kBID1 = 1;
static constexpr int32_t kBID2 = 2;
static constexpr int32_t kBID3 = 3;
// Site instance IDs.
static constexpr int32_t kSID1 = 1;
static constexpr int32_t kSID2 = 2;
static constexpr int32_t kSID3 = 3;
void SetUp() override {
metrics_ = new TestIsolationContextMetrics();
// Sets a valid starting time.
AdvanceClock(base::TimeDelta::FromSeconds(1));
graph()->PassToGraph(base::WrapUnique(metrics_));
}
void ExpectBrowsingInstanceData(int32_t browsing_instance_id,
int page_count,
int visible_page_count) {
auto iter = metrics_->browsing_instance_data_.find(browsing_instance_id);
EXPECT_TRUE(iter != metrics_->browsing_instance_data_.end());
auto& data = iter->second;
EXPECT_EQ(page_count, data.page_count);
EXPECT_EQ(visible_page_count, data.visible_page_count);
}
void ExpectNoBrowsingInstanceData(int32_t browsing_instance_id) {
auto iter = metrics_->browsing_instance_data_.find(browsing_instance_id);
EXPECT_TRUE(iter == metrics_->browsing_instance_data_.end());
}
// A frame node constructor that lets us specify the browsing instance ID and
// site instance ID, but defaults everything else.
TestNodeWrapper<FrameNodeImpl> CreateFrameNode(
ProcessNodeImpl* process_node,
PageNodeImpl* page_node,
int32_t browsing_instance_id,
int32_t site_instance_id,
FrameNodeImpl* parent_frame_node = nullptr) {
return CreateNode<FrameNodeImpl>(
process_node, page_node, parent_frame_node, 0 /* frame_tree_node_id */,
++next_render_frame_id_, base::UnguessableToken::Create(),
browsing_instance_id, site_instance_id);
}
// Advance time until the timer fires.
void FastForwardUntilTimerFires() {
base::RunLoop run_loop;
metrics_->on_reporting_timer_fired_closure_ = run_loop.QuitClosure();
run_loop.Run();
metrics_->on_reporting_timer_fired_closure_ = base::RepeatingClosure();
}
base::HistogramTester histogram_tester_;
TestIsolationContextMetrics* metrics_;
int next_render_frame_id_ = 0;
};
// static
constexpr int32_t IsolationContextMetricsTest::kBID1;
constexpr int32_t IsolationContextMetricsTest::kBID2;
constexpr int32_t IsolationContextMetricsTest::kBID3;
constexpr int32_t IsolationContextMetricsTest::kSID1;
constexpr int32_t IsolationContextMetricsTest::kSID2;
constexpr int32_t IsolationContextMetricsTest::kSID3;
TEST_F(IsolationContextMetricsTest, GetProcessDataState) {
TestIsolationContextMetrics::ProcessData data;
EXPECT_TRUE(data.site_instance_frame_count.empty());
EXPECT_EQ(0, data.multi_frame_site_instance_count);
EXPECT_FALSE(data.has_hosted_multiple_frames_with_same_site_instance);
EXPECT_EQ(task_env().NowTicks(), data.last_reported);
EXPECT_EQ(ProcessDataState::kUndefined,
TestIsolationContextMetrics::GetProcessDataState(&data));
// Make up a site instance with one frame.
data.site_instance_frame_count[kSID1] = 1;
EXPECT_EQ(1u, data.site_instance_frame_count.size());
EXPECT_EQ(ProcessDataState::kOnlyOneFrameExists,
TestIsolationContextMetrics::GetProcessDataState(&data));
// Make up another site instance with one frame.
data.site_instance_frame_count[kSID2] = 1;
EXPECT_EQ(2u, data.site_instance_frame_count.size());
EXPECT_EQ(ProcessDataState::kAllFramesHaveDistinctSiteInstances,
TestIsolationContextMetrics::GetProcessDataState(&data));
// Make one site instance have multiple frames.
data.site_instance_frame_count[kSID1] = 2;
data.multi_frame_site_instance_count = 1;
data.has_hosted_multiple_frames_with_same_site_instance = true;
EXPECT_EQ(2u, data.site_instance_frame_count.size());
EXPECT_EQ(ProcessDataState::kSomeFramesHaveSameSiteInstance,
TestIsolationContextMetrics::GetProcessDataState(&data));
// Make the second site instance have multiple frames.
data.site_instance_frame_count[kSID2] = 2;
data.multi_frame_site_instance_count = 2;
EXPECT_EQ(2u, data.site_instance_frame_count.size());
EXPECT_EQ(ProcessDataState::kSomeFramesHaveSameSiteInstance,
TestIsolationContextMetrics::GetProcessDataState(&data));
// Reduce the first site instance to 1 frame.
data.site_instance_frame_count[kSID1] = 1;
data.multi_frame_site_instance_count = 1;
EXPECT_EQ(2u, data.site_instance_frame_count.size());
EXPECT_EQ(ProcessDataState::kSomeFramesHaveSameSiteInstance,
TestIsolationContextMetrics::GetProcessDataState(&data));
// And reduce the second site instance to 1 frame.
data.site_instance_frame_count[kSID2] = 1;
data.multi_frame_site_instance_count = 0;
EXPECT_EQ(2u, data.site_instance_frame_count.size());
EXPECT_EQ(ProcessDataState::kAllFramesHaveDistinctSiteInstances,
TestIsolationContextMetrics::GetProcessDataState(&data));
// Erase the first site instance.
data.site_instance_frame_count.erase(kSID1);
EXPECT_EQ(1u, data.site_instance_frame_count.size());
EXPECT_EQ(ProcessDataState::kOnlyOneFrameExists,
TestIsolationContextMetrics::GetProcessDataState(&data));
}
TEST_F(IsolationContextMetricsTest, ProcessDataReporting) {
metrics_->StartTimer();
// Create a process that never hosts any frames. It should never contribute
// at all to the metrics.
auto empty_process = CreateNode<ProcessNodeImpl>();
// Create a process that hosts 1 frame from 1 page.
auto process = CreateNode<ProcessNodeImpl>();
auto page = CreateNode<PageNodeImpl>();
auto frame1 = CreateFrameNode(process.get(), page.get(), kBID1, kSID1);
// Expect the ProcessData to exist and be correctly filled out.
auto* data1 = ProcessData::GetOrCreate(process.get());
EXPECT_EQ(1u, data1->site_instance_frame_count.size());
EXPECT_EQ(1, data1->frame_count);
EXPECT_EQ(0, data1->multi_frame_site_instance_count);
EXPECT_FALSE(data1->has_hosted_multiple_frames);
EXPECT_FALSE(data1->has_hosted_multiple_frames_with_same_site_instance);
EXPECT_EQ(task_env().NowTicks(), data1->last_reported);
EXPECT_EQ(ProcessDataState::kOnlyOneFrameExists,
TestIsolationContextMetrics::GetProcessDataState(data1));
// Expect no metrics to have been emitted.
histogram_tester_.ExpectTotalCount(metrics_->kProcessDataByTimeHistogramName,
0);
histogram_tester_.ExpectTotalCount(
metrics_->kProcessDataByProcessHistogramName, 0);
histogram_tester_.ExpectTotalCount(
metrics_->kFramesPerRendererByTimeHistogram, 0);
histogram_tester_.ExpectTotalCount(
metrics_->kSiteInstancesPerRendererByTimeHistogram, 0);
FastForwardUntilTimerFires();
// Expect "by time" metrics to have been emitted.
EXPECT_EQ(task_env().NowTicks(), data1->last_reported);
histogram_tester_.ExpectUniqueSample(
metrics_->kProcessDataByTimeHistogramName,
ProcessDataState::kOnlyOneFrameExists,
metrics_->kReportingInterval.InSeconds());
histogram_tester_.ExpectTotalCount(
metrics_->kProcessDataByProcessHistogramName, 0);
histogram_tester_.ExpectUniqueSample(
metrics_->kFramesPerRendererByTimeHistogram, 1,
metrics_->kReportingInterval.InSeconds());
histogram_tester_.ExpectUniqueSample(
metrics_->kSiteInstancesPerRendererByTimeHistogram, 1,
metrics_->kReportingInterval.InSeconds());
{
// Advance time and add another frame to a new site instance, as a child
// of |frame1|.
AdvanceClock(base::TimeDelta::FromSeconds(1));
auto frame2 =
CreateFrameNode(process.get(), page.get(), kBID1, kSID2, frame1.get());
EXPECT_EQ(2u, data1->site_instance_frame_count.size());
EXPECT_EQ(2, data1->frame_count);
EXPECT_EQ(0, data1->multi_frame_site_instance_count);
EXPECT_TRUE(data1->has_hosted_multiple_frames);
EXPECT_FALSE(data1->has_hosted_multiple_frames_with_same_site_instance);
EXPECT_EQ(ProcessDataState::kAllFramesHaveDistinctSiteInstances,
TestIsolationContextMetrics::GetProcessDataState(data1));
// Expect metrics to have been reported on the state change.
EXPECT_EQ(task_env().NowTicks(), data1->last_reported);
histogram_tester_.ExpectUniqueSample(
metrics_->kProcessDataByTimeHistogramName,
ProcessDataState::kOnlyOneFrameExists,
metrics_->kReportingInterval.InSeconds() + 1);
histogram_tester_.ExpectTotalCount(
metrics_->kProcessDataByProcessHistogramName, 0);
histogram_tester_.ExpectBucketCount(
metrics_->kFramesPerRendererByTimeHistogram, 1,
metrics_->kReportingInterval.InSeconds());
histogram_tester_.ExpectBucketCount(
metrics_->kFramesPerRendererByTimeHistogram, 2, 1);
histogram_tester_.ExpectBucketCount(
metrics_->kSiteInstancesPerRendererByTimeHistogram, 1,
metrics_->kReportingInterval.InSeconds());
histogram_tester_.ExpectBucketCount(
metrics_->kSiteInstancesPerRendererByTimeHistogram, 2, 1);
// Advance time.
AdvanceClock(base::TimeDelta::FromSeconds(1));
}
// The second frame will be destroyed as it goes out of scope. Expect another
// flush of metrics.
EXPECT_EQ(task_env().NowTicks(), data1->last_reported);
histogram_tester_.ExpectTotalCount(
metrics_->kProcessDataByTimeHistogramName,
metrics_->kReportingInterval.InSeconds() + 2);
histogram_tester_.ExpectBucketCount(
metrics_->kProcessDataByTimeHistogramName,
ProcessDataState::kAllFramesHaveDistinctSiteInstances, 1);
histogram_tester_.ExpectBucketCount(
metrics_->kProcessDataByTimeHistogramName,
ProcessDataState::kOnlyOneFrameExists,
metrics_->kReportingInterval.InSeconds() + 1);
histogram_tester_.ExpectTotalCount(
metrics_->kProcessDataByProcessHistogramName, 0);
histogram_tester_.ExpectBucketCount(
metrics_->kFramesPerRendererByTimeHistogram, 1,
metrics_->kReportingInterval.InSeconds() + 1);
histogram_tester_.ExpectBucketCount(
metrics_->kFramesPerRendererByTimeHistogram, 2, 1);
histogram_tester_.ExpectBucketCount(
metrics_->kSiteInstancesPerRendererByTimeHistogram, 1,
metrics_->kReportingInterval.InSeconds() + 1);
histogram_tester_.ExpectBucketCount(
metrics_->kSiteInstancesPerRendererByTimeHistogram, 2, 1);
{
// Advance time and add another frame to the same site instance, as a child
// of |frame1|.
AdvanceClock(base::TimeDelta::FromSeconds(1));
auto frame2 =
CreateFrameNode(process.get(), page.get(), kBID1, kSID1, frame1.get());
EXPECT_EQ(1u, data1->site_instance_frame_count.size());
EXPECT_EQ(2, data1->frame_count);
EXPECT_EQ(1, data1->multi_frame_site_instance_count);
EXPECT_TRUE(data1->has_hosted_multiple_frames);
EXPECT_TRUE(data1->has_hosted_multiple_frames_with_same_site_instance);
EXPECT_EQ(ProcessDataState::kSomeFramesHaveSameSiteInstance,
TestIsolationContextMetrics::GetProcessDataState(data1));
// Expect metrics to have been reported on the state change.
EXPECT_EQ(task_env().NowTicks(), data1->last_reported);
histogram_tester_.ExpectTotalCount(
metrics_->kProcessDataByTimeHistogramName,
metrics_->kReportingInterval.InSeconds() + 3);
histogram_tester_.ExpectBucketCount(
metrics_->kProcessDataByTimeHistogramName,
ProcessDataState::kAllFramesHaveDistinctSiteInstances, 1);
histogram_tester_.ExpectBucketCount(
metrics_->kProcessDataByTimeHistogramName,
ProcessDataState::kOnlyOneFrameExists,
metrics_->kReportingInterval.InSeconds() + 2);
histogram_tester_.ExpectTotalCount(
metrics_->kProcessDataByProcessHistogramName, 0);
histogram_tester_.ExpectBucketCount(
metrics_->kFramesPerRendererByTimeHistogram, 1,
metrics_->kReportingInterval.InSeconds() + 1);
histogram_tester_.ExpectBucketCount(
metrics_->kFramesPerRendererByTimeHistogram, 2, 2);
histogram_tester_.ExpectBucketCount(
metrics_->kSiteInstancesPerRendererByTimeHistogram, 1,
metrics_->kReportingInterval.InSeconds() + 2);
histogram_tester_.ExpectBucketCount(
metrics_->kSiteInstancesPerRendererByTimeHistogram, 2, 1);
// Advance time.
AdvanceClock(base::TimeDelta::FromSeconds(1));
}
// The second frame will be destroyed as it goes out of scope. Expect another
// flush of metrics.
EXPECT_EQ(task_env().NowTicks(), data1->last_reported);
histogram_tester_.ExpectTotalCount(
metrics_->kProcessDataByTimeHistogramName,
metrics_->kReportingInterval.InSeconds() + 4);
histogram_tester_.ExpectBucketCount(
metrics_->kProcessDataByTimeHistogramName,
ProcessDataState::kAllFramesHaveDistinctSiteInstances, 1);
histogram_tester_.ExpectBucketCount(
metrics_->kProcessDataByTimeHistogramName,
ProcessDataState::kSomeFramesHaveSameSiteInstance, 1);
histogram_tester_.ExpectBucketCount(
metrics_->kProcessDataByTimeHistogramName,
ProcessDataState::kOnlyOneFrameExists,
metrics_->kReportingInterval.InSeconds() + 2);
histogram_tester_.ExpectTotalCount(
metrics_->kProcessDataByProcessHistogramName, 0);
histogram_tester_.ExpectBucketCount(
metrics_->kFramesPerRendererByTimeHistogram, 1,
metrics_->kReportingInterval.InSeconds() + 2);
histogram_tester_.ExpectBucketCount(
metrics_->kFramesPerRendererByTimeHistogram, 2, 2);
histogram_tester_.ExpectBucketCount(
metrics_->kSiteInstancesPerRendererByTimeHistogram, 1,
metrics_->kReportingInterval.InSeconds() + 3);
histogram_tester_.ExpectBucketCount(
metrics_->kSiteInstancesPerRendererByTimeHistogram, 2, 1);
// Destroy the other frame and the page. No metrics should be flushed.
{
base::HistogramTester tester;
frame1.reset();
page.reset();
tester.ExpectTotalCount(metrics_->kProcessDataByTimeHistogramName, 0);
tester.ExpectTotalCount(metrics_->kProcessDataByProcessHistogramName, 0);
}
// Finally, destroy the process. This should flush metrics to the
// "by process" histogram.
{
base::HistogramTester tester;
process.reset();
tester.ExpectTotalCount(metrics_->kProcessDataByTimeHistogramName, 0);
tester.ExpectUniqueSample(metrics_->kProcessDataByProcessHistogramName,
ProcessDataState::kSomeFramesHaveSameSiteInstance,
1);
}
// Ensure that the empty process never ended up having ProcessData created
// for it.
EXPECT_FALSE(ProcessData::Get(empty_process.get()));
// Destroy the empty process and expect no new metrics.
{
base::HistogramTester tester;
empty_process.reset();
tester.ExpectTotalCount(metrics_->kProcessDataByTimeHistogramName, 0);
tester.ExpectTotalCount(metrics_->kProcessDataByProcessHistogramName, 0);
}
}
TEST_F(IsolationContextMetricsTest, GetBrowsingInstanceDataState) {
TestIsolationContextMetrics::BrowsingInstanceData data;
EXPECT_EQ(0, data.page_count);
EXPECT_EQ(0, data.visible_page_count);
EXPECT_EQ(task_env().NowTicks(), data.last_reported);
EXPECT_EQ(BrowsingInstanceDataState::kUndefined,
TestIsolationContextMetrics::GetBrowsingInstanceDataState(&data));
// Add a page.
data.page_count = 1;
EXPECT_EQ(BrowsingInstanceDataState::kSinglePageBackground,
TestIsolationContextMetrics::GetBrowsingInstanceDataState(&data));
// Make it foreground.
data.visible_page_count = 1;
EXPECT_EQ(BrowsingInstanceDataState::kSinglePageForeground,
TestIsolationContextMetrics::GetBrowsingInstanceDataState(&data));
// Add another background page.
data.page_count = 2;
EXPECT_EQ(BrowsingInstanceDataState::kMultiPageSomeForeground,
TestIsolationContextMetrics::GetBrowsingInstanceDataState(&data));
// Add another background page.
data.page_count = 3;
EXPECT_EQ(BrowsingInstanceDataState::kMultiPageSomeForeground,
TestIsolationContextMetrics::GetBrowsingInstanceDataState(&data));
// Make all the pages background.
data.visible_page_count = 0;
EXPECT_EQ(BrowsingInstanceDataState::kMultiPageBackground,
TestIsolationContextMetrics::GetBrowsingInstanceDataState(&data));
}
TEST_F(IsolationContextMetricsTest, BrowsingInstanceDataReporting) {
metrics_->StartTimer();
// Create a process that hosts 1 frame from 1 page.
auto process = CreateNode<ProcessNodeImpl>();
auto page1 = CreateNode<PageNodeImpl>();
auto frame1 = CreateFrameNode(process.get(), page1.get(), kBID1, kSID1);
frame1->SetIsCurrent(true);
ExpectBrowsingInstanceData(kBID1, 1, 0);
// Advance time and add another page with 1 frame in a different browsing
// instance, but in the same process.
AdvanceClock(base::TimeDelta::FromSeconds(1));
auto page2 = CreateNode<PageNodeImpl>();
auto frame2 = CreateFrameNode(process.get(), page2.get(), kBID2, kSID2);
frame2->SetIsCurrent(true);
ExpectBrowsingInstanceData(kBID1, 1, 0);
ExpectBrowsingInstanceData(kBID2, 1, 0);
// Expect no samples, as the state didn't change; it's yet another
// background page in yet another browsing instance.
histogram_tester_.ExpectTotalCount(
metrics_->kBrowsingInstanceDataByTimeHistogramName, 0);
histogram_tester_.ExpectTotalCount(
metrics_->kBrowsingInstanceDataByPageTimeHistogramName, 0);
// Make the first page visible. This should drive a state change. Two
// seconds has passed for the first browsing instance, and 1 second for the
// second browsing instance.
{
AdvanceClock(base::TimeDelta::FromSeconds(1));
base::HistogramTester tester;
page1->SetIsVisible(true);
ExpectBrowsingInstanceData(kBID1, 1, 1);
ExpectBrowsingInstanceData(kBID2, 1, 0);
tester.ExpectUniqueSample(
metrics_->kBrowsingInstanceDataByTimeHistogramName,
BrowsingInstanceDataState::kSinglePageBackground, 3);
tester.ExpectUniqueSample(
metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
BrowsingInstanceDataState::kSinglePageBackground, 3);
}
FastForwardUntilTimerFires();
// The first BI has been background for the entire time, the second one
// was background for 1 second, and foreground for the rest of the time.
histogram_tester_.ExpectTotalCount(
metrics_->kBrowsingInstanceDataByTimeHistogramName,
metrics_->kReportingInterval.InSeconds() * 2 - 1);
histogram_tester_.ExpectBucketCount(
metrics_->kBrowsingInstanceDataByTimeHistogramName,
BrowsingInstanceDataState::kSinglePageBackground,
metrics_->kReportingInterval.InSeconds() + 1);
histogram_tester_.ExpectBucketCount(
metrics_->kBrowsingInstanceDataByTimeHistogramName,
BrowsingInstanceDataState::kSinglePageForeground,
metrics_->kReportingInterval.InSeconds() - 2);
histogram_tester_.ExpectTotalCount(
metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
metrics_->kReportingInterval.InSeconds() * 2 - 1);
histogram_tester_.ExpectBucketCount(
metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
BrowsingInstanceDataState::kSinglePageBackground,
metrics_->kReportingInterval.InSeconds() + 1);
histogram_tester_.ExpectBucketCount(
metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
BrowsingInstanceDataState::kSinglePageForeground,
metrics_->kReportingInterval.InSeconds() - 2);
// Destroy the foreground page. This should trigger one more second worth
// of reports for both pages.
{
AdvanceClock(base::TimeDelta::FromSeconds(1));
base::HistogramTester tester;
frame2.reset();
ExpectBrowsingInstanceData(kBID1, 1, 1);
ExpectNoBrowsingInstanceData(kBID2);
tester.ExpectTotalCount(metrics_->kBrowsingInstanceDataByTimeHistogramName,
2);
tester.ExpectBucketCount(metrics_->kBrowsingInstanceDataByTimeHistogramName,
BrowsingInstanceDataState::kSinglePageBackground,
1);
tester.ExpectBucketCount(metrics_->kBrowsingInstanceDataByTimeHistogramName,
BrowsingInstanceDataState::kSinglePageForeground,
1);
tester.ExpectTotalCount(
metrics_->kBrowsingInstanceDataByPageTimeHistogramName, 2);
tester.ExpectBucketCount(
metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
BrowsingInstanceDataState::kSinglePageBackground, 1);
tester.ExpectBucketCount(
metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
BrowsingInstanceDataState::kSinglePageForeground, 1);
}
// Create a second frame again, but in the same browsing instance as the first
// one. This creates a transition to a multi-page instance, so metrics are
// emitted. There was 1 second of the first page being visible in its own
// browsing instance.
{
AdvanceClock(base::TimeDelta::FromSeconds(1));
base::HistogramTester tester;
frame2 = CreateFrameNode(process.get(), page2.get(), kBID1, kSID2);
frame2->SetIsCurrent(true);
ExpectBrowsingInstanceData(kBID1, 2, 1);
tester.ExpectUniqueSample(
metrics_->kBrowsingInstanceDataByTimeHistogramName,
BrowsingInstanceDataState::kSinglePageForeground, 1);
tester.ExpectUniqueSample(
metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
BrowsingInstanceDataState::kSinglePageForeground, 1);
}
// Make the first page invisible again, and expect a transition. There was
// 1 second of the two pages being in a visible multi-page browsing instance.
{
AdvanceClock(base::TimeDelta::FromSeconds(1));
base::HistogramTester tester;
page1->SetIsVisible(false);
ExpectBrowsingInstanceData(kBID1, 2, 0);
tester.ExpectUniqueSample(
metrics_->kBrowsingInstanceDataByTimeHistogramName,
BrowsingInstanceDataState::kMultiPageSomeForeground, 1);
tester.ExpectUniqueSample(
metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
BrowsingInstanceDataState::kMultiPageSomeForeground, 2);
}
// Tear down all of the pages and expect the metrics to flush. There was 1
// more second of a multi-page browsing instance in the background.
{
AdvanceClock(base::TimeDelta::FromSeconds(1));
base::HistogramTester tester;
frame1.reset();
frame2.reset();
page1.reset();
page2.reset();
ExpectNoBrowsingInstanceData(kBID1);
tester.ExpectUniqueSample(
metrics_->kBrowsingInstanceDataByTimeHistogramName,
BrowsingInstanceDataState::kMultiPageBackground, 1);
tester.ExpectUniqueSample(
metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
BrowsingInstanceDataState::kMultiPageBackground, 2);
}
}
} // namespace performance_manager