Upload upstream chromium 114.0.5735.31
[platform/framework/web/chromium-efl.git] / media / mojo / services / webrtc_video_perf_history_unittest.cc
1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <map>
6 #include <memory>
7 #include <string>
8
9 #include "base/functional/bind.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/run_loop.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/test/bind.h"
14 #include "base/test/scoped_feature_list.h"
15 #include "base/test/task_environment.h"
16 #include "media/base/media_switches.h"
17 #include "media/capabilities/webrtc_video_stats_db.h"
18 #include "media/mojo/mojom/media_types.mojom.h"
19 #include "media/mojo/services/webrtc_video_perf_history.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 using testing::_;
24 using testing::IsNull;
25
26 namespace media {
27 namespace {
28
29 // Aliases for readability.
30 constexpr bool kIsDecode = true;
31 constexpr bool kIsEncode = false;
32 constexpr bool kHardware = true;
33 constexpr bool kSoftware = false;
34 constexpr bool kIsSmooth = true;
35 constexpr bool kIsNotSmooth = false;
36 constexpr VideoCodecProfile kKnownProfile = VP9PROFILE_PROFILE0;
37 constexpr int32_t kPixelsHd = 1280 * 720;
38 constexpr int32_t kPixelsFullHd = 1920 * 1080;
39 constexpr int32_t kPixels4K = 3840 * 2160;
40 constexpr int kFramesProcessed = 1000;
41 constexpr int kKeyFramesProcessed = 4;
42
43 }  // namespace
44
45 class FakeWebrtcVideoStatsDB : public WebrtcVideoStatsDB {
46  public:
47   FakeWebrtcVideoStatsDB() = default;
48   ~FakeWebrtcVideoStatsDB() override = default;
49
50   // Call CompleteInitialize(...) to run `init_cb` callback.
51   void Initialize(base::OnceCallback<void(bool)> init_cb) override {
52     EXPECT_FALSE(!!pendnding_init_cb_);
53     pendnding_init_cb_ = std::move(init_cb);
54   }
55
56   // Completes fake initialization, running `init_cb` with the supplied value
57   // for success.
58   void CompleteInitialize(bool success) {
59     DVLOG(2) << __func__ << " running with success = " << success;
60     EXPECT_TRUE(!!pendnding_init_cb_);
61     std::move(pendnding_init_cb_).Run(success);
62   }
63
64   // Simple hooks to fail the next calls to AppendDecodeStats() and
65   // GetDecodeStats(). Will be reset to false after the call.
66   void set_fail_next_append(bool fail_append) {
67     fail_next_append_ = fail_append;
68   }
69   void set_fail_next_get(bool fail_get) { fail_next_get_ = fail_get; }
70
71   void AppendVideoStats(const VideoDescKey& key,
72                         const VideoStats& new_stats,
73                         AppendVideoStatsCB append_done_cb) override {
74     if (fail_next_append_) {
75       fail_next_append_ = false;
76       std::move(append_done_cb).Run(false);
77       return;
78     }
79
80     std::string key_str = key.Serialize();
81     if (entries_.find(key_str) == entries_.end()) {
82       entries_.emplace(std::make_pair(key_str, VideoStatsEntry{new_stats}));
83     } else {
84       VideoStatsEntry& known_entry = entries_.at(key_str);
85       known_entry.insert(
86           known_entry.begin(),
87           VideoStats(new_stats.frames_processed, new_stats.key_frames_processed,
88                      new_stats.p99_processing_time_ms));
89     }
90
91     std::move(append_done_cb).Run(true);
92   }
93
94   void GetVideoStats(const VideoDescKey& key,
95                      GetVideoStatsCB get_stats_cb) override {
96     if (fail_next_get_) {
97       fail_next_get_ = false;
98       std::move(get_stats_cb).Run(false, absl::nullopt);
99       return;
100     }
101
102     auto entry_it = entries_.find(key.Serialize());
103     if (entry_it == entries_.end()) {
104       std::move(get_stats_cb).Run(true, absl::nullopt);
105     } else {
106       std::move(get_stats_cb).Run(true, entry_it->second);
107     }
108   }
109
110   void GetVideoStatsCollection(
111       const VideoDescKey& key,
112       GetVideoStatsCollectionCB get_stats_cb) override {
113     if (fail_next_get_) {
114       fail_next_get_ = false;
115       std::move(get_stats_cb).Run(false, absl::nullopt);
116       return;
117     }
118
119     WebrtcVideoStatsDB::VideoStatsCollection collection;
120     std::string key_filter = key.SerializeWithoutPixels();
121     for (auto const& [str, video_stats_entry] : entries_) {
122       if (str.rfind(key_filter, 0) == 0) {
123         absl::optional<int> pixels = VideoDescKey::ParsePixelsFromKey(str);
124         if (pixels) {
125           collection.insert({*pixels, std::move(video_stats_entry)});
126         }
127       }
128     }
129     if (collection.empty()) {
130       std::move(get_stats_cb).Run(true, absl::nullopt);
131     } else {
132       std::move(get_stats_cb).Run(true, std::move(collection));
133     }
134   }
135
136   void ClearStats(base::OnceClosure clear_done_cb) override {
137     entries_.clear();
138     std::move(clear_done_cb).Run();
139   }
140
141  private:
142   bool fail_next_append_ = false;
143   bool fail_next_get_ = false;
144
145   std::map<std::string, VideoStatsEntry> entries_;
146
147   base::OnceCallback<void(bool)> pendnding_init_cb_;
148 };
149
150 class WebrtcVideoPerfHistoryTest : public testing::Test {
151  public:
152   void SetUp() override {
153     perf_history_ = std::make_unique<WebrtcVideoPerfHistory>(
154         std::make_unique<FakeWebrtcVideoStatsDB>());
155   }
156
157   void TearDown() override { perf_history_.reset(); }
158
159   FakeWebrtcVideoStatsDB* GetFakeDB() {
160     return static_cast<FakeWebrtcVideoStatsDB*>(perf_history_->db_.get());
161   }
162
163   void PreInitializeDB(bool success) {
164     // Invoke private method to start initialization. Usually invoked by first
165     // API call requiring DB access.
166     perf_history_->InitDatabase();
167     // Complete initialization by firing callback from our fake DB.
168     GetFakeDB()->CompleteInitialize(success);
169   }
170
171   // Tests may set this as the callback for WebrtcVideoPerfHistory::GetPerfInfo
172   // to check the results of the call.
173   MOCK_METHOD1(MockGetPerfInfoCB, void(bool is_smooth));
174
175   // Tests may set this as the callback for
176   // WebrtcVideoPerfHistory::SavePerfRecord to verify that the data is stored.
177   MOCK_METHOD0(MockSaveDoneCB, void());
178
179   // Tests should EXPECT_CALL this method prior to ClearHistory() to know that
180   // the operation has completed.
181   MOCK_METHOD0(MockOnClearedHistory, void());
182
183   MOCK_METHOD1(MockGetWebrtcVideoStatsDBCB, void(WebrtcVideoStatsDB* db));
184
185   void SavePerfRecord(mojom::WebrtcPredictionFeatures features,
186                       mojom::WebrtcVideoStats video_stats,
187                       bool expect_callback) {
188     base::OnceClosure save_done_cb = base::BindOnce(
189         &WebrtcVideoPerfHistoryTest::MockSaveDoneCB, base::Unretained(this));
190     if (expect_callback) {
191       EXPECT_CALL(*this, MockSaveDoneCB());
192     }
193     perf_history_->GetSaveCallback().Run(features, video_stats,
194                                          std::move(save_done_cb));
195   }
196   void SavePerfRecord(mojom::WebrtcPredictionFeatures features,
197                       mojom::WebrtcVideoStats video_stats) {
198     SavePerfRecord(std::move(features), std::move(video_stats),
199                    /*expect_callback=*/true);
200   }
201
202  protected:
203   using VideoDescKey = WebrtcVideoStatsDB::VideoDescKey;
204   using VideoStatsEntry = WebrtcVideoStatsDB::VideoStatsEntry;
205   using Features = media::mojom::WebrtcPredictionFeatures;
206   using VideoStats = media::mojom::WebrtcVideoStats;
207
208   float GetSmoothnessThreshold(bool is_decode) {
209     return WebrtcVideoPerfHistory::GetSmoothnessThreshold(is_decode);
210   }
211
212   float GetSmoothDecisionRatioThreshold() {
213     return WebrtcVideoPerfHistory::GetSmoothDecisionRatioThreshold();
214   }
215
216   base::test::TaskEnvironment task_environment_;
217
218   // The WebrtcVideoStatsReporter being tested.
219   std::unique_ptr<WebrtcVideoPerfHistory> perf_history_;
220 };
221
222 struct WebrtcPerfHistoryTestParams {
223   const bool defer_initialize;
224 };
225
226 // When bool param is true, tests should wait until the end to run
227 // GetFakeDB()->CompleteInitialize(). Otherwise run PreInitializeDB() at the
228 // test start.
229 class WebrtcVideoPerfHistoryParamTest
230     : public testing::WithParamInterface<WebrtcPerfHistoryTestParams>,
231       public WebrtcVideoPerfHistoryTest {};
232
233 TEST_P(WebrtcVideoPerfHistoryParamTest, GetPerfInfo) {
234   // NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
235   // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
236   // that EXPECT_CALLs arrive in top-to-bottom order.
237   WebrtcPerfHistoryTestParams params = GetParam();
238   testing::InSequence dummy;
239
240   // Complete initialization in advance of API calls when not asked to defer.
241   if (!params.defer_initialize)
242     PreInitializeDB(/*success=*/true);
243
244   // First add 2 records to the history. First record with HD resolution and
245   // second with Full HD resolution.
246   constexpr float kP99ProcessingTimeMsSmoothAt60Hz = 12.0f;
247   constexpr float kP99ProcessingTimeMsSmoothAt30Hz = 24.0f;
248
249   // Add the entries.
250   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
251                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
252                             kP99ProcessingTimeMsSmoothAt60Hz));
253   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
254                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
255                             kP99ProcessingTimeMsSmoothAt30Hz));
256
257   // Verify perf history returns is_smooth = true for HD at 30 and 60 fps.
258   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
259   perf_history_->GetPerfInfo(
260       Features::New(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
261       /*frames_per_second=*/30,
262       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
263                      base::Unretained(this)));
264   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
265   perf_history_->GetPerfInfo(
266       Features::New(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
267       /*frames_per_second=*/60,
268       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
269                      base::Unretained(this)));
270
271   // Verify perf history returns is_smooth = true for Full HD at 30 fps and
272   // is_smooth = false for Full HD at 60 fps.
273   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
274   perf_history_->GetPerfInfo(
275       Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
276       /*frames_per_second=*/30,
277       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
278                      base::Unretained(this)));
279   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
280   perf_history_->GetPerfInfo(
281       Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
282       /*frames_per_second=*/60,
283       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
284                      base::Unretained(this)));
285
286   // Verify perf history optimistically returns is_smooth = true when no entry
287   // can be found with the given configuration.
288   constexpr VideoCodecProfile kUnknownProfile = VP9PROFILE_PROFILE2;
289   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
290   perf_history_->GetPerfInfo(
291       Features::New(kIsDecode, kUnknownProfile, kPixelsFullHd, kSoftware),
292       /*frames_per_second=*/60,
293       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
294                      base::Unretained(this)));
295
296   // Complete successful deferred DB initialization (see comment at top of test)
297   if (params.defer_initialize) {
298     GetFakeDB()->CompleteInitialize(true);
299
300     // Allow initialize-deferred API calls to complete.
301     task_environment_.RunUntilIdle();
302   }
303 }
304
305 // Test to override the smoothness threshold by setting the corresponding field
306 // trial parameter.
307 TEST_P(WebrtcVideoPerfHistoryParamTest,
308        GetPerfInfoSmoothnessThresholdOverride) {
309   // NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
310   // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
311   // that EXPECT_CALLs arrive in top-to-bottom order.
312   WebrtcPerfHistoryTestParams params = GetParam();
313   testing::InSequence dummy;
314
315   base::test::ScopedFeatureList scoped_feature_list;
316   std::unique_ptr<base::FieldTrialList> field_trial_list;
317
318   float previousSmoothnessThresholdDecode = GetSmoothnessThreshold(kIsDecode);
319   float previousSmoothnessThresholdEncode = GetSmoothnessThreshold(kIsEncode);
320   // The 99th percentile decode time must be lower than 50% of 1/fps to be
321   // considered smooth.
322   float kNewSmoothnessThresholdDecode = 0.5f;
323   // The 99th percentile encode time must be lower than 120% of 1/fps to be
324   // considered smooth.
325   float kNewSmoothnessThresholdEncode = 1.2f;
326
327   // Override field trial.
328   base::FieldTrialParams field_trial_params;
329   field_trial_params["smoothness_threshold_decode"] =
330       base::NumberToString(kNewSmoothnessThresholdDecode);
331   field_trial_params["smoothness_threshold_encode"] =
332       base::NumberToString(kNewSmoothnessThresholdEncode);
333   scoped_feature_list.InitAndEnableFeatureWithParameters(
334       media::kWebrtcMediaCapabilitiesParameters, field_trial_params);
335   EXPECT_NE(kNewSmoothnessThresholdDecode, previousSmoothnessThresholdDecode);
336   EXPECT_NE(kNewSmoothnessThresholdEncode, previousSmoothnessThresholdEncode);
337   EXPECT_EQ(kNewSmoothnessThresholdDecode, GetSmoothnessThreshold(kIsDecode));
338   EXPECT_EQ(kNewSmoothnessThresholdEncode, GetSmoothnessThreshold(kIsEncode));
339
340   // Complete initialization in advance of API calls when not asked to defer.
341   if (!params.defer_initialize)
342     PreInitializeDB(/*success=*/true);
343
344   constexpr int kFramesPerSecond = 30;
345
346   // Add a Full HD decode entry just above the new threshold.
347   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
348                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
349                             /*p99_processing_time_ms=*/1.01 *
350                                 kNewSmoothnessThresholdDecode * 1000.0 /
351                                 kFramesPerSecond));
352   // Add an HD decode entry just below the new threshold.
353   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
354                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
355                             /*p99_processing_time_ms=*/0.99 *
356                                 kNewSmoothnessThresholdDecode * 1000.0 /
357                                 kFramesPerSecond));
358
359   // Verify that Full HD is not smooth and HD is smooth.
360   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
361   perf_history_->GetPerfInfo(
362       Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
363       kFramesPerSecond,
364       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
365                      base::Unretained(this)));
366
367   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
368   perf_history_->GetPerfInfo(
369       Features::New(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
370       kFramesPerSecond,
371       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
372                      base::Unretained(this)));
373
374   // Add a Full HD encdde entry just above the new threshold.
375   SavePerfRecord(Features(kIsEncode, kKnownProfile, kPixelsFullHd, kSoftware),
376                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
377                             /*p99_processing_time_ms=*/1.01 *
378                                 kNewSmoothnessThresholdEncode * 1000.0 /
379                                 kFramesPerSecond));
380   // Add an HD encode entry just below the new threshold.
381   SavePerfRecord(Features(kIsEncode, kKnownProfile, kPixelsHd, kSoftware),
382                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
383                             /*p99_processing_time_ms=*/0.99 *
384                                 kNewSmoothnessThresholdEncode * 1000.0 /
385                                 kFramesPerSecond));
386
387   // Verify that Full HD is not smooth and HD is smooth.
388   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
389   perf_history_->GetPerfInfo(
390       Features::New(kIsEncode, kKnownProfile, kPixelsFullHd, kSoftware),
391       kFramesPerSecond,
392       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
393                      base::Unretained(this)));
394
395   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
396   perf_history_->GetPerfInfo(
397       Features::New(kIsEncode, kKnownProfile, kPixelsHd, kSoftware),
398       kFramesPerSecond,
399       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
400                      base::Unretained(this)));
401
402   // Complete successful deferred DB initialization (see comment at top of test)
403   if (params.defer_initialize) {
404     GetFakeDB()->CompleteInitialize(true);
405
406     // Allow initialize-deferred API calls to complete.
407     task_environment_.RunUntilIdle();
408   }
409 }
410
411 // Verify that the combined smoothness prediction is correct in the case that
412 // the database contains entries with mixed smoothness predicitions.
413 TEST_P(WebrtcVideoPerfHistoryParamTest, GetPerfInfoCombinedPrediction) {
414   // NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
415   // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
416   // that EXPECT_CALLs arrive in top-to-bottom order.
417   WebrtcPerfHistoryTestParams params = GetParam();
418   testing::InSequence dummy;
419
420   // Complete initialization in advance of API calls when not asked to defer.
421   if (!params.defer_initialize)
422     PreInitializeDB(/*success=*/true);
423
424   constexpr float kP99ProcessingTimeMsSmoothAt60Hz = 12.0f;
425   constexpr float kP99ProcessingTimeMsSmoothAt30Hz = 24.0f;
426
427   // The SmoothDecisionRatioThreshold determines the minimum ratio of smooth
428   // entries for the combined prediction to be considered smooth.
429   constexpr int kNumberOfEntries = 10;
430   const float kSmoothDecisionRatioThreshold = GetSmoothDecisionRatioThreshold();
431   const int kNotSmoothEntries =
432       kNumberOfEntries * (1 - kSmoothDecisionRatioThreshold);
433   const int kSmoothEntries = kNumberOfEntries - kNotSmoothEntries;
434
435   // Add `kNotSmoothEntries` that are not smooth at 60 fps.
436   for (int i = 0; i < kNotSmoothEntries; ++i) {
437     // Add the entries.
438     SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
439                    VideoStats(kFramesProcessed, kKeyFramesProcessed,
440                               kP99ProcessingTimeMsSmoothAt30Hz));
441   }
442   // Verify perf history returns is_smooth = false at 60 fps.
443   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
444   perf_history_->GetPerfInfo(
445       Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
446       /*frames_per_second=*/60,
447       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
448                      base::Unretained(this)));
449
450   // Add `kSmoothEntries` - 1 that are smooth at 60 fps and verify that
451   // is_smooth = false still.
452   for (int i = 0; i < kSmoothEntries - 1; ++i) {
453     // Add the entries.
454     SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
455                    VideoStats(kFramesProcessed, kKeyFramesProcessed,
456                               kP99ProcessingTimeMsSmoothAt60Hz));
457   }
458   // Verify perf history returns is_smooth = false at 60 fps.
459   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
460   perf_history_->GetPerfInfo(
461       Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
462       /*frames_per_second=*/60,
463       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
464                      base::Unretained(this)));
465
466   // Add one more entry and verify that is_smooth = true now.
467   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
468                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
469                             kP99ProcessingTimeMsSmoothAt60Hz));
470   // Verify perf history returns is_smooth = true at 60 fps.
471   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
472   perf_history_->GetPerfInfo(
473       Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
474       /*frames_per_second=*/60,
475       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
476                      base::Unretained(this)));
477
478   // Add 5 more entries that are smooth at 60 fps and verify that is_smooth =
479   // true still.
480   for (int i = 0; i < 5 - 1; ++i) {
481     // Add the entries.
482     SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
483                    VideoStats(kFramesProcessed, kKeyFramesProcessed,
484                               kP99ProcessingTimeMsSmoothAt60Hz));
485   }
486   // Verify perf history returns is_smooth = true at 60 fps.
487   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
488   perf_history_->GetPerfInfo(
489       Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
490       /*frames_per_second=*/60,
491       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
492                      base::Unretained(this)));
493
494   // Complete successful deferred DB initialization (see comment at top of test)
495   if (params.defer_initialize) {
496     GetFakeDB()->CompleteInitialize(true);
497
498     // Allow initialize-deferred API calls to complete.
499     task_environment_.RunUntilIdle();
500   }
501 }
502
503 // Test to override smooth decision ratio threshold by setting the corresponding
504 // field trial parameter.
505 TEST_P(WebrtcVideoPerfHistoryParamTest,
506        GetPerfInfoSmoothDecisionRatioThresholdOverride) {
507   // NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
508   // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
509   // that EXPECT_CALLs arrive in top-to-bottom order.
510   WebrtcPerfHistoryTestParams params = GetParam();
511   testing::InSequence dummy;
512
513   base::test::ScopedFeatureList scoped_feature_list;
514   std::unique_ptr<base::FieldTrialList> field_trial_list;
515   // Override the smooth decision ratio threshold through the field trial.
516   float previousSmoothDecisionRatioThreshold =
517       GetSmoothDecisionRatioThreshold();
518   // The ratio of smooth entries must be greater than the threshold for the
519   // combined stats to be considered smooth.
520   float kNewSmoothDecisionRatioThreshold = 0.7f;
521
522   base::FieldTrialParams field_trial_params;
523   field_trial_params["smooth_decision_ratio_threshold"] =
524       base::NumberToString(kNewSmoothDecisionRatioThreshold);
525   scoped_feature_list.InitAndEnableFeatureWithParameters(
526       media::kWebrtcMediaCapabilitiesParameters, field_trial_params);
527   EXPECT_NE(kNewSmoothDecisionRatioThreshold,
528             previousSmoothDecisionRatioThreshold);
529   EXPECT_EQ(kNewSmoothDecisionRatioThreshold,
530             GetSmoothDecisionRatioThreshold());
531
532   // Complete initialization in advance of API calls when not asked to defer.
533   if (!params.defer_initialize)
534     PreInitializeDB(/*success=*/true);
535
536   constexpr float kP99ProcessingTimeMsSmoothAt60Hz = 12.0f;
537   constexpr float kP99ProcessingTimeMsSmoothAt30Hz = 24.0f;
538   constexpr int kFramesPerSecond = 60;
539
540   // Add two smooth Full HD @ 60 fps decode entries.
541   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
542                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
543                             kP99ProcessingTimeMsSmoothAt60Hz));
544   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
545                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
546                             kP99ProcessingTimeMsSmoothAt60Hz));
547   // Add one not smooth Full HD @ 30 fps decode entry.
548   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
549                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
550                             kP99ProcessingTimeMsSmoothAt30Hz));
551
552   // Verify that Full HD @ 60 fps is not smooth since the ratio threshold is now
553   // set to 0.7, but only 2/3 = 0.66 of the entries are smooth.
554   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
555   perf_history_->GetPerfInfo(
556       Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
557       kFramesPerSecond,
558       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
559                      base::Unretained(this)));
560
561   // Complete successful deferred DB initialization (see comment at top of test)
562   if (params.defer_initialize) {
563     GetFakeDB()->CompleteInitialize(true);
564
565     // Allow initialize-deferred API calls to complete.
566     task_environment_.RunUntilIdle();
567   }
568 }
569
570 TEST_P(WebrtcVideoPerfHistoryParamTest, GetPerfInfoFrameRateBucketing) {
571   // NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
572   // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
573   // that EXPECT_CALLs arrive in top-to-bottom order.
574   WebrtcPerfHistoryTestParams params = GetParam();
575   testing::InSequence dummy;
576
577   // Complete initialization in advance of API calls when not asked to defer.
578   if (!params.defer_initialize)
579     PreInitializeDB(/*success=*/true);
580
581   // First add 2 records to the history. First record with HD resolution and
582   // second with Full HD resolution.
583   constexpr float kP99ProcessingTimeMsSmoothAt60Hz = 12.0f;
584   constexpr float kP99ProcessingTimeMsSmoothAt20Hz = 44.0f;
585
586   // Add the entries.
587   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
588                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
589                             kP99ProcessingTimeMsSmoothAt60Hz));
590   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
591                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
592                             kP99ProcessingTimeMsSmoothAt20Hz));
593
594   // Verify perf history returns is_smooth = true for HD at 60 fps.
595   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
596   perf_history_->GetPerfInfo(
597       Features::New(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
598       /*frames_per_second=*/60,
599       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
600                      base::Unretained(this)));
601   // Verify perf history returns is_smooth = true for HD also at 120 fps since
602   // 120 fps is quantized to 60 fps due to privacy concerns.
603   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
604   perf_history_->GetPerfInfo(
605       Features::New(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
606       /*frames_per_second=*/120,
607       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
608                      base::Unretained(this)));
609
610   // Verify perf history returns is_smooth = false for Full HD at both 20 and 30
611   // fps. Even though the processing time would work at 20 fps the output is
612   // still expected to be smooth = false since 20 fps is quantized to 30 fps.
613   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
614   perf_history_->GetPerfInfo(
615       Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
616       /*frames_per_second=*/20,
617       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
618                      base::Unretained(this)));
619   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
620   perf_history_->GetPerfInfo(
621       Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
622       /*frames_per_second=*/30,
623       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
624                      base::Unretained(this)));
625
626   // Complete successful deferred DB initialization (see comment at top of test)
627   if (params.defer_initialize) {
628     GetFakeDB()->CompleteInitialize(true);
629
630     // Allow initialize-deferred API calls to complete.
631     task_environment_.RunUntilIdle();
632   }
633 }
634
635 // Only save valid keys and stats.
636 TEST_P(WebrtcVideoPerfHistoryParamTest, OnlySaveValidKeysAndStats) {
637   // NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
638   // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
639   // that EXPECT_CALLs arrive in top-to-bottom order.
640   WebrtcPerfHistoryTestParams params = GetParam();
641   testing::InSequence dummy;
642
643   // Complete initialization in advance of API calls when not asked to defer.
644   if (!params.defer_initialize)
645     PreInitializeDB(/*success=*/true);
646
647   constexpr float kValidP99ProcessingTimeMs = 12.0f;
648   // Explicitly state that no save-done callbacks are expected.
649   EXPECT_CALL(*this, MockSaveDoneCB()).Times(0);
650   // Add invalid entries and verify that there's no save done callback.
651   // Unknown profile.
652   SavePerfRecord(
653       Features(kIsDecode, VideoCodecProfile::VIDEO_CODEC_PROFILE_UNKNOWN,
654                kPixelsHd, kSoftware),
655       VideoStats(kFramesProcessed, kKeyFramesProcessed,
656                  kValidP99ProcessingTimeMs),
657       /*expect_callback=*/false);
658   // Out of bounds profile.
659   SavePerfRecord(Features(kIsDecode, static_cast<VideoCodecProfile>(1000),
660                           kPixelsHd, kSoftware),
661                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
662                             kValidP99ProcessingTimeMs),
663                  /*expect_callback=*/false);
664   // Untracked codec profile.
665   SavePerfRecord(
666       Features(kIsDecode, DOLBYVISION_PROFILE5, kPixelsHd, kSoftware),
667       VideoStats(kFramesProcessed, kKeyFramesProcessed,
668                  kValidP99ProcessingTimeMs),
669       /*expect_callback=*/false);
670   // Invalid pixels.
671   SavePerfRecord(
672       Features(kIsDecode, kKnownProfile, /*video_pixels=*/100, kSoftware),
673       VideoStats(kFramesProcessed, kKeyFramesProcessed,
674                  kValidP99ProcessingTimeMs),
675       /*expect_callback=*/false);
676   SavePerfRecord(
677       Features(kIsDecode, kKnownProfile, /*video_pixels=*/1e9, kSoftware),
678       VideoStats(kFramesProcessed, kKeyFramesProcessed,
679                  kValidP99ProcessingTimeMs),
680       /*expect_callback=*/false);
681   // Too few frames processed.
682   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
683                  VideoStats(/*frames_processed=*/10, kKeyFramesProcessed,
684                             kValidP99ProcessingTimeMs),
685                  /*expect_callback=*/false);
686   // Too many frames processed.
687   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
688                  VideoStats(/*frames_processed=*/1e6, kKeyFramesProcessed,
689                             kValidP99ProcessingTimeMs),
690                  /*expect_callback=*/false);
691   // Key frames higher than frames_processed.
692   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
693                  VideoStats(kFramesProcessed,
694                             /*key_frames_processed=*/kFramesProcessed + 1,
695                             kValidP99ProcessingTimeMs),
696                  /*expect_callback=*/false);
697   // Negative processing time.
698   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
699                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
700                             /*p99_processing_time_ms=*/-1.0f),
701                  /*expect_callback=*/false);
702   // Too high processing time.
703   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
704                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
705                             /*p99_processing_time_ms=*/60000.0f),
706                  /*expect_callback=*/false);
707
708   // Complete successful deferred DB initialization (see comment at top of test)
709   if (params.defer_initialize) {
710     GetFakeDB()->CompleteInitialize(true);
711
712     // Allow initialize-deferred API calls to complete.
713     task_environment_.RunUntilIdle();
714   }
715 }
716
717 TEST_P(WebrtcVideoPerfHistoryParamTest, SmoothIsTrueForUntrackedCodecProfiles) {
718   // NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
719   // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
720   // that EXPECT_CALLs arrive in top-to-bottom order.
721   WebrtcPerfHistoryTestParams params = GetParam();
722   testing::InSequence dummy;
723
724   // Complete initialization in advance of API calls when not asked to defer.
725   if (!params.defer_initialize)
726     PreInitializeDB(/*success=*/true);
727
728   // First add 2 records with untracked codec profiles to the history that are
729   // not smooth at 60Hz.
730   constexpr float kP99ProcessingTimeMsNotSmoothAt60Hz = 40.0f;
731   SavePerfRecord(
732       Features(kIsDecode, DOLBYVISION_PROFILE4, kPixelsHd, kSoftware),
733       VideoStats(kFramesProcessed, kKeyFramesProcessed,
734                  kP99ProcessingTimeMsNotSmoothAt60Hz),
735       /*expect_callback=*/false);
736   SavePerfRecord(
737       Features(kIsDecode, DOLBYVISION_PROFILE8, kPixelsHd, kSoftware),
738       VideoStats(kFramesProcessed, kKeyFramesProcessed,
739                  kP99ProcessingTimeMsNotSmoothAt60Hz),
740       /*expect_callback=*/false);
741
742   // Verify perf history returns is_smooth = true anyway.
743   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
744   perf_history_->GetPerfInfo(
745       Features::New(kIsDecode, DOLBYVISION_PROFILE4, kPixelsHd, kSoftware),
746       /*frames_per_second=*/60,
747       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
748                      base::Unretained(this)));
749   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
750   perf_history_->GetPerfInfo(
751       Features::New(kIsDecode, DOLBYVISION_PROFILE8, kPixelsHd, kSoftware),
752       /*frames_per_second=*/60,
753       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
754                      base::Unretained(this)));
755
756   // Complete successful deferred DB initialization (see comment at top of test)
757   if (params.defer_initialize) {
758     GetFakeDB()->CompleteInitialize(true);
759
760     // Allow initialize-deferred API calls to complete.
761     task_environment_.RunUntilIdle();
762   }
763 }
764
765 TEST_P(WebrtcVideoPerfHistoryParamTest, GetPerfInfoFailedInitialize) {
766   WebrtcPerfHistoryTestParams params = GetParam();
767   // Fail initialization in advance of API calls when not asked to defer.
768   if (!params.defer_initialize)
769     PreInitializeDB(/*success=*/false);
770
771   // When initialization fails, callback should optimistically claim smooth
772   // performance.
773   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
774   perf_history_->GetPerfInfo(
775       Features::New(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
776       /*frames_per_second=*/30,
777       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
778                      base::Unretained(this)));
779
780   // Fail deferred DB initialization (see comment at top of test).
781   if (params.defer_initialize) {
782     GetFakeDB()->CompleteInitialize(false);
783
784     // Allow initialize-deferred API calls to complete.
785     task_environment_.RunUntilIdle();
786   }
787 }
788
789 TEST_P(WebrtcVideoPerfHistoryParamTest, AppendAndDestroyStats) {
790   // NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
791   // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
792   // that EXPECT_CALLs arrive in top-to-bottom order.
793   WebrtcPerfHistoryTestParams params = GetParam();
794   testing::InSequence dummy;
795
796   // Complete initialization in advance of API calls when not asked to defer.
797   if (!params.defer_initialize)
798     PreInitializeDB(/*success=*/true);
799
800   constexpr float kP99ProcessingTimeMsSmoothAt30Hz = 24.0f;
801
802   // Add the entries.
803   SavePerfRecord(Features(kIsEncode, kKnownProfile, kPixelsFullHd, kHardware),
804                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
805                             kP99ProcessingTimeMsSmoothAt30Hz));
806
807   // Verify its there before we ClearHistory(). Note that perf is NOT smooth at
808   // 60 fps.
809   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
810   perf_history_->GetPerfInfo(
811       Features::New(kIsEncode, kKnownProfile, kPixelsFullHd, kHardware),
812       /*frames_per_second=*/60,
813       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
814                      base::Unretained(this)));
815
816   // Initiate async clearing of history.
817   EXPECT_CALL(*this, MockOnClearedHistory());
818   perf_history_->ClearHistory(
819       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockOnClearedHistory,
820                      base::Unretained(this)));
821
822   // Verify record we added above is no longer present.
823   // SUBTLE: The PerfHistory will optimistically respond kIsSmooth when no data
824   // is found. So the signal that the entry was removed is the CB now claims
825   // "smooth" when it claimed NOT smooth just moments before.
826   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
827   perf_history_->GetPerfInfo(
828       Features::New(kIsEncode, kKnownProfile, kPixelsFullHd, kHardware),
829       /*frames_per_second=*/60,
830       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
831                      base::Unretained(this)));
832
833   // Complete successful deferred DB initialization (see comment at top of test)
834   if (params.defer_initialize) {
835     GetFakeDB()->CompleteInitialize(true);
836
837     // Allow initialize-deferred API calls to complete.
838     task_environment_.RunUntilIdle();
839   }
840 }
841
842 TEST_P(WebrtcVideoPerfHistoryParamTest, GetWebrtcVideoStatsDB) {
843   // NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
844   // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
845   // that EXPECT_CALLs arrive in top-to-bottom order.
846   WebrtcPerfHistoryTestParams params = GetParam();
847   testing::InSequence dummy;
848
849   // Complete initialization in advance of API calls when not asked to defer.
850   if (!params.defer_initialize)
851     PreInitializeDB(/*success=*/true);
852
853   // Request a pointer to WebrtcVideoStatsDB and verify the callback.
854   EXPECT_CALL(*this, MockGetWebrtcVideoStatsDBCB(_))
855       .WillOnce([&](const auto* db_ptr) {
856         // Not able to simply use a matcher because the DB does not exist at the
857         // time we setup the EXPECT_CALL.
858         EXPECT_EQ(GetFakeDB(), db_ptr);
859       });
860
861   perf_history_->GetWebrtcVideoStatsDB(
862       base::BindOnce(&WebrtcVideoPerfHistoryTest::MockGetWebrtcVideoStatsDBCB,
863                      base::Unretained(this)));
864
865   task_environment_.RunUntilIdle();
866
867   // Complete successful deferred DB initialization (see comment at top of test)
868   if (params.defer_initialize) {
869     GetFakeDB()->CompleteInitialize(true);
870
871     // Allow initialize-deferred API calls to complete.
872     task_environment_.RunUntilIdle();
873   }
874 }
875
876 TEST_P(WebrtcVideoPerfHistoryParamTest, GetWebrtcVideoStatsDBFailedInitialize) {
877   // NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
878   // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
879   // that EXPECT_CALLs arrive in top-to-bottom order.
880   WebrtcPerfHistoryTestParams params = GetParam();
881   testing::InSequence dummy;
882
883   // Complete initialization in advance of API calls when not asked to defer.
884   if (!params.defer_initialize)
885     PreInitializeDB(/*success=*/false);
886
887   // Request a pointer to WebrtcVideoStatsDB and verify the callback provides
888   // a nullptr due to failed initialization.
889   EXPECT_CALL(*this, MockGetWebrtcVideoStatsDBCB(IsNull()));
890   perf_history_->GetWebrtcVideoStatsDB(
891       base::BindOnce(&WebrtcVideoPerfHistoryTest::MockGetWebrtcVideoStatsDBCB,
892                      base::Unretained(this)));
893
894   task_environment_.RunUntilIdle();
895
896   // Complete failed deferred DB initialization (see comment at top of test)
897   if (params.defer_initialize) {
898     GetFakeDB()->CompleteInitialize(false);
899
900     // Allow initialize-deferred API calls to complete.
901     task_environment_.RunUntilIdle();
902   }
903 }
904
905 TEST_P(WebrtcVideoPerfHistoryParamTest, FailedDatabaseGetForAppend) {
906   // NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
907   // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
908   // that EXPECT_CALLs arrive in top-to-bottom order.
909   WebrtcPerfHistoryTestParams params = GetParam();
910
911   // Complete initialization in advance of API calls when not asked to defer.
912   if (!params.defer_initialize)
913     PreInitializeDB(/*success=*/true);
914
915   // Create a simple record. After we fail to save this record we should find
916   // smooth = true (the default for no-data-found).
917   constexpr float kP99ProcessingTimeMsSmoothAt30Hz = 24.0f;
918
919   // Fail the "get" step of the save (we always get existing stats so that the
920   // new stats can be appended to it).
921   GetFakeDB()->set_fail_next_get(true);
922
923   // Attempt (and fail) the save.
924   SavePerfRecord(Features(kIsEncode, kKnownProfile, kPixelsFullHd, kHardware),
925                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
926                             kP99ProcessingTimeMsSmoothAt30Hz));
927
928   // Verify perf history still returns is_smooth = true since
929   // no data was successfully saved for the given configuration.
930   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
931   perf_history_->GetPerfInfo(
932       Features::New(kIsEncode, kKnownProfile, kPixelsFullHd, kHardware),
933       /*frames_per_second=*/60,
934       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
935                      base::Unretained(this)));
936
937   // Complete successful deferred DB initialization (see comment at top of test)
938   if (params.defer_initialize) {
939     GetFakeDB()->CompleteInitialize(true);
940
941     // Allow initialize-deferred API calls to complete.
942     task_environment_.RunUntilIdle();
943   }
944 }
945
946 TEST_P(WebrtcVideoPerfHistoryParamTest, FailedDatabaseAppend) {
947   // NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
948   // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
949   // that EXPECT_CALLs arrive in top-to-bottom order.
950   WebrtcPerfHistoryTestParams params = GetParam();
951
952   // Complete initialization in advance of API calls when not asked to defer.
953   if (!params.defer_initialize)
954     PreInitializeDB(/*success=*/true);
955
956   // Force the DB to fail on the next append.
957   GetFakeDB()->set_fail_next_append(true);
958
959   // Create a simple record. After we fail to save this record we should find
960   // smooth = true (the default for no-data-found).
961
962   constexpr float kP99ProcessingTimeMsSmoothAt30Hz = 24.0f;
963
964   // Attempt (and fail) the save.
965   SavePerfRecord(Features(kIsEncode, kKnownProfile, kPixelsFullHd, kHardware),
966                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
967                             kP99ProcessingTimeMsSmoothAt30Hz));
968
969   // Verify perf history still returns is_smooth = true since
970   // no data was successfully saved for the given configuration.
971   EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
972   perf_history_->GetPerfInfo(
973       Features::New(kIsEncode, kKnownProfile, kPixelsFullHd, kHardware),
974       /*frames_per_second=*/60,
975       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
976                      base::Unretained(this)));
977
978   // Complete successful deferred DB initialization (see comment at top of test)
979   if (params.defer_initialize) {
980     GetFakeDB()->CompleteInitialize(true);
981
982     // Allow initialize-deferred API calls to complete.
983     task_environment_.RunUntilIdle();
984   }
985 }
986
987 TEST_P(WebrtcVideoPerfHistoryParamTest, GetPerfInfo4KSmoothImpliesHdSmooth) {
988   // NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
989   // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
990   // that EXPECT_CALLs arrive in top-to-bottom order.
991   WebrtcPerfHistoryTestParams params = GetParam();
992   testing::InSequence dummy;
993
994   // Complete initialization in advance of API calls when not asked to defer.
995   if (!params.defer_initialize)
996     PreInitializeDB(/*success=*/true);
997
998   // Add 4K entry that indicates that 4K is smooth at 60 Hz.
999   constexpr float kP99ProcessingTimeMsSmoothAt60Hz = 12.0f;
1000   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixels4K, kSoftware),
1001                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
1002                             kP99ProcessingTimeMsSmoothAt60Hz));
1003
1004   // Verify perf history returns is_smooth = true for all resolutions at 30/60
1005   // fps.
1006   constexpr int kPixels[] = {1280 * 720, 1920 * 1080, 3840 * 2160};
1007   constexpr int kFramerates[] = {30, 60};
1008   for (auto pixels : kPixels) {
1009     for (auto framerate : kFramerates) {
1010       EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
1011       perf_history_->GetPerfInfo(
1012           Features::New(kIsDecode, kKnownProfile, pixels, kSoftware), framerate,
1013           base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
1014                          base::Unretained(this)));
1015     }
1016   }
1017
1018   // Add an entry indicating that Full HD is not smooth.
1019   constexpr float kP99ProcessingTimeMsNotSmoothAt30Hz = 60.0f;
1020   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
1021                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
1022                             kP99ProcessingTimeMsNotSmoothAt30Hz));
1023
1024   // This is an incosistency, but the 4K entry with smooth=true overrides the
1025   // FullHD entry with smooth=false. Verify perf history returns is_smooth =
1026   // true for all resolutions at 30/60 fps.
1027   for (auto pixels : kPixels) {
1028     for (auto framerate : kFramerates) {
1029       EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
1030       perf_history_->GetPerfInfo(
1031           Features::New(kIsDecode, kKnownProfile, pixels, kSoftware), framerate,
1032           base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
1033                          base::Unretained(this)));
1034     }
1035   }
1036
1037   // Complete successful deferred DB initialization (see comment at top of test)
1038   if (params.defer_initialize) {
1039     GetFakeDB()->CompleteInitialize(true);
1040
1041     // Allow initialize-deferred API calls to complete.
1042     task_environment_.RunUntilIdle();
1043   }
1044 }
1045
1046 TEST_P(WebrtcVideoPerfHistoryParamTest,
1047        GetPerfInfoFullHdNotSmoothImplies4KNotSmooth) {
1048   // NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
1049   // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
1050   // that EXPECT_CALLs arrive in top-to-bottom order.
1051   WebrtcPerfHistoryTestParams params = GetParam();
1052   testing::InSequence dummy;
1053
1054   // Complete initialization in advance of API calls when not asked to defer.
1055   if (!params.defer_initialize)
1056     PreInitializeDB(/*success=*/true);
1057
1058   // Add entry that indicates that FullHD is not smooth at 30 Hz.
1059   constexpr float kP99ProcessingTimeMsNotSmoothAt30Hz = 60.0f;
1060   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
1061                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
1062                             kP99ProcessingTimeMsNotSmoothAt30Hz));
1063
1064   // Verify perf history returns is_smooth = true only for resolutions below
1065   // FullHD at 30/60 fps.
1066   constexpr int kPixels[] = {1280 * 720, 1920 * 1080, 3840 * 2160};
1067   constexpr int kFramerates[] = {30, 60};
1068   for (auto pixels : kPixels) {
1069     for (auto framerate : kFramerates) {
1070       EXPECT_CALL(*this, MockGetPerfInfoCB(
1071                              pixels < 1920 * 1080 ? kIsSmooth : kIsNotSmooth));
1072       perf_history_->GetPerfInfo(
1073           Features::New(kIsDecode, kKnownProfile, pixels, kSoftware), framerate,
1074           base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
1075                          base::Unretained(this)));
1076     }
1077   }
1078
1079   // Complete successful deferred DB initialization (see comment at top of test)
1080   if (params.defer_initialize) {
1081     GetFakeDB()->CompleteInitialize(true);
1082
1083     // Allow initialize-deferred API calls to complete.
1084     task_environment_.RunUntilIdle();
1085   }
1086 }
1087
1088 TEST_P(WebrtcVideoPerfHistoryParamTest,
1089        GetPerfInfoFullHdSmoothEvenIf4KNotSmooth) {
1090   // NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
1091   // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
1092   // that EXPECT_CALLs arrive in top-to-bottom order.
1093   WebrtcPerfHistoryTestParams params = GetParam();
1094   testing::InSequence dummy;
1095
1096   // Complete initialization in advance of API calls when not asked to defer.
1097   if (!params.defer_initialize)
1098     PreInitializeDB(/*success=*/true);
1099
1100   // Add 4K entry that indicates that 4K is not smooth at 30 Hz.
1101   constexpr float kP99ProcessingTimeMsNotSmoothAt30Hz = 60.0f;
1102   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixels4K, kSoftware),
1103                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
1104                             kP99ProcessingTimeMsNotSmoothAt30Hz));
1105
1106   // Verify perf history returns is_smooth = true for all resolutions below 4K
1107   // at 30/60 fps.
1108   constexpr int kPixels[] = {1280 * 720, 1920 * 1080, 3840 * 2160};
1109   constexpr int kFramerates[] = {30, 60};
1110   for (auto pixels : kPixels) {
1111     for (auto framerate : kFramerates) {
1112       EXPECT_CALL(*this, MockGetPerfInfoCB(
1113                              pixels <= 1920 * 1080 ? kIsSmooth : kIsNotSmooth));
1114       perf_history_->GetPerfInfo(
1115           Features::New(kIsDecode, kKnownProfile, pixels, kSoftware), framerate,
1116           base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
1117                          base::Unretained(this)));
1118     }
1119   }
1120
1121   // Add an entry indicating that Full HD is smooth.
1122   constexpr float kP99ProcessingTimeMsSmoothAt60Hz = 12.0f;
1123   SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
1124                  VideoStats(kFramesProcessed, kKeyFramesProcessed,
1125                             kP99ProcessingTimeMsSmoothAt60Hz));
1126
1127   // Repeat test. The added entry is consistent with the default prediction.
1128   for (auto pixels : kPixels) {
1129     for (auto framerate : kFramerates) {
1130       EXPECT_CALL(*this, MockGetPerfInfoCB(
1131                              pixels <= 1920 * 1080 ? kIsSmooth : kIsNotSmooth));
1132       perf_history_->GetPerfInfo(
1133           Features::New(kIsDecode, kKnownProfile, pixels, kSoftware), framerate,
1134           base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
1135                          base::Unretained(this)));
1136     }
1137   }
1138
1139   // Complete successful deferred DB initialization (see comment at top of test)
1140   if (params.defer_initialize) {
1141     GetFakeDB()->CompleteInitialize(true);
1142
1143     // Allow initialize-deferred API calls to complete.
1144     task_environment_.RunUntilIdle();
1145   }
1146 }
1147
1148 const WebrtcPerfHistoryTestParams kWebrtcPerfHistoryTestParams[] = {
1149     {/*defer_initialize=*/true},
1150     {/*defer_initialize=*/false},
1151 };
1152
1153 INSTANTIATE_TEST_SUITE_P(VaryDBInitTiming,
1154                          WebrtcVideoPerfHistoryParamTest,
1155                          ::testing::ValuesIn(kWebrtcPerfHistoryTestParams));
1156
1157 //
1158 // The following tests are not parameterized. They instead always hard code
1159 // deferred initialization.
1160 //
1161
1162 TEST_F(WebrtcVideoPerfHistoryTest, ClearHistoryTriggersSuccessfulInitialize) {
1163   // Clear the DB. Completion callback shouldn't fire until initialize
1164   // completes.
1165   EXPECT_CALL(*this, MockOnClearedHistory()).Times(0);
1166   perf_history_->ClearHistory(
1167       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockOnClearedHistory,
1168                      base::Unretained(this)));
1169
1170   // Give completion callback a chance to fire. Confirm it did not fire.
1171   task_environment_.RunUntilIdle();
1172   testing::Mock::VerifyAndClearExpectations(this);
1173
1174   // Expect completion callback after we successfully initialize.
1175   EXPECT_CALL(*this, MockOnClearedHistory());
1176   GetFakeDB()->CompleteInitialize(true);
1177
1178   // Give deferred callback a chance to fire.
1179   task_environment_.RunUntilIdle();
1180 }
1181
1182 TEST_F(WebrtcVideoPerfHistoryTest, ClearHistoryTriggersFailedInitialize) {
1183   // Clear the DB. Completion callback shouldn't fire until initialize
1184   // completes.
1185   EXPECT_CALL(*this, MockOnClearedHistory()).Times(0);
1186   perf_history_->ClearHistory(
1187       base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockOnClearedHistory,
1188                      base::Unretained(this)));
1189
1190   // Give completion callback a chance to fire. Confirm it did not fire.
1191   task_environment_.RunUntilIdle();
1192   testing::Mock::VerifyAndClearExpectations(this);
1193
1194   // Expect completion callback after completing initialize. "Failure" is
1195   // still a form of completion.
1196   EXPECT_CALL(*this, MockOnClearedHistory());
1197   GetFakeDB()->CompleteInitialize(false);
1198
1199   // Give deferred callback a chance to fire.
1200   task_environment_.RunUntilIdle();
1201 }
1202
1203 }  // namespace media