Index: webrtc/video/stats_counter_unittest.cc |
diff --git a/webrtc/video/stats_counter_unittest.cc b/webrtc/video/stats_counter_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9c4fd4999bb96fb98a44603c195dad1adb3d9477 |
--- /dev/null |
+++ b/webrtc/video/stats_counter_unittest.cc |
@@ -0,0 +1,300 @@ |
+/* |
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
+ * |
+ * Use of this source code is governed by a BSD-style license |
+ * that can be found in the LICENSE file in the root of the source |
+ * tree. An additional intellectual property rights grant can be found |
+ * in the file PATENTS. All contributing project authors may |
+ * be found in the AUTHORS file in the root of the source tree. |
+ */ |
+ |
+#include "webrtc/video/stats_counter.h" |
+ |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+#include "webrtc/system_wrappers/include/clock.h" |
+ |
+namespace webrtc { |
+namespace { |
+const int kProcessIntervalMs = 2000; |
+ |
+class StatsCounterObserverImpl : public StatsCounterObserver { |
+ public: |
+ StatsCounterObserverImpl() : num_calls_(0), last_sample_(-1) {} |
+ void OnMetricUpdated(int sample) override { |
+ ++num_calls_; |
+ last_sample_ = sample; |
+ } |
+ int num_calls_; |
+ int last_sample_; |
+}; |
+} // namespace |
+ |
+class StatsCounterTest : public ::testing::Test { |
+ protected: |
+ StatsCounterTest() |
+ : clock_(1234), observer_(new StatsCounterObserverImpl()) {} |
+ |
+ void AddSampleAndAdvance(int sample, int interval_ms, AvgCounter* counter) { |
+ counter->Add(sample); |
+ clock_.AdvanceTimeMilliseconds(interval_ms); |
+ } |
+ |
+ void SetSampleAndAdvance(int sample, |
+ int interval_ms, |
+ RateAccCounter* counter) { |
+ counter->Set(sample); |
+ clock_.AdvanceTimeMilliseconds(interval_ms); |
+ } |
+ |
+ void VerifyStatsIsNotSet(const StatsCounter::AggStats::Stats& stats) { |
+ EXPECT_EQ(0, stats.num_samples); |
+ EXPECT_EQ(-1, stats.min); |
+ EXPECT_EQ(-1, stats.max); |
+ EXPECT_EQ(-1, stats.average); |
+ } |
+ |
+ SimulatedClock clock_; |
+ StatsCounterObserverImpl* observer_; |
+}; |
+ |
+TEST_F(StatsCounterTest, NoSamples) { |
+ AvgCounter counter(&clock_, nullptr); |
+ VerifyStatsIsNotSet(counter.GetStats()); |
+} |
+ |
+TEST_F(StatsCounterTest, TestRegisterObserver) { |
+ const int kSample = 22; |
+ AvgCounter counter(&clock_, observer_); |
+ AddSampleAndAdvance(kSample, kProcessIntervalMs, &counter); |
+ // Trigger process (sample included in next interval). |
+ counter.Add(111); |
+ EXPECT_EQ(1, observer_->num_calls_); |
+} |
+ |
+TEST_F(StatsCounterTest, TestNoObserver) { |
+ const int kSample = 22; |
+ AvgCounter counter(&clock_, nullptr); |
+ AddSampleAndAdvance(kSample, kProcessIntervalMs, &counter); |
+ // Trigger process (sample included in next interval). |
+ counter.Add(111); |
+ EXPECT_EQ(0, observer_->num_calls_); |
+} |
+ |
+TEST_F(StatsCounterTest, VerifyProcessInterval) { |
+ AvgCounter counter(&clock_, observer_); |
+ counter.Add(4); |
+ clock_.AdvanceTimeMilliseconds(kProcessIntervalMs - 1); |
+ // Try trigger process (interval has not passed). |
+ counter.Add(8); |
+ EXPECT_EQ(0, observer_->num_calls_); |
+ VerifyStatsIsNotSet(counter.GetStats()); |
+ // Make process interval pass. |
+ clock_.AdvanceTimeMilliseconds(1); |
+ // Trigger process (sample included in next interval). |
+ counter.Add(111); |
+ EXPECT_EQ(1, observer_->num_calls_); |
+ EXPECT_EQ(6, observer_->last_sample_); |
+ // Aggregated stats. |
+ StatsCounter::AggStats::Stats stats = counter.GetStats(); |
+ EXPECT_EQ(1, stats.num_samples); |
+} |
+ |
+TEST_F(StatsCounterTest, TestMetric_AvgCounter) { |
+ AvgCounter counter(&clock_, observer_); |
+ counter.Add(4); |
+ counter.Add(8); |
+ counter.Add(9); |
+ clock_.AdvanceTimeMilliseconds(kProcessIntervalMs); |
+ // Trigger process (sample included in next interval). |
+ counter.Add(111); |
+ // Average per interval. |
+ EXPECT_EQ(1, observer_->num_calls_); |
+ EXPECT_EQ(7, observer_->last_sample_); |
+ // Aggregated stats. |
+ StatsCounter::AggStats::Stats stats = counter.GetStats(); |
+ EXPECT_EQ(1, stats.num_samples); |
+ EXPECT_EQ(7, stats.min); |
+ EXPECT_EQ(7, stats.max); |
+ EXPECT_EQ(7, stats.average); |
+} |
+ |
+TEST_F(StatsCounterTest, TestMetric_PercentCounter) { |
+ PercentCounter counter(&clock_, observer_); |
+ counter.Add(true); |
+ counter.Add(false); |
+ clock_.AdvanceTimeMilliseconds(kProcessIntervalMs); |
+ // Trigger process (sample included in next interval). |
+ counter.Add(false); |
+ // Percentage per interval. |
+ EXPECT_EQ(1, observer_->num_calls_); |
+ EXPECT_EQ(50, observer_->last_sample_); |
+ // Aggregated stats. |
+ StatsCounter::AggStats::Stats stats = counter.GetStats(); |
+ EXPECT_EQ(1, stats.num_samples); |
+ EXPECT_EQ(50, stats.min); |
+ EXPECT_EQ(50, stats.max); |
+} |
+ |
+TEST_F(StatsCounterTest, TestMetric_PermilleCounter) { |
+ PermilleCounter counter(&clock_, observer_); |
+ counter.Add(true); |
+ counter.Add(false); |
+ clock_.AdvanceTimeMilliseconds(kProcessIntervalMs); |
+ // Trigger process (sample included in next interval). |
+ counter.Add(false); |
+ // Permille per interval. |
+ EXPECT_EQ(1, observer_->num_calls_); |
+ EXPECT_EQ(500, observer_->last_sample_); |
+ // Aggregated stats. |
+ StatsCounter::AggStats::Stats stats = counter.GetStats(); |
+ EXPECT_EQ(1, stats.num_samples); |
+ EXPECT_EQ(500, stats.min); |
+ EXPECT_EQ(500, stats.max); |
+} |
+ |
+TEST_F(StatsCounterTest, TestMetric_RateCounter) { |
+ RateCounter counter(&clock_, observer_); |
+ counter.Add(186); |
+ counter.Add(350); |
+ counter.Add(22); |
+ clock_.AdvanceTimeMilliseconds(kProcessIntervalMs); |
+ // Trigger process (sample included in next interval). |
+ counter.Add(111); |
+ // Rate per interval, (186 + 350 + 22) / 2 sec = 279 samples/sec |
+ EXPECT_EQ(1, observer_->num_calls_); |
+ EXPECT_EQ(279, observer_->last_sample_); |
+ // Aggregated stats. |
+ StatsCounter::AggStats::Stats stats = counter.GetStats(); |
+ EXPECT_EQ(1, stats.num_samples); |
+ EXPECT_EQ(279, stats.min); |
+ EXPECT_EQ(279, stats.max); |
+} |
+ |
+TEST_F(StatsCounterTest, TestMetric_RateAccCounter) { |
+ RateAccCounter counter(&clock_, observer_); |
+ counter.Set(175); |
+ counter.Set(188); |
+ clock_.AdvanceTimeMilliseconds(kProcessIntervalMs); |
+ // Trigger process (sample included in next interval). |
+ counter.Set(192); |
+ // Rate per interval: (188 - 0) / 2 sec = 94 samples/sec |
+ EXPECT_EQ(1, observer_->num_calls_); |
+ EXPECT_EQ(94, observer_->last_sample_); |
+ // Aggregated stats. |
+ StatsCounter::AggStats::Stats stats = counter.GetStats(); |
+ EXPECT_EQ(1, stats.num_samples); |
+ EXPECT_EQ(94, stats.min); |
+ EXPECT_EQ(94, stats.max); |
+} |
+ |
+TEST_F(StatsCounterTest, TestGetStats_MultipleIntervals) { |
+ AvgCounter counter(&clock_, nullptr); |
+ const int kSample1 = 1; |
+ const int kSample2 = 5; |
+ const int kSample3 = 8; |
+ const int kSample4 = 11; |
+ const int kSample5 = 50; |
+ AddSampleAndAdvance(kSample1, kProcessIntervalMs, &counter); |
+ AddSampleAndAdvance(kSample2, kProcessIntervalMs, &counter); |
+ AddSampleAndAdvance(kSample3, kProcessIntervalMs, &counter); |
+ AddSampleAndAdvance(kSample4, kProcessIntervalMs, &counter); |
+ AddSampleAndAdvance(kSample5, kProcessIntervalMs, &counter); |
+ // Trigger process (sample included in next interval). |
+ counter.Add(111); |
+ StatsCounter::AggStats::Stats stats = counter.GetStats(); |
+ EXPECT_EQ(5, stats.num_samples); |
+ EXPECT_EQ(kSample1, stats.min); |
+ EXPECT_EQ(kSample5, stats.max); |
+ EXPECT_EQ(15, stats.average); |
+} |
+ |
+TEST_F(StatsCounterTest, TestGetStatsTwice) { |
+ const int kSample1 = 4; |
+ const int kSample2 = 7; |
+ AvgCounter counter(&clock_, nullptr); |
+ AddSampleAndAdvance(kSample1, kProcessIntervalMs, &counter); |
+ // Trigger process (sample included in next interval). |
+ counter.Add(kSample2); |
+ StatsCounter::AggStats::Stats stats = counter.GetStats(); |
+ EXPECT_EQ(1, stats.num_samples); |
+ EXPECT_EQ(kSample1, stats.min); |
+ EXPECT_EQ(kSample1, stats.max); |
+ // Trigger process (sample included in next interval). |
+ clock_.AdvanceTimeMilliseconds(kProcessIntervalMs); |
+ counter.Add(111); |
+ stats = counter.GetStats(); |
+ EXPECT_EQ(2, stats.num_samples); |
+ EXPECT_EQ(kSample1, stats.min); |
+ EXPECT_EQ(kSample2, stats.max); |
+ EXPECT_EQ(6, stats.average); |
+} |
+ |
+TEST_F(StatsCounterTest, TestRateAccCounter_NegativeRateIgnored) { |
+ const int kSample1 = 200; // 200 / 2 sec |
+ const int kSample2 = 100; // -100 / 2 sec - negative ignored |
+ const int kSample3 = 700; // 600 / 2 sec |
+ RateAccCounter counter(&clock_, observer_); |
+ SetSampleAndAdvance(kSample1, kProcessIntervalMs, &counter); |
+ SetSampleAndAdvance(kSample2, kProcessIntervalMs, &counter); |
+ SetSampleAndAdvance(kSample3, kProcessIntervalMs, &counter); |
+ EXPECT_EQ(1, observer_->num_calls_); |
+ EXPECT_EQ(100, observer_->last_sample_); |
+ // Trigger process (sample included in next interval). |
+ counter.Set(2000); |
+ EXPECT_EQ(2, observer_->num_calls_); |
+ EXPECT_EQ(300, observer_->last_sample_); |
+ // Aggregated stats. |
+ StatsCounter::AggStats::Stats stats = counter.GetStats(); |
+ EXPECT_EQ(2, stats.num_samples); |
+ EXPECT_EQ(100, stats.min); |
+ EXPECT_EQ(300, stats.max); |
+ EXPECT_EQ(200, stats.average); |
+} |
+ |
+TEST_F(StatsCounterTest, TestAvgCounter_IntervalsWithoutSamplesIgnored) { |
+ AvgCounter counter(&clock_, observer_); |
+ AddSampleAndAdvance(6, kProcessIntervalMs * 4 - 1, &counter); |
+ // Trigger process (sample included in next interval). |
+ counter.Add(8); |
+ // [6:1], two intervals without samples passed. |
+ EXPECT_EQ(1, observer_->num_calls_); |
+ EXPECT_EQ(6, observer_->last_sample_); |
+ // Make last interval pass. |
+ clock_.AdvanceTimeMilliseconds(1); |
+ counter.Add(111); // Trigger process (sample included in next interval). |
+ // [6:1],[8:1] |
+ EXPECT_EQ(2, observer_->num_calls_); |
+ EXPECT_EQ(8, observer_->last_sample_); |
+ // Aggregated stats. |
+ StatsCounter::AggStats::Stats stats = counter.GetStats(); |
+ EXPECT_EQ(2, stats.num_samples); |
+ EXPECT_EQ(6, stats.min); |
+ EXPECT_EQ(8, stats.max); |
+} |
+ |
+TEST_F(StatsCounterTest, TestRateCounter_IntervalsWithoutSamplesIncluded) { |
+ const int kSample1 = 50; // 50 / 2 sec |
+ const int kSample2 = 20; // 20 / 2 sec |
+ RateCounter counter(&clock_, observer_); |
+ counter.Add(kSample1); |
+ clock_.AdvanceTimeMilliseconds(kProcessIntervalMs * 3 - 1); |
+ // Trigger process (sample included in next interval). |
+ counter.Add(kSample2); |
+ // [0:1],[25:1], one interval without samples passed. |
+ EXPECT_EQ(2, observer_->num_calls_); |
+ EXPECT_EQ(25, observer_->last_sample_); |
+ // Make last interval pass. |
+ clock_.AdvanceTimeMilliseconds(1); |
+ counter.Add(111); // Trigger process (sample included in next interval). |
+ // [0:1],[10:1],[25:1] |
+ EXPECT_EQ(3, observer_->num_calls_); |
+ EXPECT_EQ(10, observer_->last_sample_); |
+ // Aggregated stats. |
+ StatsCounter::AggStats::Stats stats = counter.GetStats(); |
+ EXPECT_EQ(3, stats.num_samples); |
+ EXPECT_EQ(0, stats.min); |
+ EXPECT_EQ(25, stats.max); |
+} |
+ |
+} // namespace webrtc |