blob: 48beace188d29c1f760f8d4ea26c5afcc2b517c3 [file] [log] [blame]
// Copyright 2018 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/resource_coordinator/tab_activity_watcher.h"
#include <memory>
#include "base/macros.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_tick_clock.h"
#include "chrome/browser/resource_coordinator/tab_lifecycle_unit.h"
#include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h"
#include "chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h"
#include "chrome/browser/resource_coordinator/tab_manager_features.h"
#include "chrome/browser/resource_coordinator/tab_metrics_event.pb.h"
#include "chrome/browser/resource_coordinator/time.h"
#include "chrome/browser/resource_coordinator/utils.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_ukm_test_helper.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/ukm/test_ukm_recorder.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/web_contents_tester.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gtest/include/gtest/gtest.h"
using ukm::builders::TabManager_TabMetrics;
using ukm::builders::TabManager_Background_ForegroundedOrClosed;
namespace resource_coordinator {
namespace {
const char* kTabMetricsEntryName = TabManager_TabMetrics::kEntryName;
const char* kFOCEntryName =
TabManager_Background_ForegroundedOrClosed::kEntryName;
// The default metric values for a tab.
const UkmMetricMap kBasicMetricValues({
{TabManager_TabMetrics::kHasBeforeUnloadHandlerName, 0},
{TabManager_TabMetrics::kHasFormEntryName, 0},
{TabManager_TabMetrics::kIsPinnedName, 0},
{TabManager_TabMetrics::kKeyEventCountName, 0},
{TabManager_TabMetrics::kNavigationEntryCountName, 1},
{TabManager_TabMetrics::kSiteEngagementScoreName, 0},
{TabManager_TabMetrics::kTouchEventCountName, 0},
{TabManager_TabMetrics::kWasRecentlyAudibleName, 0},
// TODO(michaelpg): Test TabManager_TabMetrics::kMouseEventCountName.
// Depending on the test environment, the browser may receive mouse events
// from the mouse cursor during tests, so we currently don't check this
// metric.
});
// These parameters don't affect logging.
const bool kCheckNavigationSuccess = true;
const int64_t kIdShift = 1 << 16;
} // namespace
// Tests UKM entries generated by TabActivityWatcher/TabMetricsLogger as tabs
// are backgrounded and foregrounded.
// Modeled after the TabActivityWatcherTest unit tests, these browser tests
// focus on end-to-end testing from the first browser launch onwards, verifying
// that window and browser commands are really triggering the paths that lead
// to UKM logs.
class TabActivityWatcherTest : public InProcessBrowserTest {
protected:
TabActivityWatcherTest() {
scoped_feature_list_.InitAndEnableFeatureWithParameters(
features::kTabRanker,
{{"disable_background_log_with_TabRanker", "false"}});
}
// TabActivityWatcherTest:
void PreRunTestOnMainThread() override {
InProcessBrowserTest::PreRunTestOnMainThread();
ukm_entry_checker_ = std::make_unique<UkmEntryChecker>();
test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
}
void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();
ASSERT_TRUE(embedded_test_server()->Start());
test_urls_ = {embedded_test_server()->GetURL("/title1.html"),
embedded_test_server()->GetURL("/title2.html"),
embedded_test_server()->GetURL("/title3.html")};
// Browser created in BrowserMain() shouldn't result in a background tab
// being logged.
EXPECT_EQ(0u, ukm_entry_checker_->NumEntries(kTabMetricsEntryName));
}
void TearDown() override {
EXPECT_EQ(0,
ukm_entry_checker_->NumNewEntriesRecorded(kTabMetricsEntryName));
InProcessBrowserTest::TearDown();
}
protected:
void ExpectNewForegroundedEntry(const GURL& url) {
// TODO(michaelpg): Add an interactive_ui_test to test MRU metrics since
// they can be affected by window activation.
UkmMetricMap expected_metrics = {
{TabManager_Background_ForegroundedOrClosed::kIsForegroundedName, 1},
};
ukm_entry_checker_->ExpectNewEntry(kFOCEntryName, url, expected_metrics);
}
void ExpectNewClosedEntry(const GURL& url) {
UkmMetricMap expected_metrics = {
{TabManager_Background_ForegroundedOrClosed::kIsForegroundedName, 0},
};
ukm_entry_checker_->ExpectNewEntry(kFOCEntryName, url, expected_metrics);
}
// Uses test_ukm_recorder_ to check new event metrics including:
// (1) the number of UkmEntry with given event_name should be equal to |size|.
// (2) the newest entry should have source_url equal to |url|.
// (3) the newest entry should have source_id equal to |source_id| if
// |source_id| is not 0 (skip for the case of 0).
// (4) the newest entry should contain all metrics in |expected_metrics|.
// Also returns the source_id of the newest entry.
ukm::SourceId ExpectNewEntryWithSourceId(const GURL& url,
const std::string& event_name,
size_t num_entries,
const UkmMetricMap& expected_metrics,
ukm::SourceId source_id = 0) {
const std::vector<const ukm::mojom::UkmEntry*> entries =
test_ukm_recorder_->GetEntriesByName(event_name);
// Check size.
EXPECT_EQ(entries.size(), num_entries);
const ukm::mojom::UkmEntry* entry = entries.back();
// Check source_url.
test_ukm_recorder_->ExpectEntrySourceHasUrl(entry, url);
// Check source_id.
if (source_id != 0) {
EXPECT_EQ(source_id, entry->source_id);
}
// Check expected_metrics.
for (const auto& metric : expected_metrics) {
test_ukm_recorder_->ExpectEntryMetric(entry, metric.first,
*metric.second);
}
return entry->source_id;
}
// Gets the latest metric value from the event with given |metric_name|.
int64_t GetLatestMetricValue(const std::string& event_name,
const std::string& metric_name) {
const std::vector<const ukm::mojom::UkmEntry*> entries =
test_ukm_recorder_->GetEntriesByName(event_name);
// Check nonemptiness.
EXPECT_FALSE(entries.empty());
return *(test_ukm_recorder_->GetEntryMetric(entries.back(), metric_name));
}
// Logs tab@i.
void LogTabFeaturesAt(const int i) {
resource_coordinator::LifecycleUnit* lifecycle_unit =
GetTabLifecycleUnitSource()->GetTabLifecycleUnit(
browser()->tab_strip_model()->GetWebContentsAt(i));
std::vector<resource_coordinator::LifecycleUnit*> lifecycle_unit_vec = {
lifecycle_unit};
// Calling LogAndMaybeSortLifecycleUnitWithTabRanker will log the
// TabFeatures.
TabActivityWatcher::GetInstance()
->LogAndMaybeSortLifecycleUnitWithTabRanker(&lifecycle_unit_vec);
}
std::vector<GURL> test_urls_;
std::unique_ptr<UkmEntryChecker> ukm_entry_checker_;
std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_;
private:
base::test::ScopedFeatureList scoped_feature_list_;
DISALLOW_COPY_AND_ASSIGN(TabActivityWatcherTest);
};
class TabActivityWatcherTestWithBackgroundLogDisabled
: public TabActivityWatcherTest {
public:
TabActivityWatcherTestWithBackgroundLogDisabled() {
feature_list_.InitAndEnableFeatureWithParameters(
features::kTabRanker,
{{"disable_background_log_with_TabRanker", "true"}});
}
private:
base::test::ScopedFeatureList feature_list_;
};
// Tests calculating tab scores using the Tab Ranker.
IN_PROC_BROWSER_TEST_F(TabActivityWatcherTestWithBackgroundLogDisabled,
CalculateReactivationScore) {
// Use test clock so tabs have non-zero backgrounded times.
base::SimpleTestTickClock test_clock;
ScopedSetTickClockForTesting scoped_set_tick_clock_for_testing(&test_clock);
test_clock.Advance(base::TimeDelta::FromMinutes(1));
AddTabAtIndex(1, test_urls_[0], ui::PAGE_TRANSITION_LINK);
test_clock.Advance(base::TimeDelta::FromMinutes(1));
browser()->tab_strip_model()->ActivateTabAt(
0, {TabStripModel::GestureType::kOther});
test_clock.Advance(base::TimeDelta::FromMinutes(1));
// A background tab is scored successfully.
base::Optional<float> background_score =
TabActivityWatcher::GetInstance()->CalculateReactivationScore(
browser()->tab_strip_model()->GetWebContentsAt(1));
EXPECT_TRUE(background_score.has_value());
// Foreground tabs are not modeled by the tab ranker and should not be scored.
base::Optional<float> foreground_score =
TabActivityWatcher::GetInstance()->CalculateReactivationScore(
browser()->tab_strip_model()->GetWebContentsAt(0));
EXPECT_FALSE(foreground_score.has_value());
CloseBrowserSynchronously(browser());
}
// Tests TabMetrics UKMs logged by creating and switching between tabs.
IN_PROC_BROWSER_TEST_F(TabActivityWatcherTest, SwitchTabs) {
const GURL kTabUrls[] = {
GURL(), // "about:blank" tab doesn't have a UKM source.
test_urls_[0], test_urls_[1],
};
EXPECT_EQ(0u, ukm_entry_checker_->NumEntries(kTabMetricsEntryName));
UkmMetricMap expected_metrics = kBasicMetricValues;
// Adding a new foreground tab logs the previously active tab.
AddTabAtIndex(1, kTabUrls[1], ui::PAGE_TRANSITION_LINK);
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, kTabUrls[0],
expected_metrics);
}
AddTabAtIndex(2, kTabUrls[2], ui::PAGE_TRANSITION_LINK);
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, kTabUrls[1],
expected_metrics);
}
// Switching to another tab logs the previously active tab.
browser()->tab_strip_model()->ActivateTabAt(
0, {TabStripModel::GestureType::kOther});
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, kTabUrls[2],
expected_metrics);
ExpectNewForegroundedEntry(kTabUrls[0]);
}
browser()->tab_strip_model()->ActivateTabAt(
1, {TabStripModel::GestureType::kOther});
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, kTabUrls[0],
expected_metrics);
ExpectNewForegroundedEntry(kTabUrls[1]);
}
// Closing the window doesn't log more TabMetrics UKMs (tested in TearDown()).
CloseBrowserSynchronously(browser());
{
SCOPED_TRACE("");
ExpectNewClosedEntry(kTabUrls[2]);
ExpectNewClosedEntry(kTabUrls[0]);
}
}
// Tests that switching between multiple windows doesn't affect TabMetrics UKMs.
// This is a sanity check; window activation shouldn't make any difference to
// what we log. If we needed to actually test different behavior based on window
// focus, we would run these tests in interactive_ui_tests.
IN_PROC_BROWSER_TEST_F(TabActivityWatcherTest, SwitchWindows) {
Browser* browser_2 = CreateBrowser(browser()->profile());
EXPECT_EQ(0, ukm_entry_checker_->NumNewEntriesRecorded(kTabMetricsEntryName));
AddTabAtIndexToBrowser(browser(), 1, test_urls_[0], ui::PAGE_TRANSITION_LINK,
kCheckNavigationSuccess);
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, GURL(),
kBasicMetricValues);
}
AddTabAtIndexToBrowser(browser_2, 1, test_urls_[1], ui::PAGE_TRANSITION_LINK,
kCheckNavigationSuccess);
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, GURL(),
kBasicMetricValues);
}
browser()->window()->Activate();
browser_2->window()->Activate();
EXPECT_EQ(0, ukm_entry_checker_->NumNewEntriesRecorded(kTabMetricsEntryName));
// Closing each window doesn't log more TabMetrics UKMs.
CloseBrowserSynchronously(browser_2);
CloseBrowserSynchronously(browser());
}
// Tests page with a beforeunload handler.
IN_PROC_BROWSER_TEST_F(TabActivityWatcherTest, BeforeUnloadHandler) {
// Navigate to a page with a beforeunload handler.
GURL url(embedded_test_server()->GetURL("/beforeunload.html"));
ui_test_utils::NavigateToURL(browser(), url);
// Log metrics for the first tab by switching to a new tab.
AddTabAtIndex(1, test_urls_[0], ui::PAGE_TRANSITION_LINK);
UkmMetricMap expected_metrics = kBasicMetricValues;
expected_metrics[TabManager_TabMetrics::kHasBeforeUnloadHandlerName] = 1;
expected_metrics[TabManager_TabMetrics::kNavigationEntryCountName] = 2;
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, url,
expected_metrics);
}
// Sanity check: the new tab doesn't have a beforeunload handler.
browser()->tab_strip_model()->ActivateTabAt(
0, {TabStripModel::GestureType::kOther});
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, test_urls_[0],
kBasicMetricValues);
}
}
// Tests events logged when dragging a tab between browsers.
IN_PROC_BROWSER_TEST_F(TabActivityWatcherTest, TabDrag) {
// This test will navigate 3 tabs.
const GURL kBrowserStartUrl = test_urls_[0];
const GURL kBrowser2StartUrl = test_urls_[1];
const GURL kDraggedTabUrl = test_urls_[2];
Browser* browser_2 = CreateBrowser(browser()->profile());
ui_test_utils::NavigateToURL(browser(), kBrowserStartUrl);
ui_test_utils::NavigateToURL(browser_2, kBrowser2StartUrl);
// Adding a tab backgrounds the original tab in the window.
AddTabAtIndexToBrowser(browser(), 1, kDraggedTabUrl, ui::PAGE_TRANSITION_LINK,
kCheckNavigationSuccess);
{
SCOPED_TRACE("");
UkmMetricMap expected_metrics_1 = kBasicMetricValues;
expected_metrics_1[TabManager_TabMetrics::kNavigationEntryCountName] = 2;
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, kBrowserStartUrl,
expected_metrics_1);
}
// "Drag" the new tab out of its browser.
content::WebContents* dragged_contents =
browser()->tab_strip_model()->GetWebContentsAt(1);
std::unique_ptr<content::WebContents> owned_dragged_contents =
browser()->tab_strip_model()->DetachWebContentsAt(1);
dragged_contents->WasHidden();
// The other tab in the browser is now foregrounded.
ExpectNewForegroundedEntry(kBrowserStartUrl);
// "Drop" the tab into the other browser. This requires showing and
// reactivating the tab, but to the user, it never leaves the foreground, so
// we don't log a foregrounded event for it.
browser_2->tab_strip_model()->InsertWebContentsAt(
1, std::move(owned_dragged_contents), TabStripModel::ADD_NONE);
dragged_contents->WasShown();
browser_2->tab_strip_model()->ActivateTabAt(
1, {TabStripModel::GestureType::kOther});
EXPECT_EQ(0, ukm_entry_checker_->NumNewEntriesRecorded(kFOCEntryName));
// The first tab in this window was backgrounded when the new one was
// inserted.
{
SCOPED_TRACE("");
UkmMetricMap expected_metrics_2 = kBasicMetricValues;
expected_metrics_2[TabManager_TabMetrics::kNavigationEntryCountName] = 2;
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, kBrowser2StartUrl,
expected_metrics_2);
}
// Closing the window with 2 tabs means we log the backgrounded tab as closed.
CloseBrowserSynchronously(browser_2);
ExpectNewClosedEntry(kBrowser2StartUrl);
CloseBrowserSynchronously(browser());
EXPECT_EQ(0, ukm_entry_checker_->NumNewEntriesRecorded(kTabMetricsEntryName));
EXPECT_EQ(0, ukm_entry_checker_->NumNewEntriesRecorded(kFOCEntryName));
}
class TabActivityWatcherTestWithBackgroundLogEnabled
: public TabActivityWatcherTest {
public:
TabActivityWatcherTestWithBackgroundLogEnabled() {
feature_list_.InitAndEnableFeatureWithParameters(
features::kTabRanker,
{{"number_of_oldest_tabs_to_log_with_TabRanker", "1"},
{"disable_background_log_with_TabRanker", "false"}});
}
private:
base::test::ScopedFeatureList feature_list_;
};
// Tests discarded tab is recorded correctly.
IN_PROC_BROWSER_TEST_F(TabActivityWatcherTestWithBackgroundLogEnabled,
DiscardedTabGetsPreviousSourceId) {
ukm::SourceId ukm_source_id_for_tab_0 = 0;
ukm::SourceId ukm_source_id_for_tab_1 = 0;
ui_test_utils::NavigateToURL(browser(), test_urls_[0]);
EXPECT_EQ(0u, ukm_entry_checker_->NumEntries(kTabMetricsEntryName));
// Adding a new foreground tab logs the previously active tab.
AddTabAtIndex(1, test_urls_[1], ui::PAGE_TRANSITION_LINK);
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(
kTabMetricsEntryName, test_urls_[0],
{{TabManager_TabMetrics::kNavigationEntryCountName, 2}});
ukm_source_id_for_tab_0 = ExpectNewEntryWithSourceId(
test_urls_[0], kTabMetricsEntryName, 1,
{{TabManager_TabMetrics::kNavigationEntryCountName, 2}});
}
// Discard the first tab.
content::WebContents* first_contents =
browser()->tab_strip_model()->GetWebContentsAt(0);
resource_coordinator::GetTabLifecycleUnitSource()
->GetTabLifecycleUnitExternal(first_contents)
->DiscardTab(LifecycleUnitDiscardReason::URGENT);
// Logs tab@0.
LogTabFeaturesAt(0);
{
SCOPED_TRACE("");
// tab feature of tab@0 should be logged correctly.
UkmMetricMap expected_tab_feature_values = kBasicMetricValues;
expected_tab_feature_values[TabManager_TabMetrics::kMRUIndexName] = 1;
expected_tab_feature_values
[TabManager_TabMetrics::kNumReactivationBeforeName] = 0;
expected_tab_feature_values[TabManager_TabMetrics::kTotalTabCountName] = 2;
expected_tab_feature_values[TabManager_TabMetrics::kWindowTabCountName] = 2;
expected_tab_feature_values[TabManager_TabMetrics::kLabelIdName] =
2 * kIdShift;
expected_tab_feature_values[TabManager_TabMetrics::kQueryIdName] =
1 * kIdShift;
expected_tab_feature_values
[TabManager_TabMetrics::kNavigationEntryCountName] = 2;
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, test_urls_[0],
expected_tab_feature_values);
ExpectNewEntryWithSourceId(test_urls_[0], kTabMetricsEntryName, 2,
expected_tab_feature_values,
ukm_source_id_for_tab_0);
}
// Switching to first tab logs a forgrounded event for test_urls_[0]
// and a backgrounded event for test_urls_[1].
browser()->tab_strip_model()->ActivateTabAt(
0, {TabStripModel::GestureType::kOther});
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, test_urls_[1],
kBasicMetricValues);
ukm_source_id_for_tab_1 = ExpectNewEntryWithSourceId(
test_urls_[1], kTabMetricsEntryName, 3, kBasicMetricValues);
ExpectNewEntryWithSourceId(
test_urls_[0], kFOCEntryName, 1,
{{TabManager_Background_ForegroundedOrClosed::kIsForegroundedName, 1},
{TabManager_Background_ForegroundedOrClosed::kIsDiscardedName, 1}},
ukm_source_id_for_tab_0);
}
// Discard the second tab.
content::WebContents* second_content =
browser()->tab_strip_model()->GetWebContentsAt(1);
resource_coordinator::GetTabLifecycleUnitSource()
->GetTabLifecycleUnitExternal(second_content)
->DiscardTab(LifecycleUnitDiscardReason::URGENT);
CloseBrowserSynchronously(browser());
{
SCOPED_TRACE("");
ExpectNewEntryWithSourceId(
test_urls_[1], kFOCEntryName, 2,
{{TabManager_Background_ForegroundedOrClosed::kIsForegroundedName, 0},
{TabManager_Background_ForegroundedOrClosed::kIsDiscardedName, 1}},
ukm_source_id_for_tab_1);
}
}
// Tests that all window metrics are logged with correct value which are
// different from their default values in TabFeatures.
IN_PROC_BROWSER_TEST_F(TabActivityWatcherTest, AllWindowMetricsArePopulated) {
ui_test_utils::NavigateToURL(browser(), test_urls_[0]);
// Adding a new foreground tab logs the previously active tab.
AddTabAtIndex(1, test_urls_[1], ui::PAGE_TRANSITION_LINK);
{
SCOPED_TRACE("");
UkmMetricMap expected_metrics = {
{"WindowShowState", metrics::WindowMetricsEvent::SHOW_STATE_NORMAL},
{"WindowTabCount", 2},
{"WindowType", metrics::WindowMetricsEvent::TYPE_TABBED},
};
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, test_urls_[0],
expected_metrics);
}
}
class TabActivityWatcherTestWithBackgroundLogDisabledAndOnlyOneOldestTab
: public TabActivityWatcherTest {
public:
TabActivityWatcherTestWithBackgroundLogDisabledAndOnlyOneOldestTab() {
// Set Feature params for this test.
// (1) background log is disabled, so that only query time logging and
// corresponding labels should be logged.
// (2) number of oldest tabs to log is set to 1, so that only 1 tab should
// be logged.
feature_list_.InitAndEnableFeatureWithParameters(
features::kTabRanker,
{{"number_of_oldest_tabs_to_log_with_TabRanker", "1"},
{"disable_background_log_with_TabRanker", "true"}});
}
private:
base::test::ScopedFeatureList feature_list_;
};
// Test the query time logging is correct.
IN_PROC_BROWSER_TEST_F(
TabActivityWatcherTestWithBackgroundLogDisabledAndOnlyOneOldestTab,
LogOldestNTabFeatures) {
// Use test clock so tabs have non-zero backgrounded times.
base::SimpleTestTickClock test_clock;
ScopedSetTickClockForTesting scoped_set_tick_clock_for_testing(&test_clock);
test_clock.Advance(base::TimeDelta::FromMinutes(1));
ui_test_utils::NavigateToURL(browser(), test_urls_[0]);
// Insert the tab@1.
AddTabAtIndex(1, test_urls_[1], ui::PAGE_TRANSITION_LINK);
test_clock.Advance(base::TimeDelta::FromMinutes(1));
// Insert the tab@2.
AddTabAtIndex(2, test_urls_[2], ui::PAGE_TRANSITION_LINK);
test_clock.Advance(base::TimeDelta::FromMinutes(1));
// Activate tab@0.
browser()->tab_strip_model()->ActivateTabAt(
0, {TabStripModel::GestureType::kOther});
test_clock.Advance(base::TimeDelta::FromMinutes(1));
// No tab metrics should be logged till now.
EXPECT_EQ(0, ukm_entry_checker_->NumNewEntriesRecorded(kTabMetricsEntryName));
// Logs tab@1.
LogTabFeaturesAt(1);
{
SCOPED_TRACE("");
// tab feature of tab@1 should be logged correctly.
UkmMetricMap expected_tab_feature_values = kBasicMetricValues;
expected_tab_feature_values[TabManager_TabMetrics::kMRUIndexName] = 2;
expected_tab_feature_values
[TabManager_TabMetrics::kNumReactivationBeforeName] = 0;
expected_tab_feature_values[TabManager_TabMetrics::kTotalTabCountName] = 3;
expected_tab_feature_values[TabManager_TabMetrics::kWindowTabCountName] = 3;
expected_tab_feature_values[TabManager_TabMetrics::kLabelIdName] =
2 * kIdShift;
expected_tab_feature_values[TabManager_TabMetrics::kQueryIdName] =
1 * kIdShift;
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, test_urls_[1],
expected_tab_feature_values);
}
// Reactivate tab@1 should log a ForegroundedOrClosed event with LabelId as
// label_id_1.
browser()->tab_strip_model()->ActivateTabAt(
1, {TabStripModel::GestureType::kOther});
test_clock.Advance(base::TimeDelta::FromMinutes(1));
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(
kFOCEntryName, test_urls_[1],
{{TabManager_Background_ForegroundedOrClosed::kIsForegroundedName, 1},
{TabManager_Background_ForegroundedOrClosed::kLabelIdName,
2 * kIdShift},
{TabManager_Background_ForegroundedOrClosed::kIsDiscardedName, 0}});
}
// Logs tab@2.
LogTabFeaturesAt(2);
{
SCOPED_TRACE("");
// tab feature of tab@2 should be logged correctly.
UkmMetricMap expected_tab_feature_values = kBasicMetricValues;
expected_tab_feature_values[TabManager_TabMetrics::kMRUIndexName] = 2;
expected_tab_feature_values
[TabManager_TabMetrics::kNumReactivationBeforeName] = 0;
expected_tab_feature_values[TabManager_TabMetrics::kTotalTabCountName] = 3;
expected_tab_feature_values[TabManager_TabMetrics::kWindowTabCountName] = 3;
expected_tab_feature_values[TabManager_TabMetrics::kLabelIdName] =
4 * kIdShift;
expected_tab_feature_values[TabManager_TabMetrics::kQueryIdName] =
3 * kIdShift;
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, test_urls_[2],
expected_tab_feature_values);
}
// No ForegroundedOrClosed event is logged for tab@1 because it's foregrounded
CloseBrowserSynchronously(browser());
{
SCOPED_TRACE("");
// Close Browser should log a ForegroundedOrClosed event for tab@2 with
// correct label_id.
ukm_entry_checker_->ExpectNewEntry(
kFOCEntryName, test_urls_[2],
{{TabManager_Background_ForegroundedOrClosed::kIsForegroundedName, 0},
{TabManager_Background_ForegroundedOrClosed::kLabelIdName,
4 * kIdShift},
{TabManager_Background_ForegroundedOrClosed::kIsDiscardedName, 0}});
}
}
// Tests label id is recorded correctly for discarded tabs.
IN_PROC_BROWSER_TEST_F(
TabActivityWatcherTestWithBackgroundLogDisabledAndOnlyOneOldestTab,
DiscardedTabGetsCorrectLabelId) {
ui_test_utils::NavigateToURL(browser(), test_urls_[0]);
AddTabAtIndex(1, test_urls_[1], ui::PAGE_TRANSITION_LINK);
// No TabMetrics events are logged till now.
EXPECT_EQ(0u, ukm_entry_checker_->NumEntries(kTabMetricsEntryName));
// Logs tab@0.
LogTabFeaturesAt(0);
{
SCOPED_TRACE("");
UkmMetricMap expected_metrics = kBasicMetricValues;
expected_metrics[TabManager_TabMetrics::kNavigationEntryCountName] = 2;
expected_metrics[TabManager_TabMetrics::kLabelIdName] = 2 * kIdShift;
expected_metrics[TabManager_TabMetrics::kQueryIdName] = 1 * kIdShift;
// tab feature of tab@0 should be logged correctly.
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, test_urls_[0],
expected_metrics);
}
// Discard the first tab.
content::WebContents* first_contents =
browser()->tab_strip_model()->GetWebContentsAt(0);
resource_coordinator::GetTabLifecycleUnitSource()
->GetTabLifecycleUnitExternal(first_contents)
->DiscardTab(LifecycleUnitDiscardReason::URGENT);
// Switching to first tab logs a forgrounded event for test_urls_[0].
browser()->tab_strip_model()->ActivateTabAt(
0, {TabStripModel::GestureType::kOther});
{
SCOPED_TRACE("");
UkmMetricMap expected_metrics = {
{TabManager_Background_ForegroundedOrClosed::kIsForegroundedName, 1},
{TabManager_Background_ForegroundedOrClosed::kIsDiscardedName, 1},
{TabManager_Background_ForegroundedOrClosed::kLabelIdName,
2 * kIdShift}};
ukm_entry_checker_->ExpectNewEntry(kFOCEntryName, test_urls_[0],
expected_metrics);
}
// Logs tab@1.
LogTabFeaturesAt(1);
{
SCOPED_TRACE("");
// tab feature of tab@1 should be logged correctly.
UkmMetricMap expected_metrics = kBasicMetricValues;
expected_metrics[TabManager_TabMetrics::kLabelIdName] = 4 * kIdShift;
expected_metrics[TabManager_TabMetrics::kQueryIdName] = 3 * kIdShift;
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, test_urls_[1],
expected_metrics);
}
// Discard the second tab.
content::WebContents* second_content =
browser()->tab_strip_model()->GetWebContentsAt(1);
resource_coordinator::GetTabLifecycleUnitSource()
->GetTabLifecycleUnitExternal(second_content)
->DiscardTab(LifecycleUnitDiscardReason::URGENT);
CloseBrowserSynchronously(browser());
{
SCOPED_TRACE("");
UkmMetricMap expected_metrics = {
{TabManager_Background_ForegroundedOrClosed::kIsForegroundedName, 0},
{TabManager_Background_ForegroundedOrClosed::kIsDiscardedName, 1},
{TabManager_Background_ForegroundedOrClosed::kLabelIdName,
4 * kIdShift}};
ukm_entry_checker_->ExpectNewEntry(kFOCEntryName, test_urls_[1],
expected_metrics);
}
}
// Tests label_id is incremented if the LogOldestNTabFeatures is called second
// times without logging the label first.
IN_PROC_BROWSER_TEST_F(
TabActivityWatcherTestWithBackgroundLogDisabledAndOnlyOneOldestTab,
TabsAlreadyHaveLabelIdGetIncrementalLabelIds) {
ui_test_utils::NavigateToURL(browser(), test_urls_[0]);
AddTabAtIndex(1, test_urls_[1], ui::PAGE_TRANSITION_LINK);
// No TabMetrics events are logged till now.
EXPECT_EQ(0u, ukm_entry_checker_->NumEntries(kTabMetricsEntryName));
// Logs tab@0.
LogTabFeaturesAt(0);
{
SCOPED_TRACE("");
UkmMetricMap expected_metrics = kBasicMetricValues;
expected_metrics[TabManager_TabMetrics::kNavigationEntryCountName] = 2;
expected_metrics[TabManager_TabMetrics::kLabelIdName] = 2 * kIdShift;
expected_metrics[TabManager_TabMetrics::kQueryIdName] = 1 * kIdShift;
// tab feature of tab@0 should be logged correctly.
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, test_urls_[0],
expected_metrics);
}
LogTabFeaturesAt(0);
{
SCOPED_TRACE("");
UkmMetricMap expected_metrics = kBasicMetricValues;
expected_metrics[TabManager_TabMetrics::kNavigationEntryCountName] = 2;
expected_metrics[TabManager_TabMetrics::kLabelIdName] = 2 * kIdShift + 1;
expected_metrics[TabManager_TabMetrics::kQueryIdName] = 3 * kIdShift;
// tab feature of tab@0 should be logged correctly.
ukm_entry_checker_->ExpectNewEntry(kTabMetricsEntryName, test_urls_[0],
expected_metrics);
}
}
} // namespace resource_coordinator