|  | /* | 
|  | *  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 "video/stats_counter.h" | 
|  |  | 
|  | #include "system_wrappers/include/clock.h" | 
|  | #include "test/gtest.h" | 
|  |  | 
|  | namespace webrtc { | 
|  | namespace { | 
|  | const int kDefaultProcessIntervalMs = 2000; | 
|  | const uint32_t kStreamId = 123456; | 
|  |  | 
|  | 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) {} | 
|  |  | 
|  | 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, kStreamId); | 
|  | clock_.AdvanceTimeMilliseconds(interval_ms); | 
|  | } | 
|  |  | 
|  | void VerifyStatsIsNotSet(const AggregatedStats& stats) { | 
|  | EXPECT_EQ(0, stats.num_samples); | 
|  | EXPECT_EQ(-1, stats.min); | 
|  | EXPECT_EQ(-1, stats.max); | 
|  | EXPECT_EQ(-1, stats.average); | 
|  | } | 
|  |  | 
|  | SimulatedClock clock_; | 
|  | }; | 
|  |  | 
|  | TEST_F(StatsCounterTest, NoSamples) { | 
|  | AvgCounter counter(&clock_, nullptr, false); | 
|  | VerifyStatsIsNotSet(counter.GetStats()); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestRegisterObserver) { | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | const int kSample = 22; | 
|  | AvgCounter counter(&clock_, observer, false); | 
|  | AddSampleAndAdvance(kSample, kDefaultProcessIntervalMs, &counter); | 
|  | // Trigger process (sample included in next interval). | 
|  | counter.Add(111); | 
|  | EXPECT_EQ(1, observer->num_calls_); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, HasSample) { | 
|  | AvgCounter counter(&clock_, nullptr, false); | 
|  | EXPECT_FALSE(counter.HasSample()); | 
|  | counter.Add(1); | 
|  | EXPECT_TRUE(counter.HasSample()); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, VerifyProcessInterval) { | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | AvgCounter counter(&clock_, observer, false); | 
|  | counter.Add(4); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs - 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. | 
|  | AggregatedStats stats = counter.GetStats(); | 
|  | EXPECT_EQ(1, stats.num_samples); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestMetric_AvgCounter) { | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | AvgCounter counter(&clock_, observer, false); | 
|  | counter.Add(4); | 
|  | counter.Add(8); | 
|  | counter.Add(9); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | // 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. | 
|  | AggregatedStats 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_MaxCounter) { | 
|  | const int64_t kProcessIntervalMs = 1000; | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | MaxCounter counter(&clock_, observer, kProcessIntervalMs); | 
|  | counter.Add(4); | 
|  | counter.Add(9); | 
|  | counter.Add(8); | 
|  | clock_.AdvanceTimeMilliseconds(kProcessIntervalMs); | 
|  | // Trigger process (sample included in next interval). | 
|  | counter.Add(111); | 
|  | // Average per interval. | 
|  | EXPECT_EQ(1, observer->num_calls_); | 
|  | EXPECT_EQ(9, observer->last_sample_); | 
|  | // Aggregated stats. | 
|  | AggregatedStats stats = counter.GetStats(); | 
|  | EXPECT_EQ(1, stats.num_samples); | 
|  | EXPECT_EQ(9, stats.min); | 
|  | EXPECT_EQ(9, stats.max); | 
|  | EXPECT_EQ(9, stats.average); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestMetric_PercentCounter) { | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | PercentCounter counter(&clock_, observer); | 
|  | counter.Add(true); | 
|  | counter.Add(false); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | // 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. | 
|  | AggregatedStats stats = counter.GetStats(); | 
|  | EXPECT_EQ(1, stats.num_samples); | 
|  | EXPECT_EQ(50, stats.min); | 
|  | EXPECT_EQ(50, stats.max); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestMetric_PermilleCounter) { | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | PermilleCounter counter(&clock_, observer); | 
|  | counter.Add(true); | 
|  | counter.Add(false); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | // 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. | 
|  | AggregatedStats stats = counter.GetStats(); | 
|  | EXPECT_EQ(1, stats.num_samples); | 
|  | EXPECT_EQ(500, stats.min); | 
|  | EXPECT_EQ(500, stats.max); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestMetric_RateCounter) { | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | RateCounter counter(&clock_, observer, true); | 
|  | counter.Add(186); | 
|  | counter.Add(350); | 
|  | counter.Add(22); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | // 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. | 
|  | AggregatedStats stats = counter.GetStats(); | 
|  | EXPECT_EQ(1, stats.num_samples); | 
|  | EXPECT_EQ(279, stats.min); | 
|  | EXPECT_EQ(279, stats.max); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestMetric_RateAccCounter) { | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | RateAccCounter counter(&clock_, observer, true); | 
|  | counter.Set(175, kStreamId); | 
|  | counter.Set(188, kStreamId); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | // Trigger process (sample included in next interval). | 
|  | counter.Set(192, kStreamId); | 
|  | // Rate per interval: (188 - 0) / 2 sec = 94 samples/sec | 
|  | EXPECT_EQ(1, observer->num_calls_); | 
|  | EXPECT_EQ(94, observer->last_sample_); | 
|  | // Aggregated stats. | 
|  | AggregatedStats stats = counter.GetStats(); | 
|  | EXPECT_EQ(1, stats.num_samples); | 
|  | EXPECT_EQ(94, stats.min); | 
|  | EXPECT_EQ(94, stats.max); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestMetric_RateAccCounterWithSetLast) { | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | RateAccCounter counter(&clock_, observer, true); | 
|  | counter.SetLast(98, kStreamId); | 
|  | counter.Set(175, kStreamId); | 
|  | counter.Set(188, kStreamId); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | // Trigger process (sample included in next interval). | 
|  | counter.Set(192, kStreamId); | 
|  | // Rate per interval: (188 - 98) / 2 sec = 45 samples/sec | 
|  | EXPECT_EQ(1, observer->num_calls_); | 
|  | EXPECT_EQ(45, observer->last_sample_); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestMetric_RateAccCounterWithMultipleStreamIds) { | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | RateAccCounter counter(&clock_, observer, true); | 
|  | counter.Set(175, kStreamId); | 
|  | counter.Set(188, kStreamId); | 
|  | counter.Set(100, kStreamId + 1); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | // Trigger process (sample included in next interval). | 
|  | counter.Set(150, kStreamId + 1); | 
|  | // Rate per interval: ((188 - 0) + (100 - 0)) / 2 sec = 144 samples/sec | 
|  | EXPECT_EQ(1, observer->num_calls_); | 
|  | EXPECT_EQ(144, observer->last_sample_); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | // Trigger process (sample included in next interval). | 
|  | counter.Set(198, kStreamId); | 
|  | // Rate per interval: (0 + (150 - 100)) / 2 sec = 25 samples/sec | 
|  | EXPECT_EQ(2, observer->num_calls_); | 
|  | EXPECT_EQ(25, observer->last_sample_); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | // Trigger process (sample included in next interval). | 
|  | counter.Set(200, kStreamId); | 
|  | // Rate per interval: ((198 - 188) + (0)) / 2 sec = 5 samples/sec | 
|  | EXPECT_EQ(3, observer->num_calls_); | 
|  | EXPECT_EQ(5, observer->last_sample_); | 
|  | // Aggregated stats. | 
|  | AggregatedStats stats = counter.GetStats(); | 
|  | EXPECT_EQ(3, stats.num_samples); | 
|  | EXPECT_EQ(5, stats.min); | 
|  | EXPECT_EQ(144, stats.max); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestGetStats_MultipleIntervals) { | 
|  | AvgCounter counter(&clock_, nullptr, false); | 
|  | const int kSample1 = 1; | 
|  | const int kSample2 = 5; | 
|  | const int kSample3 = 8; | 
|  | const int kSample4 = 11; | 
|  | const int kSample5 = 50; | 
|  | AddSampleAndAdvance(kSample1, kDefaultProcessIntervalMs, &counter); | 
|  | AddSampleAndAdvance(kSample2, kDefaultProcessIntervalMs, &counter); | 
|  | AddSampleAndAdvance(kSample3, kDefaultProcessIntervalMs, &counter); | 
|  | AddSampleAndAdvance(kSample4, kDefaultProcessIntervalMs, &counter); | 
|  | AddSampleAndAdvance(kSample5, kDefaultProcessIntervalMs, &counter); | 
|  | // Trigger process (sample included in next interval). | 
|  | counter.Add(111); | 
|  | AggregatedStats 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, false); | 
|  | AddSampleAndAdvance(kSample1, kDefaultProcessIntervalMs, &counter); | 
|  | // Trigger process (sample included in next interval). | 
|  | counter.Add(kSample2); | 
|  | AggregatedStats 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(kDefaultProcessIntervalMs); | 
|  | 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) { | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | 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, true); | 
|  | SetSampleAndAdvance(kSample1, kDefaultProcessIntervalMs, &counter); | 
|  | SetSampleAndAdvance(kSample2, kDefaultProcessIntervalMs, &counter); | 
|  | SetSampleAndAdvance(kSample3, kDefaultProcessIntervalMs, &counter); | 
|  | EXPECT_EQ(1, observer->num_calls_); | 
|  | EXPECT_EQ(100, observer->last_sample_); | 
|  | // Trigger process (sample included in next interval). | 
|  | counter.Set(2000, kStreamId); | 
|  | EXPECT_EQ(2, observer->num_calls_); | 
|  | EXPECT_EQ(300, observer->last_sample_); | 
|  | // Aggregated stats. | 
|  | AggregatedStats 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_IntervalsWithoutSamplesIncluded) { | 
|  | // Samples: | 6 | x | x | 8 |  // x: empty interval | 
|  | // Stats:   | 6 | 6 | 6 | 8 |  // x -> last value reported | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | AvgCounter counter(&clock_, observer, true); | 
|  | AddSampleAndAdvance(6, kDefaultProcessIntervalMs * 4 - 1, &counter); | 
|  | // Trigger process (sample included in next interval). | 
|  | counter.Add(8); | 
|  | // [6:3], 3 intervals passed (2 without samples -> last value reported). | 
|  | AggregatedStats stats = counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(3, stats.num_samples); | 
|  | EXPECT_EQ(6, stats.min); | 
|  | EXPECT_EQ(6, stats.max); | 
|  | // Make next interval pass and verify stats: [6:3],[8:1] | 
|  | clock_.AdvanceTimeMilliseconds(1); | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(4, observer->num_calls_); | 
|  | EXPECT_EQ(8, observer->last_sample_); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestAvgCounter_WithPause) { | 
|  | // Samples: | 6 | x | x | x | - | 22 | x  |  // x: empty interval, -: paused | 
|  | // Stats:   | 6 | 6 | 6 | 6 | - | 22 | 22 |  // x -> last value reported | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | AvgCounter counter(&clock_, observer, true); | 
|  | // Add sample and advance 3 intervals (2 w/o samples -> last value reported). | 
|  | AddSampleAndAdvance(6, kDefaultProcessIntervalMs * 4 - 1, &counter); | 
|  | // Trigger process and verify stats: [6:3] | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(3, observer->num_calls_); | 
|  | EXPECT_EQ(6, observer->last_sample_); | 
|  | // Make next interval pass (1 without samples). | 
|  | // Process and pause. Verify stats: [6:4]. | 
|  | clock_.AdvanceTimeMilliseconds(1); | 
|  | counter.ProcessAndPause(); | 
|  | EXPECT_EQ(4, observer->num_calls_);  // Last value reported. | 
|  | EXPECT_EQ(6, observer->last_sample_); | 
|  | // Make next interval pass (1 without samples -> ignored while paused). | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs * 2 - 1); | 
|  | counter.Add(22);  // Stops pause. | 
|  | EXPECT_EQ(4, observer->num_calls_); | 
|  | EXPECT_EQ(6, observer->last_sample_); | 
|  | // Make next interval pass, [6:4][22:1] | 
|  | clock_.AdvanceTimeMilliseconds(1); | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(5, observer->num_calls_); | 
|  | EXPECT_EQ(22, observer->last_sample_); | 
|  | // Make 1 interval pass (1 w/o samples -> pause stopped, last value reported). | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(6, observer->num_calls_); | 
|  | EXPECT_EQ(22, observer->last_sample_); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestRateAccCounter_AddSampleStopsPause) { | 
|  | // Samples: | 12 | 24 |  // -: paused | 
|  | // Stats:   | 6  | 6  | | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | RateAccCounter counter(&clock_, observer, true); | 
|  | // Add sample and advance 1 intervals. | 
|  | counter.Set(12, kStreamId); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | // Trigger process and verify stats: [6:1] | 
|  | counter.ProcessAndPause(); | 
|  | EXPECT_EQ(1, observer->num_calls_); | 
|  | EXPECT_EQ(6, observer->last_sample_); | 
|  | // Add sample and advance 1 intervals. | 
|  | counter.Set(24, kStreamId);  // Pause stopped. | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(2, observer->num_calls_); | 
|  | EXPECT_EQ(6, observer->last_sample_); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestRateAccCounter_AddSameSampleDoesNotStopPause) { | 
|  | // Samples: | 12 | 12 | 24 |  // -: paused | 
|  | // Stats:   | 6  | -  | 6  | | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | RateAccCounter counter(&clock_, observer, true); | 
|  | // Add sample and advance 1 intervals. | 
|  | counter.Set(12, kStreamId); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | // Trigger process and verify stats: [6:1] | 
|  | counter.ProcessAndPause(); | 
|  | EXPECT_EQ(1, observer->num_calls_); | 
|  | EXPECT_EQ(6, observer->last_sample_); | 
|  | // Add same sample and advance 1 intervals. | 
|  | counter.Set(12, kStreamId);  // Pause not stopped. | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(1, observer->num_calls_); | 
|  | EXPECT_EQ(6, observer->last_sample_); | 
|  | // Add new sample and advance 1 intervals. | 
|  | counter.Set(24, kStreamId);  // Pause stopped. | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(2, observer->num_calls_); | 
|  | EXPECT_EQ(6, observer->last_sample_); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestRateAccCounter_PauseAndStopPause) { | 
|  | // Samples: | 12 | 12 | 12 |  // -: paused | 
|  | // Stats:   | 6  | -  | 0  | | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | RateAccCounter counter(&clock_, observer, true); | 
|  | // Add sample and advance 1 intervals. | 
|  | counter.Set(12, kStreamId); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | // Trigger process and verify stats: [6:1] | 
|  | counter.ProcessAndPause(); | 
|  | EXPECT_EQ(1, observer->num_calls_); | 
|  | EXPECT_EQ(6, observer->last_sample_); | 
|  | // Add same sample and advance 1 intervals. | 
|  | counter.Set(12, kStreamId);  // Pause not stopped. | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(1, observer->num_calls_); | 
|  | EXPECT_EQ(6, observer->last_sample_); | 
|  | // Stop pause, add sample and advance 1 intervals. | 
|  | counter.ProcessAndStopPause(); | 
|  | counter.Set(12, kStreamId); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(2, observer->num_calls_); | 
|  | EXPECT_EQ(0, observer->last_sample_); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestAvgCounter_WithoutMinPauseTimePassed) { | 
|  | // Samples: | 6 | 2 | - |  // x: empty interval, -: paused | 
|  | // Stats:   | 6 | 2 | - |  // x -> last value reported | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | AvgCounter counter(&clock_, observer, true); | 
|  | // Add sample and advance 1 intervals. | 
|  | AddSampleAndAdvance(6, kDefaultProcessIntervalMs, &counter); | 
|  | // Process and pause. Verify stats: [6:1]. | 
|  | const int64_t kMinMs = 500; | 
|  | counter.ProcessAndPauseForDuration(kMinMs); | 
|  | EXPECT_EQ(1, observer->num_calls_);  // Last value reported. | 
|  | EXPECT_EQ(6, observer->last_sample_); | 
|  | // Min pause time has not pass. | 
|  | clock_.AdvanceTimeMilliseconds(kMinMs - 1); | 
|  | counter.Add(2);  // Pause not stopped. | 
|  | // Make two intervals pass (1 without samples -> ignored while paused). | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs * 2 - (kMinMs - 1)); | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(2, observer->num_calls_); | 
|  | EXPECT_EQ(2, observer->last_sample_); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestAvgCounter_WithMinPauseTimePassed) { | 
|  | // Samples: | 6 | 2 | x |  // x: empty interval, -: paused | 
|  | // Stats:   | 6 | 2 | 2 |  // x -> last value reported | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | AvgCounter counter(&clock_, observer, true); | 
|  | // Add sample and advance 1 intervals. | 
|  | AddSampleAndAdvance(6, kDefaultProcessIntervalMs, &counter); | 
|  | // Process and pause. Verify stats: [6:1]. | 
|  | const int64_t kMinMs = 500; | 
|  | counter.ProcessAndPauseForDuration(kMinMs); | 
|  | EXPECT_EQ(1, observer->num_calls_);  // Last value reported. | 
|  | EXPECT_EQ(6, observer->last_sample_); | 
|  | // Make min pause time pass. | 
|  | clock_.AdvanceTimeMilliseconds(kMinMs); | 
|  | counter.Add(2);  // Stop pause. | 
|  | // Make two intervals pass (1 without samples -> last value reported). | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs * 2 - kMinMs); | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(3, observer->num_calls_); | 
|  | EXPECT_EQ(2, observer->last_sample_); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestRateCounter_IntervalsWithoutSamplesIgnored) { | 
|  | // Samples: | 50 | x | 20 |  // x: empty interval | 
|  | // Stats:   | 25 | x | 10 |  // x -> ignored | 
|  | const bool kIncludeEmptyIntervals = false; | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | const int kSample1 = 50;  //  50 / 2 sec | 
|  | const int kSample2 = 20;  //  20 / 2 sec | 
|  | RateCounter counter(&clock_, observer, kIncludeEmptyIntervals); | 
|  | counter.Add(kSample1); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs * 3 - 1); | 
|  | // Trigger process (sample included in next interval). | 
|  | counter.Add(kSample2); | 
|  | // [25:1], 2 intervals passed (1 without samples -> ignored). | 
|  | EXPECT_EQ(1, observer->num_calls_); | 
|  | EXPECT_EQ(25, observer->last_sample_); | 
|  | // Make next interval pass and verify stats: [10:1],[25:1] | 
|  | clock_.AdvanceTimeMilliseconds(1); | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(2, observer->num_calls_); | 
|  | EXPECT_EQ(10, observer->last_sample_); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestRateCounter_IntervalsWithoutSamplesIncluded) { | 
|  | // Samples: | 50 | x | 20 |  // x: empty interval | 
|  | // Stats:   | 25 | 0 | 10 |  // x -> zero reported | 
|  | const bool kIncludeEmptyIntervals = true; | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | const int kSample1 = 50;  //  50 / 2 sec | 
|  | const int kSample2 = 20;  //  20 / 2 sec | 
|  | RateCounter counter(&clock_, observer, kIncludeEmptyIntervals); | 
|  | counter.Add(kSample1); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs * 3 - 1); | 
|  | // Trigger process (sample included in next interval). | 
|  | counter.Add(kSample2); | 
|  | // [0:1],[25:1], 2 intervals passed (1 without samples -> zero reported). | 
|  | EXPECT_EQ(2, observer->num_calls_); | 
|  | EXPECT_EQ(0, observer->last_sample_); | 
|  | // Make last interval pass and verify stats: [0:1],[10:1],[25:1] | 
|  | clock_.AdvanceTimeMilliseconds(1); | 
|  | AggregatedStats stats = counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(25, stats.max); | 
|  | EXPECT_EQ(3, observer->num_calls_); | 
|  | EXPECT_EQ(10, observer->last_sample_); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestRateAccCounter_IntervalsWithoutSamplesIncluded) { | 
|  | // Samples: | 12 | x | x | x | 60 |  // x: empty interval | 
|  | // Stats:   | 6  | 0 | 0 | 0 | 24 |  // x -> zero reported | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | RateAccCounter counter(&clock_, observer, true); | 
|  | VerifyStatsIsNotSet(counter.ProcessAndGetStats()); | 
|  | // Advance one interval and verify stats. | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs); | 
|  | VerifyStatsIsNotSet(counter.ProcessAndGetStats()); | 
|  | // Add sample and advance 3 intervals (2 w/o samples -> zero reported). | 
|  | counter.Set(12, kStreamId); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs * 4 - 1); | 
|  | // Trigger process and verify stats: [0:2][6:1] | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(3, observer->num_calls_); | 
|  | EXPECT_EQ(0, observer->last_sample_); | 
|  | // Make next interval pass (1 w/o samples -> zero reported), [0:3][6:1] | 
|  | clock_.AdvanceTimeMilliseconds(1); | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(4, observer->num_calls_); | 
|  | EXPECT_EQ(0, observer->last_sample_); | 
|  | // Insert sample and advance non-complete interval, no change, [0:3][6:1] | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs - 1); | 
|  | counter.Set(60, kStreamId); | 
|  | EXPECT_EQ(4, observer->num_calls_); | 
|  | // Make next interval pass, [0:3][6:1][24:1] | 
|  | clock_.AdvanceTimeMilliseconds(1); | 
|  | AggregatedStats stats = counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(5, observer->num_calls_); | 
|  | EXPECT_EQ(24, observer->last_sample_); | 
|  | EXPECT_EQ(6, stats.average); | 
|  | } | 
|  |  | 
|  | TEST_F(StatsCounterTest, TestRateAccCounter_IntervalsWithoutSamplesIgnored) { | 
|  | // Samples: | 12 | x | x | x | 60 |  // x: empty interval | 
|  | // Stats:   | 6  | x | x | x | 24 |  // x -> ignored | 
|  | StatsCounterObserverImpl* observer = new StatsCounterObserverImpl(); | 
|  | RateAccCounter counter(&clock_, observer, false); | 
|  | // Add sample and advance 3 intervals (2 w/o samples -> ignored). | 
|  | counter.Set(12, kStreamId); | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs * 4 - 1); | 
|  | // Trigger process and verify stats: [6:1] | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(1, observer->num_calls_); | 
|  | EXPECT_EQ(6, observer->last_sample_); | 
|  | // Make next interval pass (1 w/o samples -> ignored), [6:1] | 
|  | clock_.AdvanceTimeMilliseconds(1); | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(1, observer->num_calls_); | 
|  | // Insert sample and advance non-complete interval, no change, [6:1] | 
|  | clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs - 1); | 
|  | counter.Set(60, kStreamId); | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(1, observer->num_calls_); | 
|  | // Make next interval pass, [6:1][24:1] | 
|  | clock_.AdvanceTimeMilliseconds(1); | 
|  | counter.ProcessAndGetStats(); | 
|  | EXPECT_EQ(2, observer->num_calls_); | 
|  | EXPECT_EQ(24, observer->last_sample_); | 
|  | } | 
|  |  | 
|  | }  // namespace webrtc |