| // 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 |