blob: 49cec262b997a7e4a33106c1c98b33a5dcc3d490 [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/resource_coordinator/tab_metrics_logger.h"
#include <memory>
#include "base/macros.h"
#include "build/build_config.h"
#include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h"
#include "chrome/browser/resource_coordinator/tab_metrics_event.pb.h"
#include "chrome/browser/resource_coordinator/tab_ranker/tab_features.h"
#include "chrome/browser/resource_coordinator/tab_ranker/window_features.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/test/browser_test.h"
#include "testing/gtest/include/gtest/gtest.h"
using metrics::WindowMetricsEvent;
using resource_coordinator::TabLifecycleUnitExternal;
using tab_ranker::WindowFeatures;
const char* kTestUrl = "https://example.com/";
constexpr char kBeforeUnloadHtml[] =
"data:text/html,<html><body><script>window.onbeforeunload=function(e) {}"
"</script></body></html>";
// Tests WindowFeatures generated by TabMetricsLogger::CreateWindowFeatures due
// to interactive changes to window state.
class TabMetricsLoggerTest : public InProcessBrowserTest {
protected:
TabMetricsLoggerTest() = default;
// InProcessBrowserTest:
void PreRunTestOnMainThread() override {
InProcessBrowserTest::PreRunTestOnMainThread();
}
void SetUpOnMainThread() override {
#if defined(OS_MAC)
// On Mac, the browser window needs to be forced to the front. This will
// create a UKM entry for the activation because it happens after the
// WindowActivityWatcher creation. On other platforms, activation happens
// before creation, and as a result, no UKM entry is created.
// TODO(crbug.com/650859): Reassess after activation is restored in the
// focus manager.
ui_test_utils::BrowserActivationWaiter waiter(browser());
ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
waiter.WaitForActivation();
ASSERT_TRUE(browser()->window()->IsActive());
#endif
}
// Returns TabFeatures of Tab at |index|.
tab_ranker::TabFeatures CurrentTabFeatures(const int index) {
auto* web_contents = browser()->tab_strip_model()->GetWebContentsAt(index);
return TabMetricsLogger::GetTabFeatures(TabMetricsLogger::PageMetrics(),
web_contents)
.value();
}
void DiscardTabAt(const int index) {
auto* web_contents = browser()->tab_strip_model()->GetWebContentsAt(index);
auto* external = TabLifecycleUnitExternal::FromWebContents(web_contents);
external->DiscardTab(mojom::LifecycleUnitDiscardReason::URGENT);
}
base::test::ScopedFeatureList scoped_feature_list_;
private:
DISALLOW_COPY_AND_ASSIGN(TabMetricsLoggerTest);
};
// Tests before unload handler is calculated correctly.
IN_PROC_BROWSER_TEST_F(TabMetricsLoggerTest, GetBeforeUnloadHandler) {
EXPECT_FALSE(CurrentTabFeatures(0).has_before_unload_handler);
ui_test_utils::NavigateToURL(browser(), GURL(kBeforeUnloadHtml));
EXPECT_TRUE(CurrentTabFeatures(0).has_before_unload_handler);
}
// Tests WindowMetrics of the current browser window.
IN_PROC_BROWSER_TEST_F(TabMetricsLoggerTest, CreateWindowFeaturesTest) {
WindowFeatures expected_metrics{WindowMetricsEvent::TYPE_TABBED,
WindowMetricsEvent::SHOW_STATE_NORMAL, true,
1};
EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser()),
expected_metrics);
// Updated metrics after adding tabs.
{
SCOPED_TRACE("");
AddTabAtIndex(1, GURL(kTestUrl), ui::PAGE_TRANSITION_LINK);
expected_metrics.tab_count++;
EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser()),
expected_metrics);
}
{
SCOPED_TRACE("");
AddTabAtIndex(0, GURL(kTestUrl), ui::PAGE_TRANSITION_LINK);
expected_metrics.tab_count++;
EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser()),
expected_metrics);
}
// Closing the window doesn't log more WindowMetrics UKMs.
CloseBrowserSynchronously(browser());
}
// Tests GetDiscardCount.
IN_PROC_BROWSER_TEST_F(TabMetricsLoggerTest, GetDiscardCount) {
// We need at least two tabs because "transition from DISCARDED to DISCARDED
// is not allowed".
AddTabAtIndex(1, GURL(kTestUrl), ui::PAGE_TRANSITION_LINK);
EXPECT_EQ(CurrentTabFeatures(0).discard_count, 0);
DiscardTabAt(0);
EXPECT_EQ(CurrentTabFeatures(0).discard_count, 1);
browser()->tab_strip_model()->ActivateTabAt(
0, {TabStripModel::GestureType::kOther});
EXPECT_EQ(CurrentTabFeatures(0).discard_count, 1);
DiscardTabAt(1);
EXPECT_EQ(CurrentTabFeatures(1).discard_count, 1);
browser()->tab_strip_model()->ActivateTabAt(
1, {TabStripModel::GestureType::kOther});
EXPECT_EQ(CurrentTabFeatures(1).discard_count, 1);
DiscardTabAt(0);
EXPECT_EQ(CurrentTabFeatures(0).discard_count, 2);
CloseBrowserSynchronously(browser());
}
// TODO(https://crbug.com/51364): Implement BrowserWindow::Deactivate() on Mac.
#if !defined(OS_MAC)
// Tests WindowMetrics by activating/deactivating the window.
IN_PROC_BROWSER_TEST_F(TabMetricsLoggerTest,
CreateWindowFeaturesTestWindowActivation) {
WindowFeatures expected_metrics{WindowMetricsEvent::TYPE_TABBED,
WindowMetricsEvent::SHOW_STATE_NORMAL, false,
1};
{
SCOPED_TRACE("");
ui_test_utils::BrowserDeactivationWaiter waiter(browser());
browser()->window()->Deactivate();
waiter.WaitForDeactivation();
EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser()),
expected_metrics);
}
{
SCOPED_TRACE("");
ui_test_utils::BrowserActivationWaiter waiter(browser());
browser()->window()->Activate();
waiter.WaitForActivation();
ASSERT_TRUE(browser()->window()->IsActive());
expected_metrics.is_active = true;
EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser()),
expected_metrics);
}
// Closing the window doesn't log more WindowMetrics UKMs.
CloseBrowserSynchronously(browser());
}
// Tests WindowMetrics when switching between windows.
IN_PROC_BROWSER_TEST_F(TabMetricsLoggerTest,
CreateWindowFeaturesTestMultipleWindows) {
// Create a new browser window.
Browser* browser_2 = CreateBrowser(browser()->profile());
WindowFeatures expected_metrics{WindowMetricsEvent::TYPE_TABBED,
WindowMetricsEvent::SHOW_STATE_NORMAL, false,
1};
WindowFeatures expected_metrics_2{WindowMetricsEvent::TYPE_TABBED,
WindowMetricsEvent::SHOW_STATE_NORMAL,
false, 1};
// Wait for the old window to be deactivated and the new window to be
// activated if they aren't yet.
{
ui_test_utils::BrowserActivationWaiter waiter(browser_2);
waiter.WaitForActivation();
expected_metrics_2.is_active = true;
}
{
ui_test_utils::BrowserDeactivationWaiter waiter(browser());
waiter.WaitForDeactivation();
}
{
SCOPED_TRACE("");
// Check for activation and deactivation.
EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser_2),
expected_metrics_2);
EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser()),
expected_metrics);
}
{
SCOPED_TRACE("");
ui_test_utils::BrowserActivationWaiter activation_waiter(browser());
ui_test_utils::BrowserDeactivationWaiter deactivation_waiter(browser_2);
// Switch back to the first window.
// Note: use Activate() rather than Show() because on some platforms, Show()
// calls SetLastActive() before doing anything else.
browser()->window()->Activate();
activation_waiter.WaitForActivation();
deactivation_waiter.WaitForDeactivation();
expected_metrics.is_active = true;
expected_metrics_2.is_active = false;
EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser()),
expected_metrics);
EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser_2),
expected_metrics_2);
}
CloseBrowserSynchronously(browser());
// GetLastActive could return browser2 if browser1 was active and then was
// removed, so browser2 might not actually be active.
{
ui_test_utils::BrowserActivationWaiter activation_waiter(browser_2);
browser_2->window()->Activate();
activation_waiter.WaitForActivation();
}
EXPECT_TRUE(BrowserList::GetInstance()->GetLastActive() == browser_2);
EXPECT_TRUE(browser_2->window()->IsActive());
{
SCOPED_TRACE("");
expected_metrics_2.is_active = true;
EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser_2),
expected_metrics_2);
}
}
#endif // !defined(OS_MAC)