chromium/chromecast/cast_core/runtime/browser/cast_runtime_histogram_flattener_unittest.cc

// Copyright 2021 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/cast_core/runtime/browser/cast_runtime_histogram_flattener.h"

#include <memory>
#include <string_view>

#include "base/metrics/histogram_macros.h"
#include "base/metrics/statistics_recorder.h"
#include "chromecast/cast_core/runtime/browser/cast_runtime_metrics_test_helpers.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace chromecast {
namespace {

const cast::metrics::Histogram* LookupHistogram(
    std::string_view name,
    const std::vector<cast::metrics::Histogram>& deltas) {
  for (const auto& histogram : deltas) {
    if (histogram.name() == name) {
      return &histogram;
    }
  }
  return nullptr;
}

}  // namespace

class CastRuntimeHistogramFlattenerTest : public ::testing::Test {
 public:
  void SetUp() override {
    // Create the temporary stats recorder to get a clean state
    // for each test.
    statistics_recorder_ =
        base::StatisticsRecorder::CreateTemporaryForTesting();

    // Ensure existing deltas from previous tests in the process are cleared.
    ASSERT_TRUE(GetHistogramDeltas().empty());
  }

  void TearDown() override {
    // Destroy the temporary stats recorder, implicitly restoring
    // the previous global stats recorder.
    statistics_recorder_.reset();
  }

  // Stand-in `StatisticsRecorder` for this test suite, to ensure
  // each test is isolated from everything else in the process that
  // could emit histograms.
  std::unique_ptr<base::StatisticsRecorder> statistics_recorder_;
};

TEST_F(CastRuntimeHistogramFlattenerTest, Empty) {
  EXPECT_TRUE(GetHistogramDeltas().empty());
}

TEST_F(CastRuntimeHistogramFlattenerTest, EmptyAfterPoll) {
  constexpr char kHistName[] = "Foo.Bar.SomeCount";
  UMA_HISTOGRAM_COUNTS_1M(kHistName, 13);
  auto deltas = GetHistogramDeltas();
  EXPECT_EQ(1, GetCount(13, LookupHistogram(kHistName, deltas)));

  EXPECT_TRUE(GetHistogramDeltas().empty());
}

TEST_F(CastRuntimeHistogramFlattenerTest, Boolean) {
  constexpr char kBooleanName[] = "Foo.Bar.SomeBool";
  UMA_HISTOGRAM_BOOLEAN(kBooleanName, true);
  UMA_HISTOGRAM_BOOLEAN(kBooleanName, true);
  UMA_HISTOGRAM_BOOLEAN(kBooleanName, false);

  auto deltas = GetHistogramDeltas();
  EXPECT_EQ(GetCount(0, LookupHistogram(kBooleanName, deltas)), 1);
  EXPECT_EQ(GetCount(1, LookupHistogram(kBooleanName, deltas)), 2);
}

TEST_F(CastRuntimeHistogramFlattenerTest, Linear) {
  constexpr char kLinearName[] = "Foo.Bar.SomeLinear";
  constexpr int kHistogramLimit = 100;
  for (int i = 0; i < kHistogramLimit; ++i) {
    UMA_HISTOGRAM_EXACT_LINEAR(kLinearName, i, kHistogramLimit);
  }

  auto deltas = GetHistogramDeltas();

  const cast::metrics::Histogram* histogram =
      LookupHistogram(kLinearName, deltas);
  for (int i = 0; i < kHistogramLimit; ++i) {
    EXPECT_EQ(GetCount(i, histogram), 1);
  }
}

TEST_F(CastRuntimeHistogramFlattenerTest, Percentage) {
  constexpr char kPercentageName[] = "Foo.Bar.SomePercentage";
  for (int i = 0; i <= 100; ++i) {
    for (int j = 0; j < 2 * i; ++j) {
      UMA_HISTOGRAM_PERCENTAGE(kPercentageName, i);
    }
  }

  auto deltas = GetHistogramDeltas();

  const cast::metrics::Histogram* histogram =
      LookupHistogram(kPercentageName, deltas);
  for (int i = 0; i <= 100; ++i) {
    EXPECT_EQ(GetCount(i, histogram), 2 * i);
  }
}

TEST_F(CastRuntimeHistogramFlattenerTest, Enumeration) {
  constexpr char kEnumName[] = "Foo.Bar.SomeEnum";
  enum Category {
    kAlpha,
    kBeta,
    kGamma,
    kDelta,
    kCategoryMax = kDelta,
  };

  UMA_HISTOGRAM_ENUMERATION(kEnumName, kAlpha, kCategoryMax);
  UMA_HISTOGRAM_ENUMERATION(kEnumName, kGamma, kCategoryMax);
  UMA_HISTOGRAM_ENUMERATION(kEnumName, kDelta, kCategoryMax);
  UMA_HISTOGRAM_ENUMERATION(kEnumName, kGamma, kCategoryMax);

  auto deltas = GetHistogramDeltas();

  const cast::metrics::Histogram* histogram =
      LookupHistogram(kEnumName, deltas);
  EXPECT_EQ(1, GetCount(kAlpha, histogram));
  EXPECT_EQ(0, GetCount(kBeta, histogram));
  EXPECT_EQ(2, GetCount(kGamma, histogram));
  EXPECT_EQ(1, GetCount(kDelta, histogram));
}

TEST_F(CastRuntimeHistogramFlattenerTest, MultipleHistograms) {
  constexpr char kHistName1[] = "Foo.Bar.SomeCount";
  constexpr char kHistName2[] = "Foo.Bar.SomeOtherCount";

  UMA_HISTOGRAM_COUNTS_1M(kHistName1, 13);
  UMA_HISTOGRAM_COUNTS_1M(kHistName2, 1337);
  UMA_HISTOGRAM_COUNTS_1M(kHistName2, 1337);

  auto deltas = GetHistogramDeltas();
  EXPECT_EQ(1, GetCount(13, LookupHistogram(kHistName1, deltas)));
  EXPECT_EQ(2, GetCount(1337, LookupHistogram(kHistName2, deltas)));
}

TEST_F(CastRuntimeHistogramFlattenerTest, SeparateBuckets) {
  constexpr char kHistName[] = "Foo.Bar.SomeCount";

  UMA_HISTOGRAM_COUNTS_1M(kHistName, 13);
  UMA_HISTOGRAM_COUNTS_1M(kHistName, 13000);

  auto deltas = GetHistogramDeltas();
  EXPECT_EQ(1, GetCount(13, LookupHistogram(kHistName, deltas)));
  EXPECT_EQ(1, GetCount(13000, LookupHistogram(kHistName, deltas)));

  UMA_HISTOGRAM_COUNTS_1M(kHistName, 13000);
  UMA_HISTOGRAM_COUNTS_1M(kHistName, 13000);
  deltas = GetHistogramDeltas();
  EXPECT_EQ(2, GetCount(13000, LookupHistogram(kHistName, deltas)));
}

}  // namespace chromecast