blob: 71a6ee191d25c2b98932460ae2844553903e1298 [file] [log] [blame]
// 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 "components/feed/core/feed_storage_database.h"
#include <map>
#include "base/test/scoped_task_environment.h"
#include "components/feed/core/proto/feed_storage.pb.h"
#include "components/feed/core/time_serialization.h"
#include "components/leveldb_proto/testing/fake_db.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using leveldb_proto::test::FakeDB;
using testing::Mock;
using testing::NotNull;
using testing::_;
namespace feed {
namespace {
const std::string kContentKeyPrefix = "ContentKey";
const std::string kContentKey1 = "ContentKey1";
const std::string kContentKey2 = "ContentKey2";
const std::string kContentKey3 = "ContentKey3";
const std::string kContentData1 = "Content Data1";
const std::string kContentData2 = "Content Data2";
const std::string kContentData3 = "Content Data3";
const std::string kJournalKey1 = "JournalKey1";
const std::string kJournalKey2 = "JournalKey2";
const std::string kJournalKey3 = "JournalKey3";
const std::string kJournalData1 = "Journal Data1";
const std::string kJournalData2 = "Journal Data2";
const std::string kJournalData3 = "Journal Data3";
const std::string kJournalData4 = "Journal Data4";
const std::string kJournalData5 = "Journal Data5";
const std::string kJournalData6 = "Journal Data6";
} // namespace
class FeedStorageDatabaseTest : public testing::Test {
public:
FeedStorageDatabaseTest() : storage_db_(nullptr) {}
void CreateDatabase(bool init_database) {
// The FakeDBs are owned by |feed_db_|, so clear our pointers before
// resetting |feed_db_| itself.
storage_db_ = nullptr;
// Explicitly destroy any existing database before creating a new one.
feed_db_.reset();
auto storage_db =
std::make_unique<FakeDB<FeedStorageProto>>(&storage_db_storage_);
storage_db_ = storage_db.get();
feed_db_ = std::make_unique<FeedStorageDatabase>(base::FilePath(),
std::move(storage_db));
if (init_database) {
storage_db_->InitCallback(true);
ASSERT_TRUE(db()->IsInitialized());
}
}
void InjectContentStorageProto(const std::string& key,
const std::string& data) {
FeedStorageProto storage_proto;
storage_proto.set_key(key);
storage_proto.set_content_data(data);
storage_db_storage_["cs-" + key] = storage_proto;
}
void InjectJournalStorageProto(const std::string& key,
const std::vector<std::string>& entries) {
FeedStorageProto storage_proto;
storage_proto.set_key(key);
for (const std::string& entry : entries) {
storage_proto.add_journal_data(entry);
}
storage_db_storage_["js-" + key] = storage_proto;
}
void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); }
FakeDB<FeedStorageProto>* storage_db() { return storage_db_; }
FeedStorageDatabase* db() { return feed_db_.get(); }
MOCK_METHOD1(OnContentEntriesReceived,
void(std::vector<std::pair<std::string, std::string>>));
MOCK_METHOD1(OnContentKeyReceived, void(std::vector<std::string>));
MOCK_METHOD1(OnJournalEntryReceived, void(std::vector<std::string>));
MOCK_METHOD1(OnJournalEntriesReceived,
void(std::vector<std::vector<std::string>>));
MOCK_METHOD1(OnStorageCommitted, void(bool));
private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
std::map<std::string, FeedStorageProto> storage_db_storage_;
// Owned by |feed_db_|.
FakeDB<FeedStorageProto>* storage_db_;
std::unique_ptr<FeedStorageDatabase> feed_db_;
DISALLOW_COPY_AND_ASSIGN(FeedStorageDatabaseTest);
};
TEST_F(FeedStorageDatabaseTest, Init) {
ASSERT_FALSE(db());
CreateDatabase(/*init_database=*/false);
storage_db()->InitCallback(true);
EXPECT_TRUE(db()->IsInitialized());
}
TEST_F(FeedStorageDatabaseTest, LoadContentAfterInitSuccess) {
CreateDatabase(/*init_database=*/true);
EXPECT_CALL(*this, OnContentEntriesReceived(_));
db()->LoadContent(
{kContentKey1},
base::BindOnce(&FeedStorageDatabaseTest::OnContentEntriesReceived,
base::Unretained(this)));
storage_db()->LoadCallback(true);
}
TEST_F(FeedStorageDatabaseTest, LoadContentsEntries) {
CreateDatabase(/*init_database=*/true);
// Store |kContentKey1| and |kContentKey2|.
InjectContentStorageProto(kContentKey1, kContentData1);
InjectContentStorageProto(kContentKey2, kContentData2);
InjectJournalStorageProto(kJournalKey1,
{kJournalData1, kJournalData2, kJournalData3});
InjectJournalStorageProto(kJournalKey2, {kJournalData4, kJournalData5});
InjectJournalStorageProto(kJournalKey3, {kJournalData6});
// Try to Load |kContentKey2| and |kContentKey3|, only |kContentKey2| should
// return.
EXPECT_CALL(*this, OnContentEntriesReceived(_))
.WillOnce([](std::vector<std::pair<std::string, std::string>> results) {
ASSERT_EQ(results.size(), 1U);
EXPECT_EQ(results[0].first, kContentKey2);
EXPECT_EQ(results[0].second, kContentData2);
});
db()->LoadContent(
{kContentKey2, kContentKey3},
base::BindOnce(&FeedStorageDatabaseTest::OnContentEntriesReceived,
base::Unretained(this)));
storage_db()->LoadCallback(true);
}
TEST_F(FeedStorageDatabaseTest, LoadContentsEntriesByPrefix) {
CreateDatabase(/*init_database=*/true);
// Store |kContentKey1|, |kContentKey2|, |kJournalKey1|, |kJournalKey2|,
// |kJournalKey3|.
InjectContentStorageProto(kContentKey1, kContentData1);
InjectContentStorageProto(kContentKey2, kContentData2);
InjectJournalStorageProto(kJournalKey1,
{kJournalData1, kJournalData2, kJournalData3});
InjectJournalStorageProto(kJournalKey2, {kJournalData4, kJournalData5});
InjectJournalStorageProto(kJournalKey3, {kJournalData6});
// Try to Load "ContentKey", both |kContentKey1| and |kContentKey2| should
// return.
EXPECT_CALL(*this, OnContentEntriesReceived(_))
.WillOnce([](std::vector<std::pair<std::string, std::string>> results) {
ASSERT_EQ(results.size(), 2U);
EXPECT_EQ(results[0].first, kContentKey1);
EXPECT_EQ(results[0].second, kContentData1);
EXPECT_EQ(results[1].first, kContentKey2);
EXPECT_EQ(results[1].second, kContentData2);
});
db()->LoadContentByPrefix(
kContentKeyPrefix,
base::BindOnce(&FeedStorageDatabaseTest::OnContentEntriesReceived,
base::Unretained(this)));
storage_db()->LoadCallback(true);
}
TEST_F(FeedStorageDatabaseTest, LoadAllContentKeys) {
CreateDatabase(/*init_database=*/true);
// Store |kContentKey1|, |kContentKey2|, |kJournalKey1|, |kJournalKey2|,
// |kJournalKey3|.
InjectContentStorageProto(kContentKey1, kContentData1);
InjectContentStorageProto(kContentKey2, kContentData2);
InjectJournalStorageProto(kJournalKey1,
{kJournalData1, kJournalData2, kJournalData3});
InjectJournalStorageProto(kJournalKey2, {kJournalData4, kJournalData5});
InjectJournalStorageProto(kJournalKey3, {kJournalData6});
EXPECT_CALL(*this, OnContentKeyReceived(_))
.WillOnce([](std::vector<std::string> results) {
ASSERT_EQ(results.size(), 2U);
EXPECT_EQ(results[0], kContentKey1);
EXPECT_EQ(results[1], kContentKey2);
});
db()->LoadAllContentKeys(base::BindOnce(
&FeedStorageDatabaseTest::OnContentKeyReceived, base::Unretained(this)));
storage_db()->LoadKeysCallback(true);
}
TEST_F(FeedStorageDatabaseTest, SaveContent) {
CreateDatabase(/*init_database=*/true);
// Store |kContentKey1|, |kContentKey2|, |kJournalKey1|, |kJournalKey2|,
// |kJournalKey3|.
std::vector<std::pair<std::string, std::string>> entries;
entries.push_back(std::make_pair(kContentKey1, kContentData1));
entries.push_back(std::make_pair(kContentKey2, kContentData2));
EXPECT_CALL(*this, OnStorageCommitted(true));
db()->SaveContent(std::move(entries),
base::BindOnce(&FeedStorageDatabaseTest::OnStorageCommitted,
base::Unretained(this)));
storage_db()->UpdateCallback(true);
// Make sure they're there.
EXPECT_CALL(*this, OnContentEntriesReceived(_))
.WillOnce([](std::vector<std::pair<std::string, std::string>> results) {
ASSERT_EQ(results.size(), 2U);
EXPECT_EQ(results[0].first, kContentKey1);
EXPECT_EQ(results[0].second, kContentData1);
EXPECT_EQ(results[1].first, kContentKey2);
EXPECT_EQ(results[1].second, kContentData2);
});
db()->LoadContent(
{kContentKey1, kContentKey2},
base::BindOnce(&FeedStorageDatabaseTest::OnContentEntriesReceived,
base::Unretained(this)));
storage_db()->LoadCallback(true);
}
TEST_F(FeedStorageDatabaseTest, DeleteContent) {
CreateDatabase(/*init_database=*/true);
// Store |kContentKey1| and |kContentKey2|.
InjectContentStorageProto(kContentKey1, kContentData1);
InjectContentStorageProto(kContentKey2, kContentData2);
// Delete |kContentKey2| and |kContentKey3|
std::vector<std::string> keys;
keys.push_back(kContentKey2);
keys.push_back(kContentKey3);
EXPECT_CALL(*this, OnStorageCommitted(true));
db()->DeleteContent(
std::move(keys),
base::BindOnce(&FeedStorageDatabaseTest::OnStorageCommitted,
base::Unretained(this)));
storage_db()->UpdateCallback(true);
// Make sure only |kContentKey2| got deleted.
EXPECT_CALL(*this, OnContentEntriesReceived(_))
.WillOnce([](std::vector<std::pair<std::string, std::string>> results) {
EXPECT_EQ(results.size(), 1U);
EXPECT_EQ(results[0].first, kContentKey1);
EXPECT_EQ(results[0].second, kContentData1);
});
db()->LoadContent(
{kContentKey1, kContentKey2},
base::BindOnce(&FeedStorageDatabaseTest::OnContentEntriesReceived,
base::Unretained(this)));
storage_db()->LoadCallback(true);
}
TEST_F(FeedStorageDatabaseTest, DeleteContentByPrefix) {
CreateDatabase(/*init_database=*/true);
// Store |kContentKey1| and |kContentKey2|.
InjectContentStorageProto(kContentKey1, kContentData1);
InjectContentStorageProto(kContentKey2, kContentData2);
// Delete |kContentKey1| and |kContentKey2|
EXPECT_CALL(*this, OnStorageCommitted(true));
db()->DeleteContentByPrefix(
kContentKeyPrefix,
base::BindOnce(&FeedStorageDatabaseTest::OnStorageCommitted,
base::Unretained(this)));
storage_db()->UpdateCallback(true);
// Make sure |kContentKey1| and |kContentKey2| got deleted.
EXPECT_CALL(*this, OnContentEntriesReceived(_))
.WillOnce([](std::vector<std::pair<std::string, std::string>> results) {
EXPECT_EQ(results.size(), 0U);
});
db()->LoadContent(
{kContentKey1, kContentKey2},
base::BindOnce(&FeedStorageDatabaseTest::OnContentEntriesReceived,
base::Unretained(this)));
storage_db()->LoadCallback(true);
}
TEST_F(FeedStorageDatabaseTest, DeleteAllContent) {
CreateDatabase(/*init_database=*/true);
// Store |kContentKey1| and |kContentKey2|.
InjectContentStorageProto(kContentKey1, kContentData1);
InjectContentStorageProto(kContentKey2, kContentData2);
// Store |kJournalKey1|, |kJournalKey2|, |kJournalKey3|.
InjectJournalStorageProto(kJournalKey1,
{kJournalData1, kJournalData2, kJournalData3});
InjectJournalStorageProto(kJournalKey2, {kJournalData4, kJournalData5});
InjectJournalStorageProto(kJournalKey3, {kJournalData6});
// Delete all content, meaning |kContentKey1| and |kContentKey2| are expected
// to be deleted.
EXPECT_CALL(*this, OnStorageCommitted(true));
db()->DeleteAllContent(base::BindOnce(
&FeedStorageDatabaseTest::OnStorageCommitted, base::Unretained(this)));
storage_db()->UpdateCallback(true);
// Make sure |kContentKey1| and |kContentKey2| got deleted.
EXPECT_CALL(*this, OnContentEntriesReceived(_))
.WillOnce([](std::vector<std::pair<std::string, std::string>> results) {
EXPECT_EQ(results.size(), 0U);
});
db()->LoadContent(
{kContentKey1, kContentKey2},
base::BindOnce(&FeedStorageDatabaseTest::OnContentEntriesReceived,
base::Unretained(this)));
storage_db()->LoadCallback(true);
// Make sure all journals are there.
EXPECT_CALL(*this, OnJournalEntriesReceived(_))
.WillOnce([](std::vector<std::vector<std::string>> results) {
ASSERT_EQ(results.size(), 3U);
});
db()->LoadAllJournals(
base::BindOnce(&FeedStorageDatabaseTest::OnJournalEntriesReceived,
base::Unretained(this)));
storage_db()->LoadCallback(true);
}
TEST_F(FeedStorageDatabaseTest, LoadJournalEntry) {
CreateDatabase(/*init_database=*/true);
// Store |kJournalKey1|.
InjectJournalStorageProto(kJournalKey1,
{kJournalData1, kJournalData2, kJournalData3});
// Try to Load |kJournalKey1|.
EXPECT_CALL(*this, OnJournalEntryReceived(_))
.WillOnce([](std::vector<std::string> results) {
ASSERT_EQ(results.size(), 3U);
EXPECT_EQ(results[0], kJournalData1);
EXPECT_EQ(results[1], kJournalData2);
EXPECT_EQ(results[2], kJournalData3);
});
db()->LoadJournal(
kJournalKey1,
base::BindOnce(&FeedStorageDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->GetCallback(true);
}
TEST_F(FeedStorageDatabaseTest, LoadNonExistingJournalEntry) {
CreateDatabase(/*init_database=*/true);
// Try to Load |kJournalKey1|.
EXPECT_CALL(*this, OnJournalEntryReceived(_))
.WillOnce([](std::vector<std::string> results) {
ASSERT_EQ(results.size(), 0U);
});
db()->LoadJournal(
kJournalKey1,
base::BindOnce(&FeedStorageDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->GetCallback(true);
}
TEST_F(FeedStorageDatabaseTest, LoadAllJournals) {
CreateDatabase(/*init_database=*/true);
// Store |kContentKey1|, |kContentKey2|, |kJournalKey1|, |kJournalKey2|,
// |kJournalKey3|.
InjectContentStorageProto(kContentKey1, kContentData1);
InjectContentStorageProto(kContentKey2, kContentData2);
InjectJournalStorageProto(kJournalKey1,
{kJournalData1, kJournalData2, kJournalData3});
InjectJournalStorageProto(kJournalKey2, {kJournalData4, kJournalData5});
InjectJournalStorageProto(kJournalKey3, {kJournalData6});
EXPECT_CALL(*this, OnJournalEntriesReceived(_))
.WillOnce([](std::vector<std::vector<std::string>> results) {
ASSERT_EQ(results.size(), 3U);
EXPECT_EQ(results[0][0], kJournalData1);
EXPECT_EQ(results[0][1], kJournalData2);
EXPECT_EQ(results[0][2], kJournalData3);
EXPECT_EQ(results[1][0], kJournalData4);
EXPECT_EQ(results[1][1], kJournalData5);
EXPECT_EQ(results[2][0], kJournalData6);
});
db()->LoadAllJournals(
base::BindOnce(&FeedStorageDatabaseTest::OnJournalEntriesReceived,
base::Unretained(this)));
storage_db()->LoadCallback(true);
}
TEST_F(FeedStorageDatabaseTest, AppendToJournal_WhenJournalExists) {
CreateDatabase(/*init_database=*/true);
// Save |kContentKey1|
EXPECT_CALL(*this, OnStorageCommitted(true));
db()->AppendToJournal(
kJournalKey1, {kJournalData1, kJournalData2},
base::BindOnce(&FeedStorageDatabaseTest::OnStorageCommitted,
base::Unretained(this)));
storage_db()->GetCallback(true);
storage_db()->UpdateCallback(true);
// Make sure they're there.
EXPECT_CALL(*this, OnJournalEntryReceived(_))
.WillOnce([](std::vector<std::string> results) {
ASSERT_EQ(results.size(), 2U);
EXPECT_EQ(results[0], kJournalData1);
EXPECT_EQ(results[1], kJournalData2);
});
db()->LoadJournal(
kJournalKey1,
base::BindOnce(&FeedStorageDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->GetCallback(true);
Mock::VerifyAndClearExpectations(this);
// Append more for |kContentKey1|
EXPECT_CALL(*this, OnStorageCommitted(true));
db()->AppendToJournal(
kJournalKey1, {kJournalData3, kJournalData4, kJournalData5},
base::BindOnce(&FeedStorageDatabaseTest::OnStorageCommitted,
base::Unretained(this)));
storage_db()->GetCallback(true);
storage_db()->UpdateCallback(true);
// Check new instances are there.
EXPECT_CALL(*this, OnJournalEntryReceived(_))
.WillOnce([](std::vector<std::string> results) {
ASSERT_EQ(results.size(), 5U);
EXPECT_EQ(results[0], kJournalData1);
EXPECT_EQ(results[1], kJournalData2);
EXPECT_EQ(results[2], kJournalData3);
EXPECT_EQ(results[3], kJournalData4);
EXPECT_EQ(results[4], kJournalData5);
});
db()->LoadJournal(
kJournalKey1,
base::BindOnce(&FeedStorageDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->GetCallback(true);
}
TEST_F(FeedStorageDatabaseTest, AppendToJournal_WhenJournalMissing) {
CreateDatabase(/*init_database=*/true);
// Append data for |kContentKey1|
EXPECT_CALL(*this, OnStorageCommitted(true));
db()->AppendToJournal(
kJournalKey1, {kJournalData1, kJournalData2, kJournalData3},
base::BindOnce(&FeedStorageDatabaseTest::OnStorageCommitted,
base::Unretained(this)));
storage_db()->GetCallback(true);
storage_db()->UpdateCallback(true);
// Check new data are there.
EXPECT_CALL(*this, OnJournalEntryReceived(_))
.WillOnce([](std::vector<std::string> results) {
ASSERT_EQ(results.size(), 3U);
EXPECT_EQ(results[0], kJournalData1);
EXPECT_EQ(results[1], kJournalData2);
EXPECT_EQ(results[2], kJournalData3);
});
db()->LoadJournal(
kJournalKey1,
base::BindOnce(&FeedStorageDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->GetCallback(true);
}
TEST_F(FeedStorageDatabaseTest, CopyJournal) {
CreateDatabase(/*init_database=*/true);
// Save |kContentKey1|.
InjectJournalStorageProto(kJournalKey1,
{kJournalData1, kJournalData2, kJournalData3});
// Copy |kContentKey1| to |kContentKey2|.
EXPECT_CALL(*this, OnStorageCommitted(true));
db()->CopyJournal(kJournalKey1, kJournalKey2,
base::BindOnce(&FeedStorageDatabaseTest::OnStorageCommitted,
base::Unretained(this)));
storage_db()->GetCallback(true);
storage_db()->UpdateCallback(true);
// Check new journal is there.
EXPECT_CALL(*this, OnJournalEntryReceived(_))
.WillOnce([](std::vector<std::string> results) {
ASSERT_EQ(results.size(), 3U);
EXPECT_EQ(results[0], kJournalData1);
EXPECT_EQ(results[1], kJournalData2);
EXPECT_EQ(results[2], kJournalData3);
});
db()->LoadJournal(
kJournalKey2,
base::BindOnce(&FeedStorageDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->GetCallback(true);
Mock::VerifyAndClearExpectations(this);
// Check first journal is still there.
EXPECT_CALL(*this, OnJournalEntryReceived(_))
.WillOnce([](std::vector<std::string> results) {
ASSERT_EQ(results.size(), 3U);
EXPECT_EQ(results[0], kJournalData1);
EXPECT_EQ(results[1], kJournalData2);
EXPECT_EQ(results[2], kJournalData3);
});
db()->LoadJournal(
kJournalKey1,
base::BindOnce(&FeedStorageDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->GetCallback(true);
}
TEST_F(FeedStorageDatabaseTest, DeleteJournal) {
CreateDatabase(/*init_database=*/true);
// Store |kJournalKey1|, |kJournalKey2|, |kJournalKey3|.
InjectJournalStorageProto(kJournalKey1,
{kJournalData1, kJournalData2, kJournalData3});
InjectJournalStorageProto(kJournalKey2, {kJournalData4, kJournalData5});
InjectJournalStorageProto(kJournalKey3, {kJournalData6});
// Delete |kJournalKey2|.
EXPECT_CALL(*this, OnStorageCommitted(true));
db()->DeleteJournal(
kJournalKey2, base::BindOnce(&FeedStorageDatabaseTest::OnStorageCommitted,
base::Unretained(this)));
storage_db()->UpdateCallback(true);
// Make sure |kJournalKey2| got deleted.
EXPECT_CALL(*this, OnJournalEntriesReceived(_))
.WillOnce([](std::vector<std::vector<std::string>> results) {
ASSERT_EQ(results.size(), 2U);
EXPECT_EQ(results[0][0], kJournalData1);
EXPECT_EQ(results[0][1], kJournalData2);
EXPECT_EQ(results[0][2], kJournalData3);
EXPECT_EQ(results[1][0], kJournalData6);
});
db()->LoadAllJournals(
base::BindOnce(&FeedStorageDatabaseTest::OnJournalEntriesReceived,
base::Unretained(this)));
storage_db()->LoadCallback(true);
}
TEST_F(FeedStorageDatabaseTest, DeleteAllJournals) {
CreateDatabase(/*init_database=*/true);
// Store |kContentKey1| and |kContentKey2|.
InjectContentStorageProto(kContentKey1, kContentData1);
InjectContentStorageProto(kContentKey2, kContentData2);
// Store |kJournalKey1|, |kJournalKey2|, |kJournalKey3|.
InjectJournalStorageProto(kJournalKey1,
{kJournalData1, kJournalData2, kJournalData3});
InjectJournalStorageProto(kJournalKey2, {kJournalData4, kJournalData5});
InjectJournalStorageProto(kJournalKey3, {kJournalData6});
// Delete all journals, meaning |kJournalKey1|, |kJournalKey2| and
// |kJournalKey3| are expected to be deleted.
EXPECT_CALL(*this, OnStorageCommitted(true));
db()->DeleteAllJournals(base::BindOnce(
&FeedStorageDatabaseTest::OnStorageCommitted, base::Unretained(this)));
storage_db()->UpdateCallback(true);
// Make sure all journals got deleted.
EXPECT_CALL(*this, OnJournalEntriesReceived(_))
.WillOnce([](std::vector<std::vector<std::string>> results) {
ASSERT_EQ(results.size(), 0U);
});
db()->LoadAllJournals(
base::BindOnce(&FeedStorageDatabaseTest::OnJournalEntriesReceived,
base::Unretained(this)));
storage_db()->LoadCallback(true);
// Make sure all content are still there.
EXPECT_CALL(*this, OnContentEntriesReceived(_))
.WillOnce([](std::vector<std::pair<std::string, std::string>> results) {
ASSERT_EQ(results.size(), 2U);
EXPECT_EQ(results[0].first, kContentKey1);
EXPECT_EQ(results[0].second, kContentData1);
EXPECT_EQ(results[1].first, kContentKey2);
EXPECT_EQ(results[1].second, kContentData2);
});
db()->LoadContent(
{kContentKey1, kContentKey2},
base::BindOnce(&FeedStorageDatabaseTest::OnContentEntriesReceived,
base::Unretained(this)));
storage_db()->LoadCallback(true);
}
} // namespace feed