Commit 6eca5f27 authored by Gang Wu's avatar Gang Wu Committed by Commit Bot

[Feed] Implement commit Journal operations for Journal storage

Implement commit Journal operations for Journal storage on C++ side.

Bug:879855

Change-Id: I8bf9d38571a4c83f7110be2d0043a8471171ba8c
Reviewed-on: https://chromium-review.googlesource.com/1200943
Commit-Queue: Gang Wu <gangwu@chromium.org>
Reviewed-by: default avatarFilip Gorski <fgorski@chromium.org>
Reviewed-by: default avatarSky Malice <skym@chromium.org>
Cr-Commit-Position: refs/heads/master@{#590106}
parent 2658ccbe
......@@ -60,7 +60,7 @@ public class FeedJournalBridge {
public void commitJournalMutation(JournalMutation mutation, Callback<Boolean> callback) {
assert mNativeFeedJournalBridge != 0;
nativeCreateJournalMutation(mNativeFeedJournalBridge, mutation.getJournalName());
nativeStartJournalMutation(mNativeFeedJournalBridge, mutation.getJournalName());
for (JournalOperation operation : mutation.getOperations()) {
switch (operation.getType()) {
case Type.APPEND:
......@@ -110,7 +110,7 @@ public class FeedJournalBridge {
long nativeFeedJournalBridge, String journalName, Callback<String[]> callback);
private native void nativeCommitJournalMutation(
long nativeFeedJournalBridge, Callback<Boolean> callback);
private native void nativeCreateJournalMutation(
private native void nativeStartJournalMutation(
long nativeFeedJournalBridge, String journalName);
private native void nativeDeleteJournalMutation(long nativeFeedJournalBridge);
private native void nativeAddAppendOperation(long nativeFeedJournalBridge, String value);
......
......@@ -20,6 +20,7 @@
#include "chrome/browser/profiles/profile_android.h"
#include "components/feed/content/feed_host_service.h"
#include "components/feed/core/feed_journal_database.h"
#include "components/feed/core/feed_journal_mutation.h"
#include "jni/FeedJournalBridge_jni.h"
namespace feed {
......@@ -67,14 +68,21 @@ void FeedJournalBridge::LoadJournal(
ScopedJavaGlobalRef<jobject> callback(j_callback);
feed_journal_database_->LoadJournal(
journal_name, base::BindOnce(&FeedJournalBridge::OnLoadJournalDone,
weak_ptr_factory_.GetWeakPtr(), callback));
journal_name,
base::BindOnce(&FeedJournalBridge::OnLoadJournalDone, callback));
}
void FeedJournalBridge::CommitJournalMutation(
JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jobject>& j_callback) {}
const base::android::JavaRef<jobject>& j_callback) {
DCHECK(journal_mutation_);
ScopedJavaGlobalRef<jobject> callback(j_callback);
feed_journal_database_->CommitJournalMutation(
std::move(journal_mutation_),
base::BindOnce(&FeedJournalBridge::OnStorageCommitDone, callback));
}
void FeedJournalBridge::DoesJournalExist(
JNIEnv* j_env,
......@@ -92,29 +100,50 @@ void FeedJournalBridge::DeleteAllJournals(
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jobject>& j_callback) {}
void FeedJournalBridge::CreateJournalMutation(
void FeedJournalBridge::StartJournalMutation(
JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jstring>& j_journal_name) {}
const base::android::JavaRef<jstring>& j_journal_name) {
DCHECK(!journal_mutation_);
std::string journal_name = ConvertJavaStringToUTF8(j_env, j_journal_name);
journal_mutation_ =
std::make_unique<JournalMutation>(std::move(journal_name));
}
void FeedJournalBridge::DeleteJournalMutation(
JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this) {}
const base::android::JavaRef<jobject>& j_this) {
DCHECK(journal_mutation_);
journal_mutation_.reset();
}
void FeedJournalBridge::AddAppendOperation(
JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jstring>& j_value) {}
const base::android::JavaRef<jstring>& j_value) {
DCHECK(journal_mutation_);
std::string value = ConvertJavaStringToUTF8(j_env, j_value);
journal_mutation_->AddAppendOperation(std::move(value));
}
void FeedJournalBridge::AddCopyOperation(
JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jstring>& j_to_journal_name) {}
const base::android::JavaRef<jstring>& j_to_journal_name) {
DCHECK(journal_mutation_);
std::string to_journal_name =
ConvertJavaStringToUTF8(j_env, j_to_journal_name);
journal_mutation_->AddCopyOperation(std::move(to_journal_name));
}
void FeedJournalBridge::AddDeleteOperation(
JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this) {}
const base::android::JavaRef<jobject>& j_this) {
DCHECK(journal_mutation_);
journal_mutation_->AddDeleteOperation();
}
// static
void FeedJournalBridge::OnLoadJournalDone(
base::android::ScopedJavaGlobalRef<jobject> callback,
std::vector<std::string> entries) {
......@@ -125,4 +154,11 @@ void FeedJournalBridge::OnLoadJournalDone(
RunObjectCallbackAndroid(callback, j_entries);
}
// static
void FeedJournalBridge::OnStorageCommitDone(
ScopedJavaGlobalRef<jobject> callback,
bool success) {
RunBooleanCallbackAndroid(callback, success);
}
} // namespace feed
......@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_ANDROID_FEED_FEED_JOURNAL_BRIDGE_H_
#define CHROME_BROWSER_ANDROID_FEED_FEED_JOURNAL_BRIDGE_H_
#include <memory>
#include <string>
#include <vector>
......@@ -14,6 +15,7 @@
namespace feed {
class FeedJournalDatabase;
class JournalMutation;
// Native counterpart of FeedJournalBridge.java. Holds non-owning pointers
// to native implementation to which operations are delegated. Results are
......@@ -28,6 +30,7 @@ class FeedJournalBridge {
void Destroy(JNIEnv* j_env, const base::android::JavaRef<jobject>& j_this);
// Database related methods, they add/delete/update database.
void LoadJournal(JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jstring>& j_journal_name,
......@@ -46,7 +49,9 @@ class FeedJournalBridge {
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jobject>& j_callback);
void CreateJournalMutation(
// The following methods create/delete mutation, and add operations into
// mutation.
void StartJournalMutation(
JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jstring>& j_journal_name);
......@@ -63,8 +68,17 @@ class FeedJournalBridge {
const base::android::JavaRef<jobject>& j_this);
private:
void OnLoadJournalDone(base::android::ScopedJavaGlobalRef<jobject> callback,
std::vector<std::string> entries);
static void OnLoadJournalDone(
base::android::ScopedJavaGlobalRef<jobject> callback,
std::vector<std::string> entries);
static void OnStorageCommitDone(
base::android::ScopedJavaGlobalRef<jobject> callback,
bool success);
// This unique_ptr will hold a list of JournalOperations which are not
// committed yet. After send |journal_mutation_| to database, this unique_ptr
// will be reset.
std::unique_ptr<JournalMutation> journal_mutation_;
FeedJournalDatabase* feed_journal_database_;
......
......@@ -12,6 +12,8 @@
#include "base/sys_info.h"
#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/feed/core/feed_content_mutation.h"
#include "components/feed/core/feed_content_operation.h"
#include "components/feed/core/proto/content_storage.pb.h"
#include "components/leveldb_proto/proto_database_impl.h"
......
......@@ -12,12 +12,12 @@
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
#include "components/feed/core/feed_content_mutation.h"
#include "components/feed/core/feed_content_operation.h"
#include "components/leveldb_proto/proto_database.h"
namespace feed {
class ContentMutation;
class ContentOperation;
class ContentStorageProto;
// FeedContentDatabase is leveldb backend store for Feed's content storage data.
......
......@@ -8,6 +8,9 @@
#include "base/sys_info.h"
#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/feed/core/feed_journal_mutation.h"
#include "components/feed/core/feed_journal_operation.h"
#include "components/feed/core/proto/journal_storage.pb.h"
#include "components/leveldb_proto/proto_database_impl.h"
......@@ -76,6 +79,108 @@ void FeedJournalDatabase::LoadJournal(const std::string& key,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedJournalDatabase::CommitJournalMutation(
std::unique_ptr<JournalMutation> journal_mutation,
ConfirmationCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(journal_mutation);
if (journal_mutation->Empty()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), true));
return;
}
// Skip loading journal if the first operation is JOURNAL_DELETE.
if (journal_mutation->FirstOperationType() ==
JournalOperation::JOURNAL_DELETE) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&FeedJournalDatabase::PerformOperations,
weak_ptr_factory_.GetWeakPtr(), nullptr,
std::move(journal_mutation), std::move(callback)));
return;
}
std::string journal_name = journal_mutation->journal_name();
storage_database_->GetEntry(
journal_name,
base::BindOnce(&FeedJournalDatabase::OnGetEntryForCommitJournalMutation,
weak_ptr_factory_.GetWeakPtr(),
std::move(journal_mutation), std::move(callback)));
}
void FeedJournalDatabase::PerformOperations(
std::unique_ptr<JournalStorageProto> journal,
std::unique_ptr<JournalMutation> journal_mutation,
ConfirmationCallback callback) {
DCHECK(!journal_mutation->Empty());
if (journal) {
DCHECK_EQ(journal->key(), journal_mutation->journal_name());
} else {
journal = std::make_unique<JournalStorageProto>();
journal->set_key(journal_mutation->journal_name());
}
JournalMap copy_to_journal;
while (!journal_mutation->Empty()) {
JournalOperation operation = journal_mutation->TakeFristOperation();
switch (operation.type()) {
case JournalOperation::JOURNAL_APPEND:
journal->add_journal_data(operation.value());
break;
case JournalOperation::JOURNAL_COPY:
copy_to_journal[operation.to_journal_name()] =
CopyJouarnal(operation.to_journal_name(), *journal);
break;
case JournalOperation::JOURNAL_DELETE:
journal->clear_journal_data();
break;
}
}
CommitOperations(std::move(journal), std::move(copy_to_journal),
std::move(callback));
}
void FeedJournalDatabase::CommitOperations(
std::unique_ptr<JournalStorageProto> journal,
JournalMap copy_to_journal,
ConfirmationCallback callback) {
auto journals_to_save = std::make_unique<StorageEntryVector>();
auto journals_to_delete = std::make_unique<std::vector<std::string>>();
if (journal->journal_data_size() == 0) {
// This can only happens when the journal is deleted.
journals_to_delete->push_back(journal->key());
} else {
std::string journal_name = journal->key();
journals_to_save->emplace_back(journal_name, std::move(*journal));
}
for (JournalMap::iterator it = copy_to_journal.begin();
it != copy_to_journal.end(); ++it) {
journals_to_save->emplace_back(it->first, std::move(it->second));
}
storage_database_->UpdateEntries(
std::move(journals_to_save), std::move(journals_to_delete),
base::BindOnce(&FeedJournalDatabase::OnOperationCommitted,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedJournalDatabase::OnDatabaseInitialized(bool success) {
DCHECK_EQ(database_status_, UNINITIALIZED);
if (success) {
database_status_ = INITIALIZED;
} else {
database_status_ = INIT_FAILURE;
DVLOG(1) << "FeedJournalDatabase init failed.";
}
}
void FeedJournalDatabase::OnGetEntryForLoadJournal(
JournalLoadCallback callback,
bool success,
......@@ -95,15 +200,37 @@ void FeedJournalDatabase::OnGetEntryForLoadJournal(
std::move(callback).Run(std::move(results));
}
void FeedJournalDatabase::OnDatabaseInitialized(bool success) {
DCHECK_EQ(database_status_, UNINITIALIZED);
void FeedJournalDatabase::OnGetEntryForCommitJournalMutation(
std::unique_ptr<JournalMutation> journal_mutation,
ConfirmationCallback callback,
bool success,
std::unique_ptr<JournalStorageProto> journal) {
if (!success) {
DVLOG(1) << "FeedJournalDatabase load journal failed.";
std::move(callback).Run(success);
return;
}
if (success) {
database_status_ = INITIALIZED;
} else {
database_status_ = INIT_FAILURE;
DVLOG(1) << "FeedJournalDatabase init failed.";
PerformOperations(std::move(journal), std::move(journal_mutation),
std::move(callback));
}
void FeedJournalDatabase::OnOperationCommitted(ConfirmationCallback callback,
bool success) {
DVLOG_IF(1, !success) << "FeedJournalDatabase commit failed.";
std::move(callback).Run(success);
}
JournalStorageProto FeedJournalDatabase::CopyJouarnal(
const std::string& new_journal_name,
const JournalStorageProto& source_journal) {
JournalStorageProto new_journal;
new_journal.set_key(new_journal_name);
for (int i = 0; i < source_journal.journal_data_size(); ++i) {
new_journal.add_journal_data(source_journal.journal_data(i));
}
return new_journal;
}
} // namespace feed
......@@ -9,6 +9,7 @@
#include <string>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
......@@ -17,6 +18,8 @@
namespace feed {
class JournalMutation;
class JournalOperation;
class JournalStorageProto;
// FeedJournalDatabase is leveldb backend store for Feed's journal storage data.
......@@ -34,6 +37,13 @@ class FeedJournalDatabase {
using JournalLoadCallback =
base::OnceCallback<void(std::vector<std::string>)>;
// Returns whether the commit operation succeeded when calling for database
// operations, or return whether the entry exists when calling for checking
// the entry's existence.
using ConfirmationCallback = base::OnceCallback<void(bool)>;
using JournalMap = base::flat_map<std::string, JournalStorageProto>;
// Initializes the database with |database_folder|.
explicit FeedJournalDatabase(const base::FilePath& database_folder);
......@@ -54,13 +64,38 @@ class FeedJournalDatabase {
// Loads the journal data for the |key| and passes it to |callback|.
void LoadJournal(const std::string& key, JournalLoadCallback callback);
// Commits the operations in the |journal_mutation|. |callback| will be called
// when all the operations are committed. Or if any operation failed, database
// will stop process any operations and passed error to |callback|.
void CommitJournalMutation(std::unique_ptr<JournalMutation> journal_mutation,
ConfirmationCallback callback);
private:
void OnGetEntryForLoadJournal(JournalLoadCallback callback,
bool success,
std::unique_ptr<JournalStorageProto> journal);
// This method performs JournalOperation in the |journal_mutation|.
// If the first operation in |journal_mutation| is JOURNAL_DELETE, journal can
// be empty, otherwise we need to load |journal| from database and then pass
// to this method.
void PerformOperations(std::unique_ptr<JournalStorageProto> journal,
std::unique_ptr<JournalMutation> journal_mutation,
ConfirmationCallback callback);
void CommitOperations(std::unique_ptr<JournalStorageProto> journal,
JournalMap copy_to_journal,
ConfirmationCallback callback);
// Callback methods given to |storage_database_| for async responses.
void OnDatabaseInitialized(bool success);
void OnGetEntryForLoadJournal(JournalLoadCallback callback,
bool success,
std::unique_ptr<JournalStorageProto> journal);
void OnGetEntryForCommitJournalMutation(
std::unique_ptr<JournalMutation> journal_mutation,
ConfirmationCallback callback,
bool success,
std::unique_ptr<JournalStorageProto> journal);
void OnOperationCommitted(ConfirmationCallback callback, bool success);
JournalStorageProto CopyJouarnal(const std::string& new_journal_name,
const JournalStorageProto& source_journal);
// Status of the database initialization.
State database_status_;
......
......@@ -8,6 +8,7 @@
#include <utility>
#include "base/test/scoped_task_environment.h"
#include "components/feed/core/feed_journal_mutation.h"
#include "components/feed/core/proto/journal_storage.pb.h"
#include "components/leveldb_proto/testing/fake_db.h"
#include "testing/gmock/include/gmock/gmock.h"
......@@ -24,10 +25,12 @@ namespace {
const char kJournalKey1[] = "JournalKey1";
const char kJournalKey2[] = "JournalKey2";
const char kJournalKey3[] = "JournalKey3";
const char kJournalData1[] = "Journal Data1";
const char kJournalData2[] = "Journal Data2";
const char kJournalData3[] = "Journal Data3";
const char kJournalData4[] = "Journal Data4";
const char kJournalData5[] = "Journal Data5";
} // namespace
......@@ -71,6 +74,7 @@ class FeedJournalDatabaseTest : public testing::Test {
FeedJournalDatabase* db() { return feed_db_.get(); }
MOCK_METHOD1(OnJournalEntryReceived, void(std::vector<std::string>));
MOCK_METHOD1(OnStorageCommitted, void(bool));
private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
......@@ -135,4 +139,179 @@ TEST_F(FeedJournalDatabaseTest, LoadNonExistingJournalEntry) {
storage_db()->GetCallback(true);
}
TEST_F(FeedJournalDatabaseTest, AppendJournal) {
CreateDatabase(/*init_database=*/true);
// Save |kJournalKey1|.
auto journal_mutation = std::make_unique<JournalMutation>(kJournalKey1);
journal_mutation->AddAppendOperation(kJournalData1);
journal_mutation->AddAppendOperation(kJournalData2);
EXPECT_CALL(*this, OnStorageCommitted(true));
db()->CommitJournalMutation(
std::move(journal_mutation),
base::BindOnce(&FeedJournalDatabaseTest::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(&FeedJournalDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->GetCallback(true);
Mock::VerifyAndClearExpectations(this);
// Append more for |kJournalKey1|.
journal_mutation = std::make_unique<JournalMutation>(kJournalKey1);
journal_mutation->AddAppendOperation(kJournalData3);
journal_mutation->AddAppendOperation(kJournalData4);
journal_mutation->AddAppendOperation(kJournalData5);
EXPECT_CALL(*this, OnStorageCommitted(true));
db()->CommitJournalMutation(
std::move(journal_mutation),
base::BindOnce(&FeedJournalDatabaseTest::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(&FeedJournalDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->GetCallback(true);
}
TEST_F(FeedJournalDatabaseTest, CopyJournal) {
CreateDatabase(/*init_database=*/true);
// Save |kJournalKey1|.
InjectJournalStorageProto(kJournalKey1, {kJournalData1, kJournalData2});
// Copy |kJournalKey1| to |kJournalKey2|.
auto journal_mutation = std::make_unique<JournalMutation>(kJournalKey1);
journal_mutation->AddCopyOperation(kJournalKey2);
journal_mutation->AddAppendOperation(kJournalData3);
journal_mutation->AddAppendOperation(kJournalData4);
journal_mutation->AddCopyOperation(kJournalKey3);
EXPECT_CALL(*this, OnStorageCommitted(true));
db()->CommitJournalMutation(
std::move(journal_mutation),
base::BindOnce(&FeedJournalDatabaseTest::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(), 2U);
EXPECT_EQ(results[0], kJournalData1);
EXPECT_EQ(results[1], kJournalData2);
});
db()->LoadJournal(
kJournalKey2,
base::BindOnce(&FeedJournalDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->GetCallback(true);
Mock::VerifyAndClearExpectations(this);
// Check new journal is there.
EXPECT_CALL(*this, OnJournalEntryReceived(_))
.WillOnce([](std::vector<std::string> results) {
ASSERT_EQ(results.size(), 4U);
EXPECT_EQ(results[0], kJournalData1);
EXPECT_EQ(results[1], kJournalData2);
EXPECT_EQ(results[2], kJournalData3);
EXPECT_EQ(results[3], kJournalData4);
});
db()->LoadJournal(
kJournalKey3,
base::BindOnce(&FeedJournalDatabaseTest::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(), 4U);
EXPECT_EQ(results[0], kJournalData1);
EXPECT_EQ(results[1], kJournalData2);
EXPECT_EQ(results[2], kJournalData3);
EXPECT_EQ(results[3], kJournalData4);
});
db()->LoadJournal(
kJournalKey1,
base::BindOnce(&FeedJournalDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->GetCallback(true);
}
TEST_F(FeedJournalDatabaseTest, DeleteJournal) {
CreateDatabase(/*init_database=*/true);
// Store |kJournalKey1|, |kJournalKey2|.
InjectJournalStorageProto(kJournalKey1,
{kJournalData1, kJournalData2, kJournalData3});
InjectJournalStorageProto(kJournalKey2, {kJournalData4, kJournalData5});
// Delete |kJournalKey2|.
auto journal_mutation = std::make_unique<JournalMutation>(kJournalKey2);
journal_mutation->AddDeleteOperation();
EXPECT_CALL(*this, OnStorageCommitted(true));
db()->CommitJournalMutation(
std::move(journal_mutation),
base::BindOnce(&FeedJournalDatabaseTest::OnStorageCommitted,
base::Unretained(this)));
RunUntilIdle();
storage_db()->UpdateCallback(true);
// Make sure |kJournalKey2| got deleted.
EXPECT_CALL(*this, OnJournalEntryReceived(_))
.WillOnce([](std::vector<std::string> results) {
ASSERT_EQ(results.size(), 0U);
});
db()->LoadJournal(
kJournalKey2,
base::BindOnce(&FeedJournalDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->GetCallback(true);
Mock::VerifyAndClearExpectations(this);
// Make sure |kJournalKey1| 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(&FeedJournalDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->GetCallback(true);
}
} // namespace feed
......@@ -6,7 +6,7 @@
#include <utility>
#include "components/feed/core/feed_journal_operation.h"
#include "base/logging.h"
namespace feed {
......@@ -43,4 +43,9 @@ JournalOperation JournalMutation::TakeFristOperation() {
return operation;
}
JournalOperation::Type JournalMutation::FirstOperationType() {
DCHECK(!operations_list_.empty());
return operations_list_.front().type();
}
} // namespace feed
......@@ -9,11 +9,10 @@
#include <string>
#include "base/macros.h"
#include "components/feed/core/feed_journal_operation.h"
namespace feed {
class JournalOperation;
// Native counterpart of JournalMutation.java.
// To commit a set of JournalOperation into FeedJournalDatabase, first,
// JournalMutation need to be created, then use Add* methods to add operations
......@@ -37,6 +36,8 @@ class JournalMutation {
// return it to caller.
JournalOperation TakeFristOperation();
JournalOperation::Type FirstOperationType();
private:
const std::string journal_name_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment