summaryrefslogtreecommitdiff
path: root/chromium/media/capabilities/in_memory_video_decode_stats_db_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/media/capabilities/in_memory_video_decode_stats_db_unittest.cc')
-rw-r--r--chromium/media/capabilities/in_memory_video_decode_stats_db_unittest.cc391
1 files changed, 391 insertions, 0 deletions
diff --git a/chromium/media/capabilities/in_memory_video_decode_stats_db_unittest.cc b/chromium/media/capabilities/in_memory_video_decode_stats_db_unittest.cc
new file mode 100644
index 00000000000..6f6264bf490
--- /dev/null
+++ b/chromium/media/capabilities/in_memory_video_decode_stats_db_unittest.cc
@@ -0,0 +1,391 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/test/scoped_task_environment.h"
+#include "media/capabilities/in_memory_video_decode_stats_db_impl.h"
+#include "media/capabilities/video_decode_stats_db_provider.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Eq;
+using testing::Pointee;
+using testing::IsNull;
+
+namespace media {
+
+static VideoDecodeStatsDB::VideoDescKey kTestKey() {
+ return VideoDecodeStatsDB::VideoDescKey::MakeBucketedKey(
+ VP9PROFILE_PROFILE3, gfx::Size(1024, 768), 60);
+}
+
+static VideoDecodeStatsDB::DecodeStatsEntry kEmtpyEntry() {
+ return VideoDecodeStatsDB::DecodeStatsEntry(0, 0, 0);
+}
+
+class MockSeedDB : public VideoDecodeStatsDB {
+ public:
+ MockSeedDB() = default;
+ ~MockSeedDB() override = default;
+
+ MOCK_METHOD1(Initialize, void(InitializeCB init_cb));
+ MOCK_METHOD3(AppendDecodeStats,
+ void(const VideoDescKey& key,
+ const DecodeStatsEntry& entry,
+ AppendDecodeStatsCB append_done_cb));
+ MOCK_METHOD2(GetDecodeStats,
+ void(const VideoDescKey& key, GetDecodeStatsCB get_stats_cb));
+ MOCK_METHOD1(DestroyStats, void(base::OnceClosure destroy_done_cb));
+};
+
+class MockDBProvider : public VideoDecodeStatsDBProvider {
+ public:
+ MockDBProvider() = default;
+ ~MockDBProvider() override = default;
+
+ MOCK_METHOD1(GetVideoDecodeStatsDB, void(GetCB get_db_b));
+};
+
+template <bool WithSeedDB>
+class InMemoryDBTestBase : public testing::Test {
+ public:
+ InMemoryDBTestBase()
+ : seed_db_(WithSeedDB ? new MockSeedDB() : nullptr),
+ db_provider_(WithSeedDB ? new MockDBProvider() : nullptr),
+ in_memory_db_(new InMemoryVideoDecodeStatsDBImpl(db_provider_.get())) {
+ // Setup MockDBProvider to provide the seed DB. No need to initialize the
+ // DB here since it too is a Mock.
+ if (db_provider_) {
+ using GetCB = VideoDecodeStatsDBProvider::GetCB;
+ ON_CALL(*db_provider_, GetVideoDecodeStatsDB(_))
+ .WillByDefault([&](GetCB cb) { std::move(cb).Run(seed_db_.get()); });
+ }
+
+ // The InMemoryDB should NEVER modify the seed DB.
+ if (seed_db_) {
+ EXPECT_CALL(*seed_db_, AppendDecodeStats(_, _, _)).Times(0);
+ EXPECT_CALL(*seed_db_, DestroyStats(_)).Times(0);
+ }
+ }
+
+ void InitializeEmptyDB() {
+ if (seed_db_)
+ EXPECT_CALL(*db_provider_, GetVideoDecodeStatsDB(_));
+
+ EXPECT_CALL(*this, InitializeCB(true));
+
+ in_memory_db_->Initialize(base::BindOnce(&InMemoryDBTestBase::InitializeCB,
+ base::Unretained(this)));
+ scoped_task_environment_.RunUntilIdle();
+ }
+
+ MOCK_METHOD1(InitializeCB, void(bool success));
+ MOCK_METHOD1(AppendDecodeStatsCB, void(bool success));
+ MOCK_METHOD2(
+ GetDecodeStatsCB,
+ void(bool success,
+ std::unique_ptr<VideoDecodeStatsDB::DecodeStatsEntry> entry));
+ MOCK_METHOD0(DestroyStatsCB, void());
+
+ protected:
+ using VideoDescKey = media::VideoDecodeStatsDB::VideoDescKey;
+ using DecodeStatsEntry = media::VideoDecodeStatsDB::DecodeStatsEntry;
+
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ std::unique_ptr<MockSeedDB> seed_db_;
+ std::unique_ptr<MockDBProvider> db_provider_;
+ std::unique_ptr<InMemoryVideoDecodeStatsDBImpl> in_memory_db_;
+};
+
+// Specialization for tests that have/lack a seed DB. Some tests only make sense
+// with seed DB, so we separate them.
+class SeededInMemoryDBTest : public InMemoryDBTestBase<true> {};
+class SeedlessInMemoryDBTest : public InMemoryDBTestBase<false> {};
+
+TEST_F(SeedlessInMemoryDBTest, ReadExpectingEmpty) {
+ InitializeEmptyDB();
+
+ // Database is empty, seed DB is empty => expect empty stats entry.
+ EXPECT_CALL(*this, GetDecodeStatsCB(true, Pointee(Eq(kEmtpyEntry()))));
+
+ in_memory_db_->GetDecodeStats(
+ kTestKey(), base::BindOnce(&InMemoryDBTestBase::GetDecodeStatsCB,
+ base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+}
+
+TEST_F(SeededInMemoryDBTest, ReadExpectingEmpty) {
+ InitializeEmptyDB();
+
+ // Make seed DB return null (empty) for this request.
+ EXPECT_CALL(*seed_db_, GetDecodeStats(Eq(kTestKey()), _))
+ .WillOnce([](const auto& key, auto get_cb) {
+ std::move(get_cb).Run(true, nullptr);
+ });
+
+ // Database is empty, seed DB is empty => expect empty stats entry.
+ EXPECT_CALL(*this, GetDecodeStatsCB(true, Pointee(Eq(kEmtpyEntry()))));
+
+ in_memory_db_->GetDecodeStats(
+ kTestKey(), base::BindOnce(&InMemoryDBTestBase::GetDecodeStatsCB,
+ base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+}
+
+TEST_F(SeededInMemoryDBTest, ReadExpectingSeedData) {
+ InitializeEmptyDB();
+
+ // Setup seed DB to return an entry for the test key.
+ DecodeStatsEntry seed_entry(1000, 2, 10);
+
+ EXPECT_CALL(*seed_db_, GetDecodeStats(Eq(kTestKey()), _))
+ .WillOnce([&](const auto& key, auto get_cb) {
+ std::move(get_cb).Run(true,
+ std::make_unique<DecodeStatsEntry>(seed_entry));
+ });
+
+ // Seed DB has a an entry for the test key. Expect it!
+ EXPECT_CALL(*this, GetDecodeStatsCB(true, Pointee(Eq(seed_entry))));
+
+ in_memory_db_->GetDecodeStats(
+ kTestKey(), base::BindOnce(&InMemoryDBTestBase::GetDecodeStatsCB,
+ base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+ ::testing::Mock::VerifyAndClear(this);
+
+ // Verify a second GetDecodeStats() call with the same key does not trigger a
+ // second call to the seed DB (we cache it).
+ EXPECT_CALL(*seed_db_, GetDecodeStats(_, _)).Times(0);
+ EXPECT_CALL(*this, GetDecodeStatsCB(true, Pointee(Eq(seed_entry))));
+ in_memory_db_->GetDecodeStats(
+ kTestKey(), base::BindOnce(&InMemoryDBTestBase::GetDecodeStatsCB,
+ base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+}
+
+TEST_F(SeededInMemoryDBTest, AppendReadAndDestroy) {
+ const DecodeStatsEntry seed_entry(1000, 2, 10);
+ const DecodeStatsEntry double_seed_entry(2000, 4, 20);
+ const DecodeStatsEntry triple_seed_entry(3000, 6, 30);
+
+ InitializeEmptyDB();
+
+ // Setup seed DB to always return an entry for the test key.
+ ON_CALL(*seed_db_, GetDecodeStats(Eq(kTestKey()), _))
+ .WillByDefault([&](const auto& key, auto get_cb) {
+ std::move(get_cb).Run(true,
+ std::make_unique<DecodeStatsEntry>(seed_entry));
+ });
+
+ // First append should trigger a request for the same key from the seed DB.
+ // Simulate a successful read providing seed_entry for that key.
+ EXPECT_CALL(*seed_db_, GetDecodeStats(Eq(kTestKey()), _));
+
+ // Append the same seed entry, doubling the stats for this key.
+ EXPECT_CALL(*this, AppendDecodeStatsCB(true));
+ in_memory_db_->AppendDecodeStats(
+ kTestKey(), seed_entry,
+ base::BindOnce(&InMemoryDBTestBase::AppendDecodeStatsCB,
+ base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+ ::testing::Mock::VerifyAndClear(this);
+
+ // Seed DB should not be queried again for this key.
+ EXPECT_CALL(*seed_db_, GetDecodeStats(Eq(kTestKey()), _)).Times(0);
+
+ // Now verify that the stats were doubled by the append above.
+ EXPECT_CALL(*this, GetDecodeStatsCB(true, Pointee(Eq(double_seed_entry))));
+ in_memory_db_->GetDecodeStats(
+ kTestKey(), base::BindOnce(&InMemoryDBTestBase::GetDecodeStatsCB,
+ base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+ ::testing::Mock::VerifyAndClear(this);
+
+ // Append the same seed entry again to triple the stats. Additional appends
+ // should not trigger queries the seed DB for this key.
+ EXPECT_CALL(*seed_db_, GetDecodeStats(Eq(kTestKey()), _)).Times(0);
+ in_memory_db_->AppendDecodeStats(
+ kTestKey(), seed_entry,
+ base::BindOnce(&InMemoryDBTestBase::AppendDecodeStatsCB,
+ base::Unretained(this)));
+
+ // Verify we have 3x the stats.
+ EXPECT_CALL(*this, GetDecodeStatsCB(true, Pointee(Eq(triple_seed_entry))));
+ in_memory_db_->GetDecodeStats(
+ kTestKey(), base::BindOnce(&InMemoryDBTestBase::GetDecodeStatsCB,
+ base::Unretained(this)));
+
+ // Now destroy the in-memory stats...
+ EXPECT_CALL(*this, DestroyStatsCB());
+ in_memory_db_->DestroyStats(base::BindOnce(
+ &InMemoryDBTestBase::DestroyStatsCB, base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+ ::testing::Mock::VerifyAndClear(this);
+
+ // With in-memory stats now gone, GetDecodeStats(kTestKey()) should again
+ // trigger a call to the seed DB and return the un-doubled seed stats.
+ EXPECT_CALL(*seed_db_, GetDecodeStats(Eq(kTestKey()), _));
+ EXPECT_CALL(*this, GetDecodeStatsCB(true, Pointee(Eq(seed_entry))));
+ in_memory_db_->GetDecodeStats(
+ kTestKey(), base::BindOnce(&InMemoryDBTestBase::GetDecodeStatsCB,
+ base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+}
+
+TEST_F(SeedlessInMemoryDBTest, AppendReadAndDestroy) {
+ const DecodeStatsEntry entry(50, 1, 5);
+ const DecodeStatsEntry double_entry(100, 2, 10);
+
+ InitializeEmptyDB();
+
+ // Expect successful append to the empty seedless DB.
+ EXPECT_CALL(*this, AppendDecodeStatsCB(true));
+ in_memory_db_->AppendDecodeStats(
+ kTestKey(), entry,
+ base::BindOnce(&InMemoryDBTestBase::AppendDecodeStatsCB,
+ base::Unretained(this)));
+
+ // Verify stats can be read back.
+ EXPECT_CALL(*this, GetDecodeStatsCB(true, Pointee(Eq(entry))));
+ in_memory_db_->GetDecodeStats(
+ kTestKey(), base::BindOnce(&InMemoryDBTestBase::GetDecodeStatsCB,
+ base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+ ::testing::Mock::VerifyAndClear(this);
+
+ // Append same stats again to test summation.
+ EXPECT_CALL(*this, AppendDecodeStatsCB(true));
+ in_memory_db_->AppendDecodeStats(
+ kTestKey(), entry,
+ base::BindOnce(&InMemoryDBTestBase::AppendDecodeStatsCB,
+ base::Unretained(this)));
+
+ // Verify doubled stats can be read back.
+ EXPECT_CALL(*this, GetDecodeStatsCB(true, Pointee(Eq(double_entry))));
+ in_memory_db_->GetDecodeStats(
+ kTestKey(), base::BindOnce(&InMemoryDBTestBase::GetDecodeStatsCB,
+ base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+ ::testing::Mock::VerifyAndClear(this);
+
+ // Now destroy the in-memory stats...
+ EXPECT_CALL(*this, DestroyStatsCB());
+ in_memory_db_->DestroyStats(base::BindOnce(
+ &InMemoryDBTestBase::DestroyStatsCB, base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+ ::testing::Mock::VerifyAndClear(this);
+
+ // Verify DB now empty for this key.
+ EXPECT_CALL(*this, GetDecodeStatsCB(true, Pointee(Eq(kEmtpyEntry()))));
+ in_memory_db_->GetDecodeStats(
+ kTestKey(), base::BindOnce(&InMemoryDBTestBase::GetDecodeStatsCB,
+ base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+}
+
+TEST_F(SeededInMemoryDBTest, ProvidedNullSeedDB) {
+ // DB provider may provide a null seed DB if it encounters some error.
+ EXPECT_CALL(*db_provider_, GetVideoDecodeStatsDB(_))
+ .WillOnce([](auto get_db_cb) { std::move(get_db_cb).Run(nullptr); });
+
+ // Failing to obtain the seed DB is not a show stopper. The in-memory DB
+ // should simply carry on in a seedless fashion.
+ EXPECT_CALL(*this, InitializeCB(true));
+ in_memory_db_->Initialize(base::BindOnce(&InMemoryDBTestBase::InitializeCB,
+ base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+ ::testing::Mock::VerifyAndClear(this);
+
+ // Writes still succeed.
+ EXPECT_CALL(*this, AppendDecodeStatsCB(true));
+ const DecodeStatsEntry entry(50, 1, 5);
+ in_memory_db_->AppendDecodeStats(
+ kTestKey(), entry,
+ base::BindOnce(&InMemoryDBTestBase::AppendDecodeStatsCB,
+ base::Unretained(this)));
+
+ // Reads should still succeed.
+ EXPECT_CALL(*this, GetDecodeStatsCB(true, Pointee(Eq(entry))));
+ in_memory_db_->GetDecodeStats(
+ kTestKey(), base::BindOnce(&InMemoryDBTestBase::GetDecodeStatsCB,
+ base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+}
+
+TEST_F(SeededInMemoryDBTest, SeedReadFailureOnGettingStats) {
+ // Everything seems fine at initialization...
+ InitializeEmptyDB();
+
+ // But seed DB will repeatedly fail to provide stats.
+ ON_CALL(*seed_db_, GetDecodeStats(_, _))
+ .WillByDefault([](const auto& key, auto get_cb) {
+ std::move(get_cb).Run(false, nullptr);
+ });
+
+ // Reading the in-memory will still try to read the seed DB, and the read
+ // callback will simply report that the DB is empty for this key.
+ EXPECT_CALL(*seed_db_, GetDecodeStats(Eq(kTestKey()), _));
+ EXPECT_CALL(*this, GetDecodeStatsCB(true, Pointee(Eq(kEmtpyEntry()))));
+ in_memory_db_->GetDecodeStats(
+ kTestKey(), base::BindOnce(&InMemoryDBTestBase::GetDecodeStatsCB,
+ base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+}
+
+TEST_F(SeededInMemoryDBTest, SeedReadFailureOnAppendingingStats) {
+ // Everything seems fine at initialization...
+ InitializeEmptyDB();
+
+ // But seed DB will repeatedly fail to provide stats.
+ ON_CALL(*seed_db_, GetDecodeStats(_, _))
+ .WillByDefault([](const auto& key, auto get_cb) {
+ std::move(get_cb).Run(false, nullptr);
+ });
+
+ // Appending to the in-memory will still try to read the seed DB, and the
+ // append will proceed successfully as if the seed DB were empty.
+ EXPECT_CALL(*seed_db_, GetDecodeStats(Eq(kTestKey()), _));
+ EXPECT_CALL(*this, AppendDecodeStatsCB(true));
+ const DecodeStatsEntry entry(50, 1, 5);
+ in_memory_db_->AppendDecodeStats(
+ kTestKey(), entry,
+ base::BindOnce(&InMemoryDBTestBase::AppendDecodeStatsCB,
+ base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+ ::testing::Mock::VerifyAndClear(this);
+
+ // Reading the appended data works without issue and does not trigger new
+ // queries to the seed DB.
+ EXPECT_CALL(*seed_db_, GetDecodeStats(Eq(kTestKey()), _)).Times(0);
+ EXPECT_CALL(*this, GetDecodeStatsCB(true, Pointee(Eq(entry))));
+ in_memory_db_->GetDecodeStats(
+ kTestKey(), base::BindOnce(&InMemoryDBTestBase::GetDecodeStatsCB,
+ base::Unretained(this)));
+
+ scoped_task_environment_.RunUntilIdle();
+}
+
+} // namespace media