blob: 7a52ffcf1c2bbb29f917c716a492a557be05c6c4 [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 <memory>
#include "base/macros.h"
#include "build/build_config.h"
#include "chrome/browser/resource_coordinator/tab_metrics_event.pb.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_ukm_test_helper.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 "chrome/test/views/scoped_macviews_browser_mode.h"
#include "components/ukm/test_ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gtest/include/gtest/gtest.h"
using metrics::WindowMetricsEvent;
using ukm::builders::TabManager_TabMetrics;
using ukm::builders::TabManager_WindowMetrics;
namespace {
const char* kEntryName = TabManager_WindowMetrics::kEntryName;
const char* kTestUrl = "https://example.com/";
} // namespace
// Tests UKM entries generated by WindowActivityWatcher due to interactive
// changes to window state.
class WindowActivityWatcherTest : public InProcessBrowserTest {
protected:
WindowActivityWatcherTest() = default;
// InProcessBrowserTest:
void PreRunTestOnMainThread() override {
InProcessBrowserTest::PreRunTestOnMainThread();
ukm_entry_checker_ = std::make_unique<UkmEntryChecker>();
}
void SetUpOnMainThread() override {
// Browser is created in BrowserMain() before the test UKM recorder.
ASSERT_EQ(0u, ukm_entry_checker_->NumEntries(kEntryName));
#if defined(OS_MACOSX)
// 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());
UkmMetricMap expected_metrics({
{TabManager_WindowMetrics::kWindowIdName, browser()->session_id().id()},
{TabManager_WindowMetrics::kShowStateName,
WindowMetricsEvent::SHOW_STATE_NORMAL},
{TabManager_WindowMetrics::kTypeName, WindowMetricsEvent::TYPE_TABBED},
{TabManager_WindowMetrics::kIsActiveName, 1},
{TabManager_WindowMetrics::kTabCountName, 1},
});
ukm_entry_checker_->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
#endif
}
protected:
std::unique_ptr<UkmEntryChecker> ukm_entry_checker_;
private:
test::ScopedMacViewsBrowserMode views_mode_{true};
DISALLOW_COPY_AND_ASSIGN(WindowActivityWatcherTest);
};
// Tests WindowMetrics UKMs logged by the current browser window.
IN_PROC_BROWSER_TEST_F(WindowActivityWatcherTest, Basic) {
UkmMetricMap expected_metrics({
{TabManager_WindowMetrics::kWindowIdName, browser()->session_id().id()},
{TabManager_WindowMetrics::kShowStateName,
WindowMetricsEvent::SHOW_STATE_NORMAL},
{TabManager_WindowMetrics::kTypeName, WindowMetricsEvent::TYPE_TABBED},
{TabManager_WindowMetrics::kIsActiveName, 1},
{TabManager_WindowMetrics::kTabCountName, 1},
});
// Updated metrics are logged after adding tabs.
{
SCOPED_TRACE("");
AddTabAtIndex(1, GURL(kTestUrl), ui::PAGE_TRANSITION_LINK);
expected_metrics[TabManager_WindowMetrics::kTabCountName] = 2;
ukm_entry_checker_->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
}
{
SCOPED_TRACE("");
AddTabAtIndex(0, GURL(kTestUrl), ui::PAGE_TRANSITION_LINK);
expected_metrics[TabManager_WindowMetrics::kTabCountName] = 3;
ukm_entry_checker_->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
}
// Closing the window doesn't log more WindowMetrics UKMs.
CloseBrowserSynchronously(browser());
}
// TODO(https://crbug.com/51364): Implement BrowserWindow::Deactivate() on Mac.
#if !defined(OS_MACOSX)
// Tests WindowMetrics UKMs logged by activating/deactivating the window.
IN_PROC_BROWSER_TEST_F(WindowActivityWatcherTest, WindowActivation) {
UkmMetricMap expected_metrics({
{TabManager_WindowMetrics::kWindowIdName, browser()->session_id().id()},
{TabManager_WindowMetrics::kShowStateName,
WindowMetricsEvent::SHOW_STATE_NORMAL},
{TabManager_WindowMetrics::kTypeName, WindowMetricsEvent::TYPE_TABBED},
{TabManager_WindowMetrics::kIsActiveName, 0},
{TabManager_WindowMetrics::kTabCountName, 1},
});
{
SCOPED_TRACE("");
ui_test_utils::BrowserDeactivationWaiter waiter(browser());
browser()->window()->Deactivate();
waiter.WaitForDeactivation();
ukm_entry_checker_->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
}
{
SCOPED_TRACE("");
ui_test_utils::BrowserActivationWaiter waiter(browser());
browser()->window()->Activate();
waiter.WaitForActivation();
ASSERT_TRUE(browser()->window()->IsActive());
expected_metrics[TabManager_WindowMetrics::kIsActiveName] = 1;
ukm_entry_checker_->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
}
// Closing the window doesn't log more WindowMetrics UKMs.
CloseBrowserSynchronously(browser());
}
// Tests WindowMetrics UKMs logged when switching between windows.
IN_PROC_BROWSER_TEST_F(WindowActivityWatcherTest, MultipleWindows) {
// Create a new browser window.
Browser* browser_2 = CreateBrowser(browser()->profile());
{
SCOPED_TRACE("");
ukm_entry_checker_->ExpectNewEntry(
kEntryName, GURL(),
{
{TabManager_WindowMetrics::kWindowIdName,
browser_2->session_id().id()},
{TabManager_WindowMetrics::kIsActiveName, 0},
});
}
// 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();
}
{
ui_test_utils::BrowserDeactivationWaiter waiter(browser());
waiter.WaitForDeactivation();
}
{
SCOPED_TRACE("");
// Check for activation and deactivation events. The exact order is
// platform-dependent.
ukm_entry_checker_->ExpectNewEntries(
kEntryName, {{
{TabManager_WindowMetrics::kWindowIdName,
browser_2->session_id().id()},
{TabManager_WindowMetrics::kIsActiveName, 1},
},
{
{TabManager_WindowMetrics::kWindowIdName,
browser()->session_id().id()},
{TabManager_WindowMetrics::kIsActiveName, 0},
}});
}
{
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();
// Check for activation and deactivation events. The exact order is
// platform-dependent.
ukm_entry_checker_->ExpectNewEntries(
kEntryName, {{
{TabManager_WindowMetrics::kWindowIdName,
browser()->session_id().id()},
{TabManager_WindowMetrics::kIsActiveName, 1},
},
{
{TabManager_WindowMetrics::kWindowIdName,
browser_2->session_id().id()},
{TabManager_WindowMetrics::kIsActiveName, 0},
}});
}
// Closing the active window activates the second window.
ASSERT_EQ(0, ukm_entry_checker_->NumNewEntriesRecorded(kEntryName));
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("");
// Check for activation and deactivation events. The exact order is
// platform-dependent.
ukm_entry_checker_->ExpectNewEntries(
kEntryName, {{
{TabManager_WindowMetrics::kWindowIdName,
browser_2->session_id().id()},
{TabManager_WindowMetrics::kIsActiveName, 1},
}});
}
// Occasionally, X sends an extraneous deactivate/reactivate cycle.
if (ukm_entry_checker_->NumNewEntriesRecorded(kEntryName) == 2) {
SCOPED_TRACE("");
LOG(WARNING) << "Extra deactivate/reactivate detected.";
ukm_entry_checker_->ExpectNewEntries(
kEntryName, {{
{TabManager_WindowMetrics::kWindowIdName,
browser_2->session_id().id()},
{TabManager_WindowMetrics::kIsActiveName, 0},
},
{
{TabManager_WindowMetrics::kWindowIdName,
browser_2->session_id().id()},
{TabManager_WindowMetrics::kIsActiveName, 1},
}});
}
// Ignore UKMs that might be logged from spurious activation events.
ukm_entry_checker_.reset();
}
// Tests we don't emit a ridiculous number of UKMs, which may indicate
// unintended log entries or unexpected interactions between events.
IN_PROC_BROWSER_TEST_F(WindowActivityWatcherTest, DontFloodUkm) {
// TODO(michaelpg): Update once window metrics are folded into tab metrics.
constexpr int kTooManyWindowMetricsEntries = 40;
constexpr int kTooManyTabMetricsEntries = 20;
// Add and activate some tabs.
for (int i = 0; i < 3; i++)
AddTabAtIndex(1, GURL(kTestUrl), ui::PAGE_TRANSITION_LINK);
// Make more windows with tabs.
constexpr bool kCheckNavigationSuccess = false;
Browser* browser_2 = CreateBrowser(browser()->profile());
for (int i = 0; i < 3; i++) {
AddTabAtIndexToBrowser(browser_2, 1, GURL(kTestUrl),
ui::PAGE_TRANSITION_LINK, kCheckNavigationSuccess);
}
Browser* browser_3 = CreateBrowser(browser()->profile());
for (int i = 0; i < 3; i++) {
AddTabAtIndexToBrowser(browser_3, 1, GURL(kTestUrl),
ui::PAGE_TRANSITION_LINK, kCheckNavigationSuccess);
}
// Cycle between windows.
for (Browser* next_browser :
{browser_2, browser_3, browser(), browser_2, browser_3}) {
next_browser->window()->Activate();
ui_test_utils::BrowserActivationWaiter(next_browser).WaitForActivation();
}
// Manage windows.
browser_2->window()->Minimize();
browser_2->window()->Maximize();
browser_3->window()->Maximize();
browser_2->window()->Restore();
browser_3->window()->Minimize();
CloseBrowserSynchronously(browser());
CloseBrowserSynchronously(browser_2);
CloseBrowserSynchronously(browser_3);
ASSERT_GT(ukm_entry_checker_->NumNewEntriesRecorded(kEntryName), 0);
ASSERT_LT(ukm_entry_checker_->NumNewEntriesRecorded(kEntryName),
kTooManyWindowMetricsEntries);
ASSERT_GT(ukm_entry_checker_->NumNewEntriesRecorded(
TabManager_TabMetrics::kEntryName),
0);
ASSERT_LT(ukm_entry_checker_->NumNewEntriesRecorded(
TabManager_TabMetrics::kEntryName),
kTooManyTabMetricsEntries);
}
#endif // !defined(OS_MACOSX)