webrtc_video_stats_db_impl_unittest.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. // Copyright 2022 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <map>
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/callback.h"
  8. #include "base/callback_helpers.h"
  9. #include "base/check.h"
  10. #include "base/files/file_path.h"
  11. #include "base/memory/ptr_util.h"
  12. #include "base/memory/raw_ptr.h"
  13. #include "base/run_loop.h"
  14. #include "base/strings/string_number_conversions.h"
  15. #include "base/test/scoped_feature_list.h"
  16. #include "base/test/simple_test_clock.h"
  17. #include "base/test/task_environment.h"
  18. #include "components/leveldb_proto/testing/fake_db.h"
  19. #include "media/base/media_switches.h"
  20. #include "media/base/test_data_util.h"
  21. #include "media/base/video_codecs.h"
  22. #include "media/capabilities/webrtc_video_stats.pb.h"
  23. #include "media/capabilities/webrtc_video_stats_db_impl.h"
  24. #include "testing/gmock/include/gmock/gmock.h"
  25. #include "testing/gtest/include/gtest/gtest.h"
  26. #include "ui/gfx/geometry/size.h"
  27. using leveldb_proto::test::FakeDB;
  28. using testing::_;
  29. using testing::Eq;
  30. using testing::Pointee;
  31. namespace media {
  32. class WebrtcVideoStatsDBImplTest : public ::testing::Test {
  33. public:
  34. using VideoDescKey = WebrtcVideoStatsDB::VideoDescKey;
  35. using VideoStats = WebrtcVideoStatsDB::VideoStats;
  36. using VideoStatsEntry = WebrtcVideoStatsDB::VideoStatsEntry;
  37. WebrtcVideoStatsDBImplTest()
  38. : kDecodeStatsKeyVp9(
  39. VideoDescKey::MakeBucketedKey(/*is_decode_stats=*/true,
  40. VP9PROFILE_PROFILE3,
  41. /*hardware_accelerated=*/false,
  42. 1280 * 720)),
  43. kDecodeStatsKeyVp9Hw(
  44. VideoDescKey::MakeBucketedKey(/*is_decode_stats=*/true,
  45. VP9PROFILE_PROFILE3,
  46. /*hardware_accelerated=*/true,
  47. 1280 * 720)),
  48. kDecodeStatsKeyVp9FullHd(
  49. VideoDescKey::MakeBucketedKey(/*is_decode_stats=*/true,
  50. VP9PROFILE_PROFILE3,
  51. /*hardware_accelerated=*/false,
  52. 1920 * 1080)),
  53. kDecodeStatsKeyVp94K(
  54. VideoDescKey::MakeBucketedKey(/*is_decode_stats=*/true,
  55. VP9PROFILE_PROFILE3,
  56. /*hardware_accelerated=*/false,
  57. 3840 * 2160)),
  58. kDecodeStatsKeyH264(
  59. VideoDescKey::MakeBucketedKey(/*is_decode_stats=*/true,
  60. H264PROFILE_MIN,
  61. /*hardware_accelerated=*/false,
  62. 1920 * 1080)),
  63. kEncodeStatsKeyVp9(
  64. VideoDescKey::MakeBucketedKey(/*is_decode_stats=*/false,
  65. VP9PROFILE_PROFILE3,
  66. /*hardware_accelerated=*/false,
  67. 1280 * 720)) {
  68. // Fake DB simply wraps a std::map with the LevelDB interface. We own the
  69. // map and will delete it in TearDown().
  70. fake_db_map_ =
  71. std::make_unique<FakeDB<WebrtcVideoStatsEntryProto>::EntryMap>();
  72. // `stats_db_` will own this pointer, but we hold a reference to control
  73. // its behavior.
  74. fake_db_ = new FakeDB<WebrtcVideoStatsEntryProto>(fake_db_map_.get());
  75. // Wrap the fake proto DB with our interface.
  76. stats_db_ = base::WrapUnique(new WebrtcVideoStatsDBImpl(
  77. std::unique_ptr<FakeDB<WebrtcVideoStatsEntryProto>>(fake_db_)));
  78. }
  79. WebrtcVideoStatsDBImplTest(const WebrtcVideoStatsDBImplTest&) = delete;
  80. WebrtcVideoStatsDBImplTest& operator=(const WebrtcVideoStatsDBImplTest&) =
  81. delete;
  82. ~WebrtcVideoStatsDBImplTest() override {
  83. // Tests should always complete any pending operations
  84. VerifyNoPendingOps();
  85. }
  86. void VerifyOnePendingOp(std::string op_name) {
  87. EXPECT_EQ(stats_db_->pending_operations_.get_pending_ops_for_test().size(),
  88. 1u);
  89. PendingOperations::PendingOperation* pending_op =
  90. stats_db_->pending_operations_.get_pending_ops_for_test()
  91. .begin()
  92. ->second.get();
  93. EXPECT_EQ(pending_op->uma_str_, op_name);
  94. }
  95. void VerifyNoPendingOps() {
  96. EXPECT_TRUE(
  97. stats_db_->pending_operations_.get_pending_ops_for_test().empty());
  98. }
  99. base::TimeDelta GetMaxTimeToKeepStats() {
  100. return WebrtcVideoStatsDBImpl::GetMaxTimeToKeepStats();
  101. }
  102. int GetMaxEntriesPerConfig() {
  103. return WebrtcVideoStatsDBImpl::GetMaxEntriesPerConfig();
  104. }
  105. void SetDBClock(base::Clock* clock) {
  106. stats_db_->set_wall_clock_for_test(clock);
  107. }
  108. void InitializeDB() {
  109. stats_db_->Initialize(base::BindOnce(
  110. &WebrtcVideoStatsDBImplTest::OnInitialize, base::Unretained(this)));
  111. EXPECT_CALL(*this, OnInitialize(true));
  112. fake_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
  113. testing::Mock::VerifyAndClearExpectations(this);
  114. }
  115. void AppendStats(const VideoDescKey& key, const VideoStats& entry) {
  116. EXPECT_CALL(*this, MockAppendVideoStatsCb(true));
  117. stats_db_->AppendVideoStats(
  118. key, entry,
  119. base::BindOnce(&WebrtcVideoStatsDBImplTest::MockAppendVideoStatsCb,
  120. base::Unretained(this)));
  121. VerifyOnePendingOp("Read");
  122. fake_db_->GetCallback(true);
  123. VerifyOnePendingOp("Write");
  124. fake_db_->UpdateCallback(true);
  125. testing::Mock::VerifyAndClearExpectations(this);
  126. }
  127. void VerifyReadStats(const VideoDescKey& key,
  128. const VideoStatsEntry& expected) {
  129. EXPECT_CALL(*this,
  130. MockGetVideoStatsCb(true, absl::make_optional(expected)));
  131. stats_db_->GetVideoStats(
  132. key, base::BindOnce(&WebrtcVideoStatsDBImplTest::MockGetVideoStatsCb,
  133. base::Unretained(this)));
  134. VerifyOnePendingOp("Read");
  135. fake_db_->GetCallback(true);
  136. testing::Mock::VerifyAndClearExpectations(this);
  137. }
  138. void VerifyReadStatsCollection(
  139. const VideoDescKey& key,
  140. const WebrtcVideoStatsDB::VideoStatsCollection& expected) {
  141. EXPECT_CALL(*this, MockGetVideoStatsCollectionCb(
  142. true, absl::make_optional(expected)));
  143. stats_db_->GetVideoStatsCollection(
  144. key, base::BindOnce(
  145. &WebrtcVideoStatsDBImplTest::MockGetVideoStatsCollectionCb,
  146. base::Unretained(this)));
  147. VerifyOnePendingOp("Read");
  148. fake_db_->LoadCallback(true);
  149. testing::Mock::VerifyAndClearExpectations(this);
  150. }
  151. void VerifyEmptyStats(const VideoDescKey& key) {
  152. EXPECT_CALL(*this,
  153. MockGetVideoStatsCb(true, absl::optional<VideoStatsEntry>()));
  154. stats_db_->GetVideoStats(
  155. key, base::BindOnce(&WebrtcVideoStatsDBImplTest::MockGetVideoStatsCb,
  156. base::Unretained(this)));
  157. VerifyOnePendingOp("Read");
  158. fake_db_->GetCallback(true);
  159. testing::Mock::VerifyAndClearExpectations(this);
  160. }
  161. void AppendToProtoDB(const VideoDescKey& key,
  162. const WebrtcVideoStatsEntryProto* const proto) {
  163. base::RunLoop run_loop;
  164. base::OnceCallback<void(bool)> update_done_cb = base::BindOnce(
  165. [](base::RunLoop* run_loop, bool success) {
  166. ASSERT_TRUE(success);
  167. run_loop->Quit();
  168. },
  169. Unretained(&run_loop));
  170. using DBType = leveldb_proto::ProtoDatabase<WebrtcVideoStatsEntryProto>;
  171. std::unique_ptr<DBType::KeyEntryVector> entries =
  172. std::make_unique<DBType::KeyEntryVector>();
  173. entries->emplace_back(key.Serialize(), *proto);
  174. fake_db_->UpdateEntries(std::move(entries),
  175. std::make_unique<leveldb_proto::KeyVector>(),
  176. std::move(update_done_cb));
  177. fake_db_->UpdateCallback(true);
  178. run_loop.Run();
  179. }
  180. MOCK_METHOD1(OnInitialize, void(bool success));
  181. MOCK_METHOD2(MockGetVideoStatsCb,
  182. void(bool success, absl::optional<VideoStatsEntry> entry));
  183. MOCK_METHOD2(MockGetVideoStatsCollectionCb,
  184. void(bool success,
  185. absl::optional<WebrtcVideoStatsDB::VideoStatsCollection>
  186. collection));
  187. MOCK_METHOD1(MockAppendVideoStatsCb, void(bool success));
  188. MOCK_METHOD0(MockClearStatsCb, void());
  189. protected:
  190. base::test::TaskEnvironment task_environment_{
  191. base::test::TaskEnvironment::TimeSource::MOCK_TIME};
  192. const VideoDescKey kDecodeStatsKeyVp9;
  193. const VideoDescKey kDecodeStatsKeyVp9Hw;
  194. const VideoDescKey kDecodeStatsKeyVp9FullHd;
  195. const VideoDescKey kDecodeStatsKeyVp94K;
  196. const VideoDescKey kDecodeStatsKeyH264;
  197. const VideoDescKey kEncodeStatsKeyVp9;
  198. // See documentation in SetUp()
  199. std::unique_ptr<FakeDB<WebrtcVideoStatsEntryProto>::EntryMap> fake_db_map_;
  200. raw_ptr<FakeDB<WebrtcVideoStatsEntryProto>> fake_db_;
  201. std::unique_ptr<WebrtcVideoStatsDBImpl> stats_db_;
  202. };
  203. TEST_F(WebrtcVideoStatsDBImplTest, InitializeFailed) {
  204. stats_db_->Initialize(base::BindOnce(
  205. &WebrtcVideoStatsDBImplTest::OnInitialize, base::Unretained(this)));
  206. EXPECT_CALL(*this, OnInitialize(false));
  207. fake_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kError);
  208. }
  209. TEST_F(WebrtcVideoStatsDBImplTest, InitializeTimedOut) {
  210. // Queue up an Initialize.
  211. stats_db_->Initialize(base::BindOnce(
  212. &WebrtcVideoStatsDBImplTest::OnInitialize, base::Unretained(this)));
  213. VerifyOnePendingOp("Initialize");
  214. // Move time forward enough to trigger timeout.
  215. EXPECT_CALL(*this, OnInitialize(_)).Times(0);
  216. task_environment_.FastForwardBy(base::Seconds(100));
  217. task_environment_.RunUntilIdle();
  218. // Verify we didn't get an init callback and task is no longer considered
  219. // pending (because it timed out).
  220. testing::Mock::VerifyAndClearExpectations(this);
  221. VerifyNoPendingOps();
  222. // Verify callback still works if init completes very late.
  223. EXPECT_CALL(*this, OnInitialize(false));
  224. fake_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kError);
  225. }
  226. TEST_F(WebrtcVideoStatsDBImplTest, ReadExpectingNothing) {
  227. InitializeDB();
  228. VerifyEmptyStats(kDecodeStatsKeyVp9);
  229. }
  230. TEST_F(WebrtcVideoStatsDBImplTest, WriteReadAndClear) {
  231. InitializeDB();
  232. // Set test clock.
  233. base::SimpleTestClock clock;
  234. SetDBClock(&clock);
  235. clock.SetNow(base::Time::Now());
  236. // Append and read back some VP9 stats.
  237. VideoStats stats1(clock.Now().ToJsTimeIgnoringNull(), 240, 6, 7.2);
  238. VideoStatsEntry entry{stats1};
  239. AppendStats(kDecodeStatsKeyVp9, stats1);
  240. VerifyReadStats(kDecodeStatsKeyVp9, entry);
  241. // Reading with the wrong key (different codec) should still return nothing.
  242. VerifyEmptyStats(kDecodeStatsKeyH264);
  243. VerifyEmptyStats(kEncodeStatsKeyVp9);
  244. // Appending new VP9 stats.
  245. clock.Advance(base::Hours(1));
  246. VideoStats stats2(clock.Now().ToJsTimeIgnoringNull(), 1000, 14, 6.8);
  247. AppendStats(kDecodeStatsKeyVp9, stats2);
  248. VideoStatsEntry aggregate_entry{stats2, stats1};
  249. VerifyReadStats(kDecodeStatsKeyVp9, aggregate_entry);
  250. // Clear all stats from the DB.
  251. EXPECT_CALL(*this, MockClearStatsCb);
  252. stats_db_->ClearStats(base::BindOnce(
  253. &WebrtcVideoStatsDBImplTest::MockClearStatsCb, base::Unretained(this)));
  254. VerifyOnePendingOp("Clear");
  255. fake_db_->UpdateCallback(true);
  256. // Database is now empty. Expect null entry.
  257. VerifyEmptyStats(kDecodeStatsKeyVp9);
  258. }
  259. TEST_F(WebrtcVideoStatsDBImplTest, ExpiredStatsAreNotReturned) {
  260. InitializeDB();
  261. // Set test clock.
  262. base::SimpleTestClock clock;
  263. SetDBClock(&clock);
  264. clock.SetNow(base::Time::Now());
  265. // Append and read back some VP9 stats.
  266. VideoStats stats1(clock.Now().ToJsTimeIgnoringNull(), 240, 6, 7.2);
  267. VideoStatsEntry entry{stats1};
  268. AppendStats(kDecodeStatsKeyVp9, stats1);
  269. VerifyReadStats(kDecodeStatsKeyVp9, entry);
  270. // Appending new VP9 stats.
  271. clock.Advance(base::Days(2));
  272. VideoStats stats2(clock.Now().ToJsTimeIgnoringNull(), 1000, 14, 6.8);
  273. clock.SetNow(base::Time::FromJsTime(stats2.timestamp));
  274. AppendStats(kDecodeStatsKeyVp9, stats2);
  275. VideoStatsEntry aggregate_entry{stats2, stats1};
  276. VerifyReadStats(kDecodeStatsKeyVp9, aggregate_entry);
  277. // Set the clock to a date so that the first entry is expired.
  278. clock.SetNow(base::Time::FromJsTime(stats1.timestamp) + base::Days(1) +
  279. GetMaxTimeToKeepStats());
  280. VideoStatsEntry nonexpired_entry{stats2};
  281. VerifyReadStats(kDecodeStatsKeyVp9, nonexpired_entry);
  282. // Set the clock so that all data have expired.
  283. clock.SetNow(base::Time::FromJsTime(stats2.timestamp) + base::Days(1) +
  284. GetMaxTimeToKeepStats());
  285. // All stats are expired. Expect null entry.
  286. VerifyEmptyStats(kDecodeStatsKeyVp9);
  287. }
  288. TEST_F(WebrtcVideoStatsDBImplTest, ConfigureExpireDays) {
  289. base::test::ScopedFeatureList scoped_feature_list;
  290. std::unique_ptr<base::FieldTrialList> field_trial_list;
  291. base::TimeDelta previous_max_days_to_keep_stats = GetMaxTimeToKeepStats();
  292. constexpr int kNewMaxDaysToKeepStats = 4;
  293. ASSERT_LT(base::Days(kNewMaxDaysToKeepStats),
  294. previous_max_days_to_keep_stats);
  295. // Override field trial.
  296. base::FieldTrialParams params;
  297. params["db_days_to_keep_stats"] =
  298. base::NumberToString(kNewMaxDaysToKeepStats);
  299. scoped_feature_list.InitAndEnableFeatureWithParameters(
  300. media::kWebrtcMediaCapabilitiesParameters, params);
  301. EXPECT_EQ(base::Days(kNewMaxDaysToKeepStats), GetMaxTimeToKeepStats());
  302. InitializeDB();
  303. // Inject a test clock and initialize with the current time.
  304. base::SimpleTestClock clock;
  305. SetDBClock(&clock);
  306. clock.SetNow(base::Time::Now());
  307. // Append and verify read-back.
  308. VideoStats stats1(clock.Now().ToJsTimeIgnoringNull(), 240, 6, 7.2);
  309. VideoStatsEntry entry{stats1};
  310. AppendStats(kDecodeStatsKeyVp9, stats1);
  311. VerifyReadStats(kDecodeStatsKeyVp9, entry);
  312. // Some simple math to avoid troubles of integer division.
  313. int half_days_to_keep_stats = kNewMaxDaysToKeepStats / 2;
  314. int remaining_days_to_keep_stats =
  315. kNewMaxDaysToKeepStats - half_days_to_keep_stats;
  316. // Advance time half way through grace period. Verify stats not expired.
  317. clock.Advance(base::Days(half_days_to_keep_stats));
  318. VerifyReadStats(kDecodeStatsKeyVp9, entry);
  319. // Advance time 1 day beyond grace period, verify stats are expired.
  320. clock.Advance(base::Days(remaining_days_to_keep_stats + 1));
  321. VerifyEmptyStats(kDecodeStatsKeyVp9);
  322. // Advance the clock 100 extra days. Verify stats still expired.
  323. clock.Advance(base::Days(100));
  324. VerifyEmptyStats(kDecodeStatsKeyVp9);
  325. }
  326. TEST_F(WebrtcVideoStatsDBImplTest, NewStatsReplaceOldStats) {
  327. InitializeDB();
  328. // Inject a test clock and initialize with the current time.
  329. base::SimpleTestClock clock;
  330. SetDBClock(&clock);
  331. clock.SetNow(base::Time::Now());
  332. // Append and verify read-back.
  333. constexpr int kNumberOfStatsToAdd = 30;
  334. EXPECT_GT(kNumberOfStatsToAdd, GetMaxEntriesPerConfig());
  335. VideoStatsEntry entry;
  336. for (int i = 0; i < kNumberOfStatsToAdd; ++i) {
  337. VideoStats stats(clock.Now().ToJsTimeIgnoringNull(), 240 + i, 6,
  338. 7.2 + i % 3);
  339. AppendStats(kDecodeStatsKeyVp9, stats);
  340. // Start popping the last stats entry if the number of entries has reached
  341. // the limit.
  342. if (i >= GetMaxEntriesPerConfig()) {
  343. entry.pop_back();
  344. }
  345. entry.insert(entry.begin(), stats);
  346. VerifyReadStats(kDecodeStatsKeyVp9, entry);
  347. clock.Advance(base::Days(1));
  348. }
  349. }
  350. TEST_F(WebrtcVideoStatsDBImplTest, ConfigureMaxEntriesPerConfig) {
  351. base::test::ScopedFeatureList scoped_feature_list;
  352. std::unique_ptr<base::FieldTrialList> field_trial_list;
  353. int previous_max_entries_per_config = GetMaxEntriesPerConfig();
  354. constexpr int kNewMaxEntriesPerConfig = 3;
  355. ASSERT_LT(kNewMaxEntriesPerConfig, previous_max_entries_per_config);
  356. // Override field trial.
  357. base::FieldTrialParams params;
  358. params["db_max_entries_per_cpnfig"] =
  359. base::NumberToString(kNewMaxEntriesPerConfig);
  360. scoped_feature_list.InitAndEnableFeatureWithParameters(
  361. media::kWebrtcMediaCapabilitiesParameters, params);
  362. EXPECT_EQ(kNewMaxEntriesPerConfig, GetMaxEntriesPerConfig());
  363. InitializeDB();
  364. // Inject a test clock and initialize with the current time.
  365. base::SimpleTestClock clock;
  366. SetDBClock(&clock);
  367. clock.SetNow(base::Time::Now());
  368. // Append and verify read-back.
  369. constexpr int kNumberOfStatsToAdd = 30;
  370. EXPECT_GT(kNumberOfStatsToAdd, GetMaxEntriesPerConfig());
  371. VideoStatsEntry entry;
  372. for (int i = 0; i < kNumberOfStatsToAdd; ++i) {
  373. VideoStats stats(clock.Now().ToJsTimeIgnoringNull(), 240 + i, 6,
  374. 7.2 + i % 3);
  375. AppendStats(kDecodeStatsKeyVp9, stats);
  376. // Start popping the last stats entry if the number of entries has reached
  377. // the limit.
  378. if (i >= GetMaxEntriesPerConfig()) {
  379. entry.pop_back();
  380. }
  381. entry.insert(entry.begin(), stats);
  382. VerifyReadStats(kDecodeStatsKeyVp9, entry);
  383. clock.Advance(base::Days(1));
  384. }
  385. }
  386. TEST_F(WebrtcVideoStatsDBImplTest, OutOfOrderTimestampClearsOldStats) {
  387. InitializeDB();
  388. // Inject a test clock and initialize with the current time.
  389. base::SimpleTestClock clock;
  390. SetDBClock(&clock);
  391. clock.SetNow(base::Time::Now());
  392. // Append and verify read-back.
  393. constexpr int kNumberOfStatsToAdd = 5;
  394. VideoStatsEntry entry;
  395. for (int i = 0; i < kNumberOfStatsToAdd; ++i) {
  396. VideoStats stats(clock.Now().ToJsTimeIgnoringNull(), 240 + i, 6,
  397. 7.2 + i % 3);
  398. AppendStats(kDecodeStatsKeyVp9, stats);
  399. entry.insert(entry.begin(), stats);
  400. VerifyReadStats(kDecodeStatsKeyVp9, entry);
  401. clock.Advance(base::Days(1));
  402. }
  403. // Go back in time and add a new stats entry.
  404. clock.Advance(-base::Days(20));
  405. VideoStats stats(clock.Now().ToJsTimeIgnoringNull(), 123, 5, 11.2);
  406. AppendStats(kDecodeStatsKeyVp9, stats);
  407. // Only the last appended stats should be in the database now.
  408. entry = {stats};
  409. VerifyReadStats(kDecodeStatsKeyVp9, entry);
  410. }
  411. TEST_F(WebrtcVideoStatsDBImplTest, FailedWrite) {
  412. InitializeDB();
  413. // Expect the callback to indicate success = false when the write fails.
  414. EXPECT_CALL(*this, MockAppendVideoStatsCb(false));
  415. // Append stats, but fail the internal DB update.
  416. stats_db_->AppendVideoStats(
  417. kDecodeStatsKeyVp9, VideoStats(1234, 240, 6, 7.2),
  418. base::BindOnce(&WebrtcVideoStatsDBImplTest::MockAppendVideoStatsCb,
  419. base::Unretained(this)));
  420. fake_db_->GetCallback(true);
  421. fake_db_->UpdateCallback(false);
  422. }
  423. TEST_F(WebrtcVideoStatsDBImplTest, DiscardCorruptedDBData) {
  424. InitializeDB();
  425. // Inject a test clock and initialize with the current time.
  426. base::SimpleTestClock clock;
  427. SetDBClock(&clock);
  428. clock.SetNow(base::Time::Now());
  429. // Start with a proto that represents a valid uncorrupted and unexpired entry.
  430. WebrtcVideoStatsEntryProto valid_proto;
  431. WebrtcVideoStatsProto* valid_entry = valid_proto.add_stats();
  432. valid_entry->set_timestamp(clock.Now().ToJsTimeIgnoringNull());
  433. valid_entry->set_frames_processed(300);
  434. valid_entry->set_key_frames_processed(8);
  435. valid_entry->set_p99_processing_time_ms(11.3);
  436. // Append it and read it back without issue.
  437. AppendToProtoDB(kEncodeStatsKeyVp9, &valid_proto);
  438. VerifyReadStats(
  439. kEncodeStatsKeyVp9,
  440. {VideoStats{valid_entry->timestamp(), valid_entry->frames_processed(),
  441. valid_entry->key_frames_processed(),
  442. valid_entry->p99_processing_time_ms()}});
  443. WebrtcVideoStatsEntryProto invalid_proto;
  444. WebrtcVideoStatsProto* invalid_entry = invalid_proto.add_stats();
  445. // Invalid because number of frames processed is too low Verify
  446. // you can't read it back (filtered for corruption).
  447. *invalid_entry = *valid_entry;
  448. invalid_entry->set_frames_processed(30);
  449. AppendToProtoDB(kDecodeStatsKeyVp9, &invalid_proto);
  450. VerifyEmptyStats(kDecodeStatsKeyVp9);
  451. // Invalid because number of frames processed is too high. Verify
  452. // you can't read it back (filtered for corruption).
  453. *invalid_entry = *valid_entry;
  454. invalid_entry->set_frames_processed(1000000);
  455. AppendToProtoDB(kDecodeStatsKeyVp9, &invalid_proto);
  456. VerifyEmptyStats(kDecodeStatsKeyVp9);
  457. // Invalid because number of key frames is higher than number of frames
  458. // processed. Verify you can't read it back (filtered for corruption).
  459. *invalid_entry = *valid_entry;
  460. invalid_entry->set_key_frames_processed(valid_entry->frames_processed() + 1);
  461. AppendToProtoDB(kDecodeStatsKeyVp9, &invalid_proto);
  462. VerifyEmptyStats(kDecodeStatsKeyVp9);
  463. // Invalid processing time. Verify
  464. // you can't read it back (filtered for corruption).
  465. *invalid_entry = *valid_entry;
  466. invalid_entry->set_p99_processing_time_ms(-1.0);
  467. AppendToProtoDB(kDecodeStatsKeyVp9, &invalid_proto);
  468. VerifyEmptyStats(kDecodeStatsKeyVp9);
  469. *invalid_entry = *valid_entry;
  470. invalid_entry->set_p99_processing_time_ms(20000.0);
  471. AppendToProtoDB(kDecodeStatsKeyVp9, &invalid_proto);
  472. VerifyEmptyStats(kDecodeStatsKeyVp9);
  473. }
  474. TEST_F(WebrtcVideoStatsDBImplTest, WriteAndReadCollection) {
  475. InitializeDB();
  476. // Set test clock.
  477. base::SimpleTestClock clock;
  478. SetDBClock(&clock);
  479. clock.SetNow(base::Time::Now());
  480. // Append stats for multiple resolutions.
  481. VideoStats stats1(clock.Now().ToJsTimeIgnoringNull(), 240, 6, 7.2);
  482. VideoStatsEntry entry1{stats1};
  483. AppendStats(kDecodeStatsKeyVp9, stats1);
  484. VideoStats stats2(clock.Now().ToJsTimeIgnoringNull(), 360, 7, 9.2);
  485. VideoStatsEntry entry2{stats2};
  486. AppendStats(kDecodeStatsKeyVp9FullHd, stats2);
  487. VideoStats stats3(clock.Now().ToJsTimeIgnoringNull(), 480, 11, 13.3);
  488. VideoStatsEntry entry3{stats3};
  489. AppendStats(kDecodeStatsKeyVp94K, stats3);
  490. // Add elements that should not be returned.
  491. VideoStats stats4(clock.Now().ToJsTimeIgnoringNull(), 490, 13, 15.3);
  492. AppendStats(kEncodeStatsKeyVp9, stats4);
  493. AppendStats(kDecodeStatsKeyVp9Hw, stats4);
  494. // Created the expected collection that should be returned.
  495. WebrtcVideoStatsDB::VideoStatsCollection expected;
  496. expected.insert({kDecodeStatsKeyVp9.pixels, entry1});
  497. expected.insert({kDecodeStatsKeyVp9FullHd.pixels, entry2});
  498. expected.insert({kDecodeStatsKeyVp94K.pixels, entry3});
  499. // The same collection is returned for all keys that are associated to the
  500. // collection.
  501. VerifyReadStatsCollection(kDecodeStatsKeyVp9, expected);
  502. VerifyReadStatsCollection(kDecodeStatsKeyVp9FullHd, expected);
  503. VerifyReadStatsCollection(kDecodeStatsKeyVp94K, expected);
  504. }
  505. } // namespace media