chromium/ash/metrics/wm_feature_metrics_recorder_unittest.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/metrics/wm_feature_metrics_recorder.h"

#include "ash/test/ash_test_base.h"
#include "ash/wm/window_state.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "chromeos/ui/base/window_state_type.h"
#include "ui/aura/window.h"
#include "ui/wm/core/window_util.h"

namespace ash {

namespace {

using WindowSizeRange = WMFeatureMetricsRecorder::WindowSizeRange;

constexpr base::TimeDelta kRecordPeriodicMetricsInterval = base::Minutes(30);

}  // namespace

class WMFeatureMetricsRecorderTests : public AshTestBase {
 public:
  WMFeatureMetricsRecorderTests()
      : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
  WMFeatureMetricsRecorderTests(const WMFeatureMetricsRecorderTests&) = delete;
  WMFeatureMetricsRecorderTests& operator=(
      const WMFeatureMetricsRecorderTests&) = delete;
  ~WMFeatureMetricsRecorderTests() override = default;

  void FastForwardBy(base::TimeDelta delta) {
    task_environment()->FastForwardBy(delta);
  }
};

// Tests the window layout related metrics can be logged periodically.
TEST_F(WMFeatureMetricsRecorderTests, WindowLayoutMetricsRecorder) {
  UpdateDisplay("1600x1000");
  base::HistogramTester histogram_tester;

  const std::string metrics_prefix =
      WMFeatureMetricsRecorder::GetFeatureMetricsPrefix(
          WMFeatureMetricsRecorder::WMFeatureType::kWindowLayoutState);

  // Create two tests windows.
  auto window1 = CreateAppWindow(gfx::Rect(0, 0, 200, 100));
  EXPECT_EQ(WindowState::Get(window1.get())->GetStateType(),
            chromeos::WindowStateType::kDefault);
  auto window2 = CreateAppWindow(gfx::Rect(0, 0, 1500, 1000));
  EXPECT_EQ(WindowState::Get(window2.get())->GetStateType(),
            chromeos::WindowStateType::kDefault);

  wm::ActivateWindow(window1.get());
  FastForwardBy(kRecordPeriodicMetricsInterval);

  // Check the metrics.
  base::HistogramTester::CountsMap expected_counts;
  expected_counts[metrics_prefix + "WindowNumbers"] = 1;
  expected_counts[metrics_prefix + "AllWindowStates"] = 2;
  expected_counts[metrics_prefix + "AllAppTypes"] = 2;
  expected_counts[metrics_prefix + "AllWindowSizes"] = 2;
  expected_counts[metrics_prefix + "FreeformedWindowSizes"] = 2;
  expected_counts[metrics_prefix + "ActiveWindowState"] = 1;
  expected_counts[metrics_prefix + "ActiveWindowAppType"] = 1;
  expected_counts[metrics_prefix + "ActiveWindowSize"] = 1;
  EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(metrics_prefix),
              testing::ContainerEq(expected_counts));

  EXPECT_THAT(
      histogram_tester.GetAllSamples(metrics_prefix + "ActiveWindowState"),
      BucketsAre(base::Bucket(chromeos::WindowStateType::kDefault, 1)));
  EXPECT_THAT(
      histogram_tester.GetAllSamples(metrics_prefix + "ActiveWindowAppType"),
      BucketsAre(base::Bucket(chromeos::AppType::SYSTEM_APP, 1)));
  EXPECT_THAT(
      histogram_tester.GetAllSamples(metrics_prefix + "ActiveWindowSize"),
      BucketsAre(base::Bucket(WindowSizeRange::kXSWidthXSHeight, 1)));

  wm::ActivateWindow(window2.get());
  WindowState::Get(window2.get())->Maximize();
  FastForwardBy(kRecordPeriodicMetricsInterval);

  expected_counts[metrics_prefix + "WindowNumbers"] = 2;
  expected_counts[metrics_prefix + "AllWindowStates"] = 4;
  expected_counts[metrics_prefix + "AllAppTypes"] = 4;
  expected_counts[metrics_prefix + "AllWindowSizes"] = 4;
  expected_counts[metrics_prefix + "FreeformedWindowSizes"] = 3;
  expected_counts[metrics_prefix + "ActiveWindowState"] = 2;
  expected_counts[metrics_prefix + "ActiveWindowAppType"] = 2;
  expected_counts[metrics_prefix + "ActiveWindowSize"] = 2;
  EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(metrics_prefix),
              testing::ContainerEq(expected_counts));

  EXPECT_THAT(
      histogram_tester.GetAllSamples(metrics_prefix + "ActiveWindowState"),
      BucketsAre(base::Bucket(chromeos::WindowStateType::kMaximized, 1),
                 base::Bucket(chromeos::WindowStateType::kDefault, 1)));
  EXPECT_THAT(
      histogram_tester.GetAllSamples(metrics_prefix + "ActiveWindowAppType"),
      BucketsAre(base::Bucket(chromeos::AppType::SYSTEM_APP, 2)));
  EXPECT_THAT(
      histogram_tester.GetAllSamples(metrics_prefix + "ActiveWindowSize"),
      BucketsAre(base::Bucket(WindowSizeRange::kLWidthLHeight, 1),
                 base::Bucket(WindowSizeRange::kXSWidthXSHeight, 1)));
}

// Tests that window sizes range can be recorded properly.
TEST_F(WMFeatureMetricsRecorderTests, WindowSizeRangeTest) {
  UpdateDisplay("1600x1000");
  base::HistogramTester histogram_tester;

  const std::string metrics_prefix =
      WMFeatureMetricsRecorder::GetFeatureMetricsPrefix(
          WMFeatureMetricsRecorder::WMFeatureType::kWindowLayoutState);
  auto window = CreateAppWindow(gfx::Rect(0, 0, 200, 100));
  wm::ActivateWindow(window.get());

  struct TestCase {
    const char* msg;
    gfx::Size size;
    WindowSizeRange expectation;
  };
  std::vector<TestCase> test_cases = {
      {"(0-800, 0-600)", gfx::Size(500, 400),
       WindowSizeRange::kXSWidthXSHeight},
      {"(0-800, 600-728)", gfx::Size(500, 700),
       WindowSizeRange::kXSWidthSHeight},
      {"(0-800, 728-900)", gfx::Size(500, 800),
       WindowSizeRange::kXSWidthMHeight},
      {"(0-800, >900)", gfx::Size(500, 1000), WindowSizeRange::kXSWidthLHeight},
      {"(800-1024, 0-600)", gfx::Size(900, 400),
       WindowSizeRange::kSWidthXSHeight},
      {"(800-1024, 600-728)", gfx::Size(900, 700),
       WindowSizeRange::kSWidthSHeight},
      {"(800-1024, 728-900)", gfx::Size(900, 800),
       WindowSizeRange::kSWidthMHeight},
      {"(800-1024, >900)", gfx::Size(900, 1000),
       WindowSizeRange::kSWidthLHeight},
      {"(1024-1400, 0-600)", gfx::Size(1200, 400),
       WindowSizeRange::kMWidthXSHeight},
      {"(1024-1400, 600-728)", gfx::Size(1200, 700),
       WindowSizeRange::kMWidthSHeight},
      {"(1024-1400, 728-900)", gfx::Size(1200, 800),
       WindowSizeRange::kMWidthMHeight},
      {"(1024-1400, >900)", gfx::Size(1200, 1000),
       WindowSizeRange::kMWidthLHeight},
      {">1400, 0-600)", gfx::Size(1500, 400), WindowSizeRange::kLWidthXSHeight},
      {">1400, 600-728)", gfx::Size(1500, 700),
       WindowSizeRange::kLWidthSHeight},
      {">1400, 728-900)", gfx::Size(1500, 800),
       WindowSizeRange::kLWidthMHeight},
      {">1400, >900)", gfx::Size(1500, 1000), WindowSizeRange::kLWidthLHeight}};

  for (auto test_case : test_cases) {
    SCOPED_TRACE(test_case.msg);
    window->SetBounds(gfx::Rect(test_case.size));
    FastForwardBy(kRecordPeriodicMetricsInterval);
    EXPECT_THAT(
        histogram_tester.GetAllSamples(metrics_prefix + "ActiveWindowSize"),
        BucketsInclude(base::Bucket(test_case.expectation, 1)));
  }
}

}  // namespace ash