blob: 1ba5e9d62d0700371c0841492317a31b152b8793 [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_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/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* kEntryName = 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 kIsUserGesture = true;
const bool kCheckNavigationSuccess = true;
} // namespace
class TabActivityWatcherTest : public InProcessBrowserTest {
protected:
TabActivityWatcherTest() = default;
~TabActivityWatcherTest() override = default;
// InProcessBrowserTest:
void SetUpOnMainThread() override {
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")};
}
std::vector<GURL> test_urls_;
private:
DISALLOW_COPY_AND_ASSIGN(TabActivityWatcherTest);
};
// Tests calculating tab scores using the Tab Ranker.
IN_PROC_BROWSER_TEST_F(TabActivityWatcherTest, 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, kIsUserGesture);
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 only oldest N tabs are scored.
IN_PROC_BROWSER_TEST_F(TabActivityWatcherTest,
OnlyCalculateReactivationScoreForOldestN) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeatureWithParameters(
features::kTabRanker,
{{"number_of_oldest_tabs_to_score_with_TabRanker", "1"}});
// 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));
AddTabAtIndex(2, test_urls_[0], ui::PAGE_TRANSITION_LINK);
test_clock.Advance(base::TimeDelta::FromMinutes(1));
browser()->tab_strip_model()->ActivateTabAt(0, kIsUserGesture);
test_clock.Advance(base::TimeDelta::FromMinutes(1));
// tab@1 is scored successfully.
base::Optional<float> tab_1 =
TabActivityWatcher::GetInstance()->CalculateReactivationScore(
browser()->tab_strip_model()->GetWebContentsAt(1));
EXPECT_TRUE(tab_1.has_value());
// tab@2 is not scored successfully since it's not in the OldestN.
base::Optional<float> tab_2 =
TabActivityWatcher::GetInstance()->CalculateReactivationScore(
browser()->tab_strip_model()->GetWebContentsAt(2));
EXPECT_FALSE(tab_2.has_value());
CloseBrowserSynchronously(browser());
}
// 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 TabActivityWatcherUkmTest : public TabActivityWatcherTest {
protected:
TabActivityWatcherUkmTest() = default;
// TabActivityWatcherTest:
void PreRunTestOnMainThread() override {
TabActivityWatcherTest::PreRunTestOnMainThread();
ukm_entry_checker_ = std::make_unique<UkmEntryChecker>();
test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
}
void SetUpOnMainThread() override {
// Browser created in BrowserMain() shouldn't result in a background tab
// being logged.
EXPECT_EQ(0u, ukm_entry_checker_->NumEntries(kEntryName));
TabActivityWatcherTest::SetUpOnMainThread();
}
void TearDown() override {
EXPECT_EQ(0, ukm_entry_checker_->NumNewEntriesRecorded(kEntryName));
TabActivityWatcherTest::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));
}
std::unique_ptr<UkmEntryChecker> ukm_entry_checker_;
std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_;
private:
DISALLOW_COPY_AND_ASSIGN(TabActivityWatcherUkmTest);
};
// Tests TabMetrics UKMs logged by creating and switching between tabs.
IN_PROC_BROWSER_TEST_F(TabActivityWatcherUkmTest, 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(kEntryName));
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(kEntryName, kTabUrls[0],
expected_metrics);
}
AddTabAtIndex(2, kTabUrls[2], ui::PAGE_TRANSITION_LINK);
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(kEntryName, kTabUrls[1],
expected_metrics);
}
// Switching to another tab logs the previously active tab.
browser()->tab_strip_model()->ActivateTabAt(0, kIsUserGesture);
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(kEntryName, kTabUrls[2],
expected_metrics);
ExpectNewForegroundedEntry(kTabUrls[0]);
}
browser()->tab_strip_model()->ActivateTabAt(1, kIsUserGesture);
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(kEntryName, 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(TabActivityWatcherUkmTest, SwitchWindows) {
Browser* browser_2 = CreateBrowser(browser()->profile());
EXPECT_EQ(0, ukm_entry_checker_->NumNewEntriesRecorded(kEntryName));
AddTabAtIndexToBrowser(browser(), 1, test_urls_[0], ui::PAGE_TRANSITION_LINK,
kCheckNavigationSuccess);
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(kEntryName, GURL(), kBasicMetricValues);
}
AddTabAtIndexToBrowser(browser_2, 1, test_urls_[1], ui::PAGE_TRANSITION_LINK,
kCheckNavigationSuccess);
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(kEntryName, GURL(), kBasicMetricValues);
}
browser()->window()->Activate();
browser_2->window()->Activate();
EXPECT_EQ(0, ukm_entry_checker_->NumNewEntriesRecorded(kEntryName));
// 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(TabActivityWatcherUkmTest, 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(kEntryName, url, expected_metrics);
}
// Sanity check: the new tab doesn't have a beforeunload handler.
browser()->tab_strip_model()->ActivateTabAt(0, kIsUserGesture);
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(kEntryName, test_urls_[0],
kBasicMetricValues);
}
}
// Tests events logged when dragging a tab between browsers.
IN_PROC_BROWSER_TEST_F(TabActivityWatcherUkmTest, 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(kEntryName, 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, kIsUserGesture);
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(kEntryName, 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(kEntryName));
EXPECT_EQ(0, ukm_entry_checker_->NumNewEntriesRecorded(kFOCEntryName));
}
// Tests discarded tab is recorded correctly.
IN_PROC_BROWSER_TEST_F(TabActivityWatcherUkmTest,
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(kEntryName));
// 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(
kEntryName, test_urls_[0],
{{TabManager_TabMetrics::kNavigationEntryCountName, 2}});
ukm_source_id_for_tab_0 = ExpectNewEntryWithSourceId(
test_urls_[0], kEntryName, 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();
// 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, kIsUserGesture);
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(kEntryName, test_urls_[1],
kBasicMetricValues);
ukm_source_id_for_tab_1 = ExpectNewEntryWithSourceId(
test_urls_[1], kEntryName, 2, 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();
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(TabActivityWatcherUkmTest,
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(kEntryName, test_urls_[0],
expected_metrics);
}
}
// Test the query time logging is correct.
IN_PROC_BROWSER_TEST_F(TabActivityWatcherUkmTest, LogOldestNTabFeatures) {
// 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.
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeatureWithParameters(
features::kTabRanker,
{{"number_of_oldest_tabs_to_log_with_TabRanker", "1"},
{"disable_background_log_with_TabRanker", "true"}});
// 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, kIsUserGesture);
test_clock.Advance(base::TimeDelta::FromMinutes(1));
// Foregrounded event should be logged for tab@0
EXPECT_EQ(1, ukm_entry_checker_->NumNewEntriesRecorded(kFOCEntryName));
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(
kFOCEntryName, test_urls_[0],
{{TabManager_Background_ForegroundedOrClosed::kIsForegroundedName, 1},
{TabManager_Background_ForegroundedOrClosed::kLabelIdName, 0},
{TabManager_Background_ForegroundedOrClosed::kIsDiscardedName, 0}});
}
// No tab metrics should be logged till now.
EXPECT_EQ(0, ukm_entry_checker_->NumNewEntriesRecorded(kEntryName));
// Call LogQueryTimeTabFeatures should log the oldest tab which is tab@1.
TabActivityWatcher::GetInstance()->LogOldestNTabFeatures();
{
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;
expected_tab_feature_values[TabManager_TabMetrics::kQueryIdName] = 1;
ukm_entry_checker_->ExpectNewEntry(kEntryName, 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, kIsUserGesture);
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},
{TabManager_Background_ForegroundedOrClosed::kIsDiscardedName, 0}});
}
// Call LogQueryTimeTabFeatures should log the oldest tab which is tab@2.
TabActivityWatcher::GetInstance()->LogOldestNTabFeatures();
{
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;
expected_tab_feature_values[TabManager_TabMetrics::kQueryIdName] = 3;
ukm_entry_checker_->ExpectNewEntry(kEntryName, 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},
{TabManager_Background_ForegroundedOrClosed::kIsDiscardedName, 0}});
// Close Browser should log a ForegroundedOrClosed event for tab@0 with
// label_id == 0 because when we score it, it was not in the oldest N list.
ukm_entry_checker_->ExpectNewEntry(
kFOCEntryName, test_urls_[0],
{{TabManager_Background_ForegroundedOrClosed::kIsForegroundedName, 0},
{TabManager_Background_ForegroundedOrClosed::kLabelIdName, 0},
{TabManager_Background_ForegroundedOrClosed::kIsDiscardedName, 0}});
}
}
// Tests label id is recorded correctly for discarded tabs.
IN_PROC_BROWSER_TEST_F(TabActivityWatcherUkmTest,
DiscardedTabGetsCorrectLabelId) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeatureWithParameters(
features::kTabRanker,
{{"number_of_oldest_tabs_to_log_with_TabRanker", "1"},
{"disable_background_log_with_TabRanker", "true"}});
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(kEntryName));
// Log tab_0.
TabActivityWatcher::GetInstance()->LogOldestNTabFeatures();
{
SCOPED_TRACE("");
UkmMetricMap expected_metrics = kBasicMetricValues;
expected_metrics[TabManager_TabMetrics::kNavigationEntryCountName] = 2;
expected_metrics[TabManager_TabMetrics::kLabelIdName] = 2;
expected_metrics[TabManager_TabMetrics::kQueryIdName] = 1;
// tab feature of tab@0 should be logged correctly.
ukm_entry_checker_->ExpectNewEntry(kEntryName, 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();
// Switching to first tab logs a forgrounded event for test_urls_[0].
browser()->tab_strip_model()->ActivateTabAt(0, kIsUserGesture);
{
SCOPED_TRACE("");
UkmMetricMap expected_metrics = {
{TabManager_Background_ForegroundedOrClosed::kIsForegroundedName, 1},
{TabManager_Background_ForegroundedOrClosed::kIsDiscardedName, 1},
{TabManager_Background_ForegroundedOrClosed::kLabelIdName, 2}};
ukm_entry_checker_->ExpectNewEntry(kFOCEntryName, test_urls_[0],
expected_metrics);
}
// Log tab_1.
TabActivityWatcher::GetInstance()->LogOldestNTabFeatures();
{
SCOPED_TRACE("");
// tab feature of tab@1 should be logged correctly.
UkmMetricMap expected_metrics = kBasicMetricValues;
expected_metrics[TabManager_TabMetrics::kLabelIdName] = 4;
expected_metrics[TabManager_TabMetrics::kQueryIdName] = 3;
ukm_entry_checker_->ExpectNewEntry(kEntryName, 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();
CloseBrowserSynchronously(browser());
{
SCOPED_TRACE("");
UkmMetricMap expected_metrics = {
{TabManager_Background_ForegroundedOrClosed::kIsForegroundedName, 0},
{TabManager_Background_ForegroundedOrClosed::kIsDiscardedName, 1},
{TabManager_Background_ForegroundedOrClosed::kLabelIdName, 4}};
ukm_entry_checker_->ExpectNewEntry(kFOCEntryName, test_urls_[1],
expected_metrics);
}
}
} // namespace resource_coordinator