chromium/chromecast/metrics/metrics_recorder_base_unittest.cc

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

#include "chromecast/metrics/metrics_recorder_base.h"

#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "chromecast/metrics/mock_cast_event_builder.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using ::testing::_;

namespace chromecast {

namespace {

class MockMetricsRecorder : public MetricsRecorderBase {
 public:
  explicit MockMetricsRecorder(const base::TickClock* tick_clock)
      : MetricsRecorderBase(tick_clock) {}
  ~MockMetricsRecorder() override;

  std::unique_ptr<CastEventBuilder> CreateEventBuilder(
      const std::string& name) override {
    auto builder = std::make_unique<FakeCastEventBuilder>();
    builder->SetName(name);
    return builder;
  }

  MOCK_METHOD(void,
              AddActiveConnection,
              (const std::string&,
               const std::string&,
               const base::Value&,
               const net::IPAddressBytes&),
              (override));
  MOCK_METHOD(void, RemoveActiveConnection, (const std::string&), (override));
  MOCK_METHOD(void,
              RecordCastEvent,
              (std::unique_ptr<CastEventBuilder> event_builder),
              (override));
  MOCK_METHOD(void,
              RecordHistogramTime,
              (const std::string&, int, int, int, int),
              (override));
  MOCK_METHOD(void,
              RecordHistogramCount,
              (const std::string&, int, int, int, int),
              (override));
  MOCK_METHOD(void,
              RecordHistogramCountRepeated,
              (const std::string&, int, int, int, int, int),
              (override));
  MOCK_METHOD(void,
              RecordHistogramEnum,
              (const std::string&, int, int),
              (override));
  MOCK_METHOD(void,
              RecordHistogramSparse,
              (const std::string&, int),
              (override));
};

inline MockMetricsRecorder::~MockMetricsRecorder() = default;

MATCHER_P2(NameAndExtraValue, name, extra_value, "") {
  auto* builder = static_cast<FakeCastEventBuilder*>(arg.get());
  if (!builder)
    return false;
  return builder->name == name && builder->extra_value == extra_value;
}

}  // namespace

class MetricsRecorderTest : public ::testing::Test {
 public:
  MetricsRecorderTest()
      : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME),
        recorder_(task_environment_.GetMockTickClock()) {}

  base::test::TaskEnvironment task_environment_;
  MockMetricsRecorder recorder_;
};

TEST_F(MetricsRecorderTest, TimelineIntervals) {
  // Demonstrates usage of the timeline measurement functions.
  recorder_.MeasureTimeUntilEvent("MyEvent", "MyEvent.LatencyMs");
  task_environment_.FastForwardBy(base::Milliseconds(1500));

  EXPECT_CALL(recorder_,
              RecordCastEvent(NameAndExtraValue("MyEvent.LatencyMs", 1500)));
  recorder_.RecordTimelineEvent("MyEvent");
}

TEST_F(MetricsRecorderTest, TimelineIntervalsMultipleMeasurement) {
  // Multiple measurements with the same end event will each trigger a
  // measurement metric event.
  recorder_.MeasureTimeUntilEvent("MyEvent", "First.Measurement.LatencyMs");
  task_environment_.FastForwardBy(base::Milliseconds(300));
  recorder_.MeasureTimeUntilEvent("MyEvent", "Second.Measurement.LatencyMs");
  task_environment_.FastForwardBy(base::Milliseconds(800));

  EXPECT_CALL(recorder_, RecordCastEvent(NameAndExtraValue(
                             "First.Measurement.LatencyMs", 1100)));
  EXPECT_CALL(recorder_, RecordCastEvent(NameAndExtraValue(
                             "Second.Measurement.LatencyMs", 800)));
  recorder_.RecordTimelineEvent("MyEvent");
}

TEST_F(MetricsRecorderTest, TimelineIntervalsDuplicateMeasurement) {
  // Measurements can have the same name and/or end event. Each instance will
  // emit a metric event containing the measurement value.
  recorder_.MeasureTimeUntilEvent("AnEvent", "AnEvent.LatencyMs");
  task_environment_.FastForwardBy(base::Milliseconds(600));
  recorder_.MeasureTimeUntilEvent("AnEvent", "AnEvent.LatencyMs");
  task_environment_.FastForwardBy(base::Milliseconds(700));

  EXPECT_CALL(recorder_,
              RecordCastEvent(NameAndExtraValue("AnEvent.LatencyMs", 1300)));
  EXPECT_CALL(recorder_,
              RecordCastEvent(NameAndExtraValue("AnEvent.LatencyMs", 700)));
  recorder_.RecordTimelineEvent("AnEvent");
}

TEST_F(MetricsRecorderTest, TimelineIntervalsRepeatEnd) {
  // The measurement should be cleared when the ending event is triggered.
  recorder_.MeasureTimeUntilEvent("SomeEvent", "SomeEvent.LatencyMs");
  task_environment_.FastForwardBy(base::Milliseconds(2300));

  EXPECT_CALL(recorder_,
              RecordCastEvent(NameAndExtraValue("SomeEvent.LatencyMs", 2300)));
  recorder_.RecordTimelineEvent("SomeEvent");

  // Repeating the end event won't trigger another latency measurement event.
  task_environment_.FastForwardBy(base::Milliseconds(800));
  EXPECT_CALL(recorder_, RecordCastEvent(_)).Times(0);
  recorder_.RecordTimelineEvent("SomeEvent");
}

TEST_F(MetricsRecorderTest, TimelineIntervalsRepeatMonitoring) {
  // Measurements can be repeated after they have finished.
  recorder_.MeasureTimeUntilEvent("AnEvent", "AnEvent.LatencyMs");
  task_environment_.FastForwardBy(base::Milliseconds(1100));

  EXPECT_CALL(recorder_,
              RecordCastEvent(NameAndExtraValue("AnEvent.LatencyMs", 1100)));
  recorder_.RecordTimelineEvent("AnEvent");

  // Monitoring again should eventually generate another latency event if both
  // monitored events are triggered in order.
  recorder_.MeasureTimeUntilEvent("AnEvent", "AnEvent.LatencyMs");
  task_environment_.FastForwardBy(base::Milliseconds(500));

  EXPECT_CALL(recorder_,
              RecordCastEvent(NameAndExtraValue("AnEvent.LatencyMs", 500)));
  recorder_.RecordTimelineEvent("AnEvent");
}

}  // namespace chromecast