Commit f57a1c98 authored by Gang Wu's avatar Gang Wu Committed by Commit Bot

[Feed] Remove old storage implementation

Remove old storage implementation for both Java and C++.

Bug: 828935
Change-Id: Ib6144e206b513272510763559337dc6aa16e06b6
Reviewed-on: https://chromium-review.googlesource.com/1185794Reviewed-by: default avatarFilip Gorski <fgorski@chromium.org>
Commit-Queue: Gang Wu <gangwu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585645}
parent 6988b464
// 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.
package org.chromium.chrome.browser.feed;
import org.chromium.base.Callback;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.chrome.browser.profiles.Profile;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Provides access to native implementations of content storage and journal storage.
*/
@JNINamespace("feed")
public class FeedStorageBridge {
private long mNativeFeedStorageBridge;
/**
* Creates a {@link FeedStorageBridge} for accessing native content and journal storage
* implementation for the current user, and initial native side bridge.
*
* @param profile {@link Profile} of the user we are rendering the Feed for.
*/
public FeedStorageBridge() {}
/**
* Inits native side bridge.
*
* @param profile {@link Profile} of the user we are rendering the Feed for.
*/
public void init(Profile profile) {
mNativeFeedStorageBridge = nativeInit(profile);
}
/** Cleans up native half of this bridge. */
public void destroy() {
assert mNativeFeedStorageBridge != 0;
nativeDestroy(mNativeFeedStorageBridge);
mNativeFeedStorageBridge = 0;
}
public void loadContent(List<String> keys, Callback<Map<String, byte[]>> callback) {
assert mNativeFeedStorageBridge != 0;
String[] keysArray = keys.toArray(new String[keys.size()]);
nativeLoadContent(mNativeFeedStorageBridge, keysArray, callback);
}
public void loadContentByPrefix(String prefix, Callback<Map<String, byte[]>> callback) {
assert mNativeFeedStorageBridge != 0;
nativeLoadContentByPrefix(mNativeFeedStorageBridge, prefix, callback);
}
public void loadAllContentKeys(Callback<List<String>> callback) {
assert mNativeFeedStorageBridge != 0;
nativeLoadAllContentKeys(mNativeFeedStorageBridge, callback);
}
public void saveContent(String[] keys, byte[][] data, Callback<Boolean> callback) {
assert mNativeFeedStorageBridge != 0;
nativeSaveContent(mNativeFeedStorageBridge, keys, data, callback);
}
public void deleteContent(List<String> keys, Callback<Boolean> callback) {
assert mNativeFeedStorageBridge != 0;
String[] keysArray = keys.toArray(new String[keys.size()]);
nativeDeleteContent(mNativeFeedStorageBridge, keysArray, callback);
}
public void deleteContentByPrefix(String prefix, Callback<Boolean> callback) {
assert mNativeFeedStorageBridge != 0;
nativeDeleteContentByPrefix(mNativeFeedStorageBridge, prefix, callback);
}
public void deleteAllContent(Callback<Boolean> callback) {
assert mNativeFeedStorageBridge != 0;
nativeDeleteAllContent(mNativeFeedStorageBridge, callback);
}
@CalledByNative
private static Object createKeyAndDataMap(String[] keys, byte[][] data) {
assert keys.length == data.length;
Map<String, byte[]> valueMap = new HashMap<>(keys.length);
for (int i = 0; i < keys.length && i < data.length; ++i) {
valueMap.put(keys[i], data[i]);
}
return valueMap;
}
@CalledByNative
private static List<String> createJavaList(String[] keys) {
return Arrays.asList(keys);
}
private native long nativeInit(Profile profile);
private native void nativeDestroy(long nativeFeedStorageBridge);
private native void nativeLoadContent(
long nativeFeedStorageBridge, String[] keys, Callback<Map<String, byte[]>> callback);
private native void nativeLoadContentByPrefix(
long nativeFeedStorageBridge, String prefix, Callback<Map<String, byte[]>> callback);
private native void nativeLoadAllContentKeys(
long nativeFeedStorageBridge, Callback<List<String>> callback);
private native void nativeSaveContent(
long nativeFeedStorageBridge, String[] keys, byte[][] data, Callback<Boolean> callback);
private native void nativeDeleteContent(
long nativeFeedStorageBridge, String[] keys, Callback<Boolean> callback);
private native void nativeDeleteContentByPrefix(
long nativeFeedStorageBridge, String prefix, Callback<Boolean> callback);
private native void nativeDeleteAllContent(
long nativeFeedStorageBridge, Callback<Boolean> callback);
}
...@@ -24,7 +24,6 @@ if (enable_feed_in_chrome) { ...@@ -24,7 +24,6 @@ if (enable_feed_in_chrome) {
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedRefreshTask.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedRefreshTask.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedScheduler.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedScheduler.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSchedulerBridge.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSchedulerBridge.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedStorageBridge.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/StreamLifecycleManager.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/StreamLifecycleManager.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/TestFeedScheduler.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/TestFeedScheduler.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/TestNetworkClient.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/TestNetworkClient.java",
......
...@@ -4421,8 +4421,6 @@ jumbo_split_static_library("browser") { ...@@ -4421,8 +4421,6 @@ jumbo_split_static_library("browser") {
"android/feed/feed_network_bridge.h", "android/feed/feed_network_bridge.h",
"android/feed/feed_scheduler_bridge.cc", "android/feed/feed_scheduler_bridge.cc",
"android/feed/feed_scheduler_bridge.h", "android/feed/feed_scheduler_bridge.h",
"android/feed/feed_storage_bridge.cc",
"android/feed/feed_storage_bridge.h",
] ]
deps += [ "//components/feed/core:feed_core" ] deps += [ "//components/feed/core:feed_core" ]
} }
...@@ -4694,7 +4692,6 @@ if (is_android) { ...@@ -4694,7 +4692,6 @@ if (is_android) {
"../android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedJournalBridge.java", "../android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedJournalBridge.java",
"../android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNetworkBridge.java", "../android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNetworkBridge.java",
"../android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSchedulerBridge.java", "../android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSchedulerBridge.java",
"../android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedStorageBridge.java",
] ]
} }
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include "components/feed/core/feed_journal_database.h" #include "components/feed/core/feed_journal_database.h"
#include "components/feed/core/feed_networking_host.h" #include "components/feed/core/feed_networking_host.h"
#include "components/feed/core/feed_scheduler_host.h" #include "components/feed/core/feed_scheduler_host.h"
#include "components/feed/core/feed_storage_database.h"
#include "components/image_fetcher/core/image_fetcher_impl.h" #include "components/image_fetcher/core/image_fetcher_impl.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/version_info/version_info.h" #include "components/version_info/version_info.h"
...@@ -90,16 +89,14 @@ KeyedService* FeedHostServiceFactory::BuildServiceInstanceFor( ...@@ -90,16 +89,14 @@ KeyedService* FeedHostServiceFactory::BuildServiceInstanceFor(
profile->GetPrefs(), g_browser_process->local_state(), profile->GetPrefs(), g_browser_process->local_state(),
base::DefaultClock::GetInstance()); base::DefaultClock::GetInstance());
auto storage_database = std::make_unique<FeedStorageDatabase>(feed_dir);
auto content_database = std::make_unique<FeedContentDatabase>(feed_dir); auto content_database = std::make_unique<FeedContentDatabase>(feed_dir);
auto journal_database = std::make_unique<FeedJournalDatabase>(feed_dir); auto journal_database = std::make_unique<FeedJournalDatabase>(feed_dir);
return new FeedHostService( return new FeedHostService(
std::move(image_manager), std::move(networking_host), std::move(image_manager), std::move(networking_host),
std::move(scheduler_host), std::move(storage_database), std::move(scheduler_host), std::move(content_database),
std::move(content_database), std::move(journal_database)); std::move(journal_database));
} }
content::BrowserContext* FeedHostServiceFactory::GetBrowserContextToUse( content::BrowserContext* FeedHostServiceFactory::GetBrowserContextToUse(
......
// 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 "chrome/browser/android/feed/feed_storage_bridge.h"
#include <jni.h>
#include <string>
#include <vector>
#include "base/android/callback_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/bind.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/android/feed/feed_host_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_android.h"
#include "components/feed/core/feed_host_service.h"
#include "components/feed/core/feed_storage_database.h"
#include "jni/FeedStorageBridge_jni.h"
#include "ui/gfx/android/java_bitmap.h"
#include "ui/gfx/image/image.h"
namespace feed {
using base::android::AppendJavaStringArrayToStringVector;
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
using base::android::JavaArrayOfByteArrayToStringVector;
using base::android::JavaIntArrayToIntVector;
using base::android::JavaRef;
using base::android::JavaParamRef;
using base::android::ScopedJavaGlobalRef;
using base::android::ScopedJavaLocalRef;
using base::android::ToJavaArrayOfByteArray;
using base::android::ToJavaArrayOfStrings;
static jlong JNI_FeedStorageBridge_Init(
JNIEnv* env,
const JavaParamRef<jobject>& j_this,
const JavaParamRef<jobject>& j_profile) {
Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
FeedHostService* host_service =
FeedHostServiceFactory::GetForBrowserContext(profile);
DCHECK(host_service);
FeedStorageDatabase* feed_storage_database =
host_service->GetStorageDatabase();
DCHECK(feed_storage_database);
FeedStorageBridge* native_storage_bridge =
new FeedStorageBridge(feed_storage_database);
return reinterpret_cast<intptr_t>(native_storage_bridge);
}
FeedStorageBridge::FeedStorageBridge(FeedStorageDatabase* feed_storage_database)
: feed_storage_database_(feed_storage_database), weak_ptr_factory_(this) {}
FeedStorageBridge::~FeedStorageBridge() = default;
void FeedStorageBridge::Destroy(JNIEnv* env, const JavaRef<jobject>& j_this) {
delete this;
}
void FeedStorageBridge::LoadContent(JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const JavaRef<jobjectArray>& j_keys,
const JavaRef<jobject>& j_callback) {
std::vector<std::string> keys;
AppendJavaStringArrayToStringVector(j_env, j_keys.obj(), &keys);
ScopedJavaGlobalRef<jobject> callback(j_callback);
feed_storage_database_->LoadContent(
keys, base::BindOnce(&FeedStorageBridge::OnLoadContentDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void FeedStorageBridge::LoadContentByPrefix(
JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const JavaRef<jstring>& j_prefix,
const JavaRef<jobject>& j_callback) {
std::string prefix = ConvertJavaStringToUTF8(j_env, j_prefix);
ScopedJavaGlobalRef<jobject> callback(j_callback);
feed_storage_database_->LoadContentByPrefix(
prefix, base::BindOnce(&FeedStorageBridge::OnLoadContentDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void FeedStorageBridge::LoadAllContentKeys(JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const JavaRef<jobject>& j_callback) {
ScopedJavaGlobalRef<jobject> callback(j_callback);
feed_storage_database_->LoadAllContentKeys(
base::BindOnce(&FeedStorageBridge::OnLoadAllContentKeysDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void FeedStorageBridge::SaveContent(JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const JavaRef<jobjectArray>& j_keys,
const JavaRef<jobjectArray>& j_data,
const JavaRef<jobject>& j_callback) {
std::vector<std::string> keys;
std::vector<std::string> data;
AppendJavaStringArrayToStringVector(j_env, j_keys.obj(), &keys);
JavaArrayOfByteArrayToStringVector(j_env, j_data.obj(), &data);
ScopedJavaGlobalRef<jobject> callback(j_callback);
DCHECK_EQ(keys.size(), data.size());
std::vector<FeedStorageDatabase::KeyAndData> pairs;
for (size_t i = 0; i < keys.size() && i < data.size(); ++i) {
pairs.emplace_back(keys[i], data[i]);
}
feed_storage_database_->SaveContent(
std::move(pairs),
base::BindOnce(&FeedStorageBridge::OnStorageCommitDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void FeedStorageBridge::DeleteContent(JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const JavaRef<jobjectArray>& j_keys,
const JavaRef<jobject>& j_callback) {
std::vector<std::string> keys;
AppendJavaStringArrayToStringVector(j_env, j_keys.obj(), &keys);
ScopedJavaGlobalRef<jobject> callback(j_callback);
feed_storage_database_->DeleteContent(
keys, base::BindOnce(&FeedStorageBridge::OnStorageCommitDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void FeedStorageBridge::DeleteContentByPrefix(
JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const JavaRef<jstring>& j_prefix,
const JavaRef<jobject>& j_callback) {
std::string prefix = ConvertJavaStringToUTF8(j_env, j_prefix);
ScopedJavaGlobalRef<jobject> callback(j_callback);
feed_storage_database_->DeleteContentByPrefix(
prefix, base::BindOnce(&FeedStorageBridge::OnStorageCommitDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void FeedStorageBridge::DeleteAllContent(JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const JavaRef<jobject>& j_callback) {
ScopedJavaGlobalRef<jobject> callback(j_callback);
feed_storage_database_->DeleteAllContent(
base::BindOnce(&FeedStorageBridge::OnStorageCommitDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void FeedStorageBridge::OnLoadContentDone(
ScopedJavaGlobalRef<jobject> callback,
std::vector<FeedStorageDatabase::KeyAndData> pairs) {
std::vector<std::string> keys;
std::vector<std::string> data;
for (auto pair : pairs) {
keys.push_back(std::move(pair.first));
data.push_back(std::move(pair.second));
}
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobjectArray> j_keys = ToJavaArrayOfStrings(env, keys);
ScopedJavaLocalRef<jobjectArray> j_data = ToJavaArrayOfByteArray(env, data);
// Ceate Java Map by JNI call.
ScopedJavaLocalRef<jobject> j_pairs =
Java_FeedStorageBridge_createKeyAndDataMap(env, j_keys, j_data);
RunObjectCallbackAndroid(callback, j_pairs);
}
void FeedStorageBridge::OnLoadAllContentKeysDone(
ScopedJavaGlobalRef<jobject> callback,
std::vector<std::string> keys) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobjectArray> j_keys = ToJavaArrayOfStrings(env, keys);
// Ceate Java List by JNI call.
ScopedJavaLocalRef<jobject> j_keys_list =
Java_FeedStorageBridge_createJavaList(env, j_keys);
RunObjectCallbackAndroid(callback, j_keys_list);
}
void FeedStorageBridge::OnStorageCommitDone(
ScopedJavaGlobalRef<jobject> callback,
bool success) {
RunBooleanCallbackAndroid(callback, success);
}
} // namespace feed
// 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.
#ifndef CHROME_BROWSER_ANDROID_FEED_FEED_STORAGE_BRIDGE_H_
#define CHROME_BROWSER_ANDROID_FEED_FEED_STORAGE_BRIDGE_H_
#include "base/android/scoped_java_ref.h"
#include "base/memory/weak_ptr.h"
#include "components/feed/core/feed_storage_database.h"
namespace feed {
class FeedStorageDatabase;
// Native counterpart of FeedStorageBridge.java. Holds non-owning pointers
// to native implementation, to which operations are delegated. Results are
// passed back by a single argument callback so
// base::android::RunBooleanCallbackAndroid() and
// base::android::RunObjectCallbackAndroid() can be used. This bridge is
// instantiated, owned, and destroyed from Java.
class FeedStorageBridge {
public:
explicit FeedStorageBridge(FeedStorageDatabase* feed_Storage_database);
~FeedStorageBridge();
void Destroy(JNIEnv* j_env, const base::android::JavaRef<jobject>& j_this);
void LoadContent(JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jobjectArray>& j_keys,
const base::android::JavaRef<jobject>& j_callback);
void LoadContentByPrefix(JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jstring>& j_prefix,
const base::android::JavaRef<jobject>& j_callback);
void LoadAllContentKeys(JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jobject>& j_callback);
void SaveContent(JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jobjectArray>& j_keys,
const base::android::JavaRef<jobjectArray>& j_data,
const base::android::JavaRef<jobject>& j_callback);
void DeleteContent(JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jobjectArray>& j_keys,
const base::android::JavaRef<jobject>& j_callback);
void DeleteContentByPrefix(JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jstring>& j_prefix,
const base::android::JavaRef<jobject>& j_callback);
void DeleteAllContent(JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jobject>& j_callback);
private:
void OnLoadContentDone(base::android::ScopedJavaGlobalRef<jobject> callback,
std::vector<FeedStorageDatabase::KeyAndData> pairs);
void OnLoadAllContentKeysDone(
base::android::ScopedJavaGlobalRef<jobject> callback,
std::vector<std::string> keys);
void OnStorageCommitDone(base::android::ScopedJavaGlobalRef<jobject> callback,
bool success);
FeedStorageDatabase* feed_storage_database_;
base::WeakPtrFactory<FeedStorageBridge> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(FeedStorageBridge);
};
} // namespace feed
#endif // CHROME_BROWSER_ANDROID_FEED_FEED_STORAGE_BRIDGE_H_
...@@ -30,8 +30,6 @@ source_set("feed_core") { ...@@ -30,8 +30,6 @@ source_set("feed_core") {
"feed_networking_host.h", "feed_networking_host.h",
"feed_scheduler_host.cc", "feed_scheduler_host.cc",
"feed_scheduler_host.h", "feed_scheduler_host.h",
"feed_storage_database.cc",
"feed_storage_database.h",
"pref_names.cc", "pref_names.cc",
"pref_names.h", "pref_names.h",
"refresh_throttler.cc", "refresh_throttler.cc",
...@@ -85,7 +83,6 @@ source_set("core_unit_tests") { ...@@ -85,7 +83,6 @@ source_set("core_unit_tests") {
"feed_journal_mutation_unittest.cc", "feed_journal_mutation_unittest.cc",
"feed_networking_host_unittest.cc", "feed_networking_host_unittest.cc",
"feed_scheduler_host_unittest.cc", "feed_scheduler_host_unittest.cc",
"feed_storage_database_unittest.cc",
"refresh_throttler_unittest.cc", "refresh_throttler_unittest.cc",
"user_classifier_unittest.cc", "user_classifier_unittest.cc",
] ]
......
...@@ -12,13 +12,11 @@ FeedHostService::FeedHostService( ...@@ -12,13 +12,11 @@ FeedHostService::FeedHostService(
std::unique_ptr<FeedImageManager> image_manager, std::unique_ptr<FeedImageManager> image_manager,
std::unique_ptr<FeedNetworkingHost> networking_host, std::unique_ptr<FeedNetworkingHost> networking_host,
std::unique_ptr<FeedSchedulerHost> scheduler_host, std::unique_ptr<FeedSchedulerHost> scheduler_host,
std::unique_ptr<FeedStorageDatabase> storage_database,
std::unique_ptr<FeedContentDatabase> content_database, std::unique_ptr<FeedContentDatabase> content_database,
std::unique_ptr<FeedJournalDatabase> journal_database) std::unique_ptr<FeedJournalDatabase> journal_database)
: image_manager_(std::move(image_manager)), : image_manager_(std::move(image_manager)),
networking_host_(std::move(networking_host)), networking_host_(std::move(networking_host)),
scheduler_host_(std::move(scheduler_host)), scheduler_host_(std::move(scheduler_host)),
storage_database_(std::move(storage_database)),
content_database_(std::move(content_database)), content_database_(std::move(content_database)),
journal_database_(std::move(journal_database)) {} journal_database_(std::move(journal_database)) {}
...@@ -36,10 +34,6 @@ FeedSchedulerHost* FeedHostService::GetSchedulerHost() { ...@@ -36,10 +34,6 @@ FeedSchedulerHost* FeedHostService::GetSchedulerHost() {
return scheduler_host_.get(); return scheduler_host_.get();
} }
FeedStorageDatabase* FeedHostService::GetStorageDatabase() {
return storage_database_.get();
}
FeedContentDatabase* FeedHostService::GetContentDatabase() { FeedContentDatabase* FeedHostService::GetContentDatabase() {
return content_database_.get(); return content_database_.get();
} }
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include "components/feed/core/feed_journal_database.h" #include "components/feed/core/feed_journal_database.h"
#include "components/feed/core/feed_networking_host.h" #include "components/feed/core/feed_networking_host.h"
#include "components/feed/core/feed_scheduler_host.h" #include "components/feed/core/feed_scheduler_host.h"
#include "components/feed/core/feed_storage_database.h"
#include "components/keyed_service/core/keyed_service.h" #include "components/keyed_service/core/keyed_service.h"
namespace feed { namespace feed {
...@@ -28,7 +27,6 @@ class FeedHostService : public KeyedService { ...@@ -28,7 +27,6 @@ class FeedHostService : public KeyedService {
FeedHostService(std::unique_ptr<FeedImageManager> image_manager, FeedHostService(std::unique_ptr<FeedImageManager> image_manager,
std::unique_ptr<FeedNetworkingHost> networking_host, std::unique_ptr<FeedNetworkingHost> networking_host,
std::unique_ptr<FeedSchedulerHost> scheduler_host, std::unique_ptr<FeedSchedulerHost> scheduler_host,
std::unique_ptr<FeedStorageDatabase> storage_database,
std::unique_ptr<FeedContentDatabase> content_database, std::unique_ptr<FeedContentDatabase> content_database,
std::unique_ptr<FeedJournalDatabase> journal_database); std::unique_ptr<FeedJournalDatabase> journal_database);
~FeedHostService() override; ~FeedHostService() override;
...@@ -36,7 +34,6 @@ class FeedHostService : public KeyedService { ...@@ -36,7 +34,6 @@ class FeedHostService : public KeyedService {
FeedImageManager* GetImageManager(); FeedImageManager* GetImageManager();
FeedNetworkingHost* GetNetworkingHost(); FeedNetworkingHost* GetNetworkingHost();
FeedSchedulerHost* GetSchedulerHost(); FeedSchedulerHost* GetSchedulerHost();
FeedStorageDatabase* GetStorageDatabase();
FeedContentDatabase* GetContentDatabase(); FeedContentDatabase* GetContentDatabase();
FeedJournalDatabase* GetJournalDatabase(); FeedJournalDatabase* GetJournalDatabase();
...@@ -44,7 +41,6 @@ class FeedHostService : public KeyedService { ...@@ -44,7 +41,6 @@ class FeedHostService : public KeyedService {
std::unique_ptr<FeedImageManager> image_manager_; std::unique_ptr<FeedImageManager> image_manager_;
std::unique_ptr<FeedNetworkingHost> networking_host_; std::unique_ptr<FeedNetworkingHost> networking_host_;
std::unique_ptr<FeedSchedulerHost> scheduler_host_; std::unique_ptr<FeedSchedulerHost> scheduler_host_;
std::unique_ptr<FeedStorageDatabase> storage_database_;
std::unique_ptr<FeedContentDatabase> content_database_; std::unique_ptr<FeedContentDatabase> content_database_;
std::unique_ptr<FeedJournalDatabase> journal_database_; std::unique_ptr<FeedJournalDatabase> journal_database_;
......
// 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 <unordered_set>
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/strings/string_util.h"
#include "base/sys_info.h"
#include "base/task/post_task.h"
#include "components/feed/core/proto/feed_storage.pb.h"
#include "components/leveldb_proto/proto_database_impl.h"
namespace feed {
namespace {
using StorageEntryVector =
leveldb_proto::ProtoDatabase<FeedStorageProto>::KeyEntryVector;
// Statistics are logged to UMA with this string as part of histogram name. They
// can all be found under LevelDB.*.FeedStorageDatabase. Changing this needs to
// synchronize with histograms.xml, AND will also become incompatible with older
// browsers still reporting the previous values.
const char kStorageDatabaseUMAClientName[] = "FeedStorageDatabase";
const char kStorageDatabaseFolder[] = "storage";
const size_t kDatabaseWriteBufferSizeBytes = 512 * 1024;
const size_t kDatabaseWriteBufferSizeBytesForLowEndDevice = 128 * 1024;
// Key prefixes for content's storage key and journal's storage key. Because we
// put both content data and journal data into one storage, we need to add
// prefixes to their keys to distinguish between content keys and journal keys.
const char kContentStoragePrefix[] = "cs-";
const char kJournalStoragePrefix[] = "js-";
// Formats content key to storage key by adding a prefix.
std::string FormatContentKeyToStorageKey(const std::string& content_key) {
return kContentStoragePrefix + content_key;
}
// Formats journal key to storage key by adding a prefix.
std::string FormatJournalKeyToStorageKey(const std::string& journal_key) {
return kJournalStoragePrefix + journal_key;
}
// Check if the |storage_key| is with |prefix|.
bool IsKeywithPrefix(const std::string& storage_key, const char prefix[]) {
return base::StartsWith(storage_key, prefix, base::CompareCase::SENSITIVE);
}
// Check if the |storage_key| is for content data.
bool IsValidContentKey(const std::string& storage_key) {
return IsKeywithPrefix(storage_key, kContentStoragePrefix);
}
// Check if the |storage_key| is for journal data.
bool IsValidJournalKey(const std::string& storage_key) {
return IsKeywithPrefix(storage_key, kJournalStoragePrefix);
}
// Help function |ParseContentKey| and |ParseJournalKey| to parse storage key by
// remove |prefix| from |storage_key|.
std::string ParseKeyHelper(const std::string& storage_key,
const char prefix[]) {
if (!IsKeywithPrefix(storage_key, prefix)) {
return std::string();
}
return storage_key.substr(strlen(prefix));
}
// Parse content key from storage key. Return an empty string if |storage_key|
// is not recognized as content key. ex. journal's storage key.
std::string ParseContentKey(const std::string& storage_key) {
return ParseKeyHelper(storage_key, kContentStoragePrefix);
}
// Parse journal key from storage key. Return an empty string if |storage_key|
// is not recognized as journal key. ex. content's storage key.
std::string ParseJournalKey(const std::string& storage_key) {
return ParseKeyHelper(storage_key, kJournalStoragePrefix);
}
bool DatabaseKeyFilter(const std::unordered_set<std::string>& key_set,
const std::string& key) {
return key_set.find(key) != key_set.end();
}
bool DatabasePrefixFilter(const std::string& key_prefix,
const std::string& key) {
return base::StartsWith(key, key_prefix, base::CompareCase::SENSITIVE);
}
} // namespace
FeedStorageDatabase::FeedStorageDatabase(const base::FilePath& database_folder)
: FeedStorageDatabase(
database_folder,
std::make_unique<leveldb_proto::ProtoDatabaseImpl<FeedStorageProto>>(
base::CreateSequencedTaskRunnerWithTraits(
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}))) {}
FeedStorageDatabase::FeedStorageDatabase(
const base::FilePath& database_folder,
std::unique_ptr<leveldb_proto::ProtoDatabase<FeedStorageProto>>
storage_database)
: database_status_(UNINITIALIZED),
storage_database_(std::move(storage_database)),
weak_ptr_factory_(this) {
leveldb_env::Options options = leveldb_proto::CreateSimpleOptions();
if (base::SysInfo::IsLowEndDevice()) {
options.write_buffer_size = kDatabaseWriteBufferSizeBytesForLowEndDevice;
} else {
options.write_buffer_size = kDatabaseWriteBufferSizeBytes;
}
base::FilePath storage_folder =
database_folder.AppendASCII(kStorageDatabaseFolder);
storage_database_->Init(
kStorageDatabaseUMAClientName, storage_folder, options,
base::BindOnce(&FeedStorageDatabase::OnDatabaseInitialized,
weak_ptr_factory_.GetWeakPtr()));
}
FeedStorageDatabase::~FeedStorageDatabase() = default;
bool FeedStorageDatabase::IsInitialized() const {
return INITIALIZED == database_status_;
}
void FeedStorageDatabase::LoadContent(const std::vector<std::string>& keys,
ContentLoadCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::unordered_set<std::string> key_set;
for (const auto& key : keys) {
key_set.insert(FormatContentKeyToStorageKey(key));
}
storage_database_->LoadEntriesWithFilter(
base::BindRepeating(&DatabaseKeyFilter, std::move(key_set)),
base::BindOnce(&FeedStorageDatabase::OnLoadEntriesForLoadContent,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedStorageDatabase::LoadContentByPrefix(const std::string& prefix,
ContentLoadCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::string key_prefix = FormatContentKeyToStorageKey(prefix);
storage_database_->LoadEntriesWithFilter(
base::BindRepeating(&DatabasePrefixFilter, std::move(key_prefix)),
base::BindOnce(&FeedStorageDatabase::OnLoadEntriesForLoadContent,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedStorageDatabase::LoadAllContentKeys(ContentKeyCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
storage_database_->LoadKeys(
base::BindOnce(&FeedStorageDatabase::OnLoadKeysForLoadAllContentKeys,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedStorageDatabase::SaveContent(std::vector<KeyAndData> pairs,
ConfirmationCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto contents_to_save = std::make_unique<StorageEntryVector>();
for (auto entry : pairs) {
FeedStorageProto proto;
proto.set_key(std::move(entry.first));
proto.set_content_data(std::move(entry.second));
contents_to_save->emplace_back(FormatContentKeyToStorageKey(proto.key()),
std::move(proto));
}
storage_database_->UpdateEntries(
std::move(contents_to_save), std::make_unique<std::vector<std::string>>(),
base::BindOnce(&FeedStorageDatabase::OnStorageCommitted,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedStorageDatabase::DeleteContent(
const std::vector<std::string>& keys_to_delete,
ConfirmationCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto content_to_delete = std::make_unique<std::vector<std::string>>();
for (const auto& key : keys_to_delete) {
content_to_delete->emplace_back(FormatContentKeyToStorageKey(key));
}
storage_database_->UpdateEntries(
std::make_unique<StorageEntryVector>(), std::move(content_to_delete),
base::BindOnce(&FeedStorageDatabase::OnStorageCommitted,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedStorageDatabase::DeleteContentByPrefix(
const std::string& prefix_to_delete,
ConfirmationCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::string key_prefix = FormatContentKeyToStorageKey(prefix_to_delete);
storage_database_->UpdateEntriesWithRemoveFilter(
std::make_unique<StorageEntryVector>(),
base::BindRepeating(&DatabasePrefixFilter, std::move(key_prefix)),
base::BindOnce(&FeedStorageDatabase::OnStorageCommitted,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedStorageDatabase::DeleteAllContent(ConfirmationCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::string key_prefix = FormatContentKeyToStorageKey(std::string());
storage_database_->UpdateEntriesWithRemoveFilter(
std::make_unique<StorageEntryVector>(),
base::BindRepeating(&DatabasePrefixFilter, std::move(key_prefix)),
base::BindOnce(&FeedStorageDatabase::OnStorageCommitted,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedStorageDatabase::LoadJournal(const std::string& key,
JournalLoadCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
storage_database_->GetEntry(
FormatJournalKeyToStorageKey(key),
base::BindOnce(&FeedStorageDatabase::OnGetEntryForLoadJournal,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedStorageDatabase::DoesJournalExist(const std::string& key,
ConfirmationCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
storage_database_->GetEntry(
FormatJournalKeyToStorageKey(key),
base::BindOnce(&FeedStorageDatabase::OnGetEntryForDoesJournalExist,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedStorageDatabase::LoadAllJournalKeys(JournalLoadCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
storage_database_->LoadKeys(
base::BindOnce(&FeedStorageDatabase::OnLoadKeysForLoadAllJournalKeys,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedStorageDatabase::AppendToJournal(const std::string& key,
std::vector<std::string> entries,
ConfirmationCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
storage_database_->GetEntry(
FormatJournalKeyToStorageKey(key),
base::BindOnce(&FeedStorageDatabase::OnGetEntryAppendToJournal,
weak_ptr_factory_.GetWeakPtr(), std::move(callback), key,
std::move(entries)));
}
void FeedStorageDatabase::CopyJournal(const std::string& from_key,
const std::string& to_key,
ConfirmationCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
storage_database_->GetEntry(
FormatJournalKeyToStorageKey(from_key),
base::BindOnce(&FeedStorageDatabase::OnGetEntryForCopyJournal,
weak_ptr_factory_.GetWeakPtr(), std::move(callback),
to_key));
}
void FeedStorageDatabase::DeleteJournal(const std::string& key,
ConfirmationCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto journals_to_delete = std::make_unique<std::vector<std::string>>();
journals_to_delete->push_back(FormatJournalKeyToStorageKey(key));
storage_database_->UpdateEntries(
std::make_unique<StorageEntryVector>(), std::move(journals_to_delete),
base::BindOnce(&FeedStorageDatabase::OnStorageCommitted,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedStorageDatabase::DeleteAllJournals(ConfirmationCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::string key_prefix = FormatJournalKeyToStorageKey(std::string());
storage_database_->UpdateEntriesWithRemoveFilter(
std::make_unique<StorageEntryVector>(),
base::BindRepeating(&DatabasePrefixFilter, std::move(key_prefix)),
base::BindOnce(&FeedStorageDatabase::OnStorageCommitted,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedStorageDatabase::OnDatabaseInitialized(bool success) {
DCHECK_EQ(database_status_, UNINITIALIZED);
if (success) {
database_status_ = INITIALIZED;
} else {
database_status_ = INIT_FAILURE;
DVLOG(1) << "FeedStorageDatabase init failed.";
}
}
void FeedStorageDatabase::OnLoadEntriesForLoadContent(
ContentLoadCallback callback,
bool success,
std::unique_ptr<std::vector<FeedStorageProto>> content) {
std::vector<KeyAndData> results;
if (!success || !content) {
DVLOG_IF(1, !success) << "FeedStorageDatabase load content failed.";
std::move(callback).Run(std::move(results));
return;
}
for (const auto& proto : *content) {
DCHECK(proto.has_key());
DCHECK(proto.has_content_data());
results.emplace_back(proto.key(), proto.content_data());
}
std::move(callback).Run(std::move(results));
}
void FeedStorageDatabase::OnLoadKeysForLoadAllContentKeys(
ContentKeyCallback callback,
bool success,
std::unique_ptr<std::vector<std::string>> keys) {
std::vector<std::string> results;
if (!success || !keys) {
DVLOG_IF(1, !success) << "FeedStorageDatabase load content keys failed.";
std::move(callback).Run(std::move(results));
return;
}
// Filter out journal keys, only keep content keys.
for (const std::string& key : *keys) {
if (IsValidContentKey(key))
results.emplace_back(ParseContentKey(key));
}
std::move(callback).Run(std::move(results));
}
void FeedStorageDatabase::OnGetEntryForLoadJournal(
JournalLoadCallback callback,
bool success,
std::unique_ptr<FeedStorageProto> journal) {
std::vector<std::string> results;
if (!success || !journal) {
DVLOG_IF(1, !success) << "FeedStorageDatabase load journal failed.";
std::move(callback).Run(std::move(results));
return;
}
for (int i = 0; i < journal->journal_data_size(); ++i) {
results.emplace_back(journal->journal_data(i));
}
std::move(callback).Run(std::move(results));
}
void FeedStorageDatabase::OnGetEntryForDoesJournalExist(
ConfirmationCallback callback,
bool success,
std::unique_ptr<FeedStorageProto> journal) {
DVLOG_IF(1, !success) << "FeedStorageDatabase load journal failed.";
std::move(callback).Run(journal != nullptr);
}
void FeedStorageDatabase::OnGetEntryAppendToJournal(
ConfirmationCallback callback,
const std::string& key,
std::vector<std::string> entries,
bool success,
std::unique_ptr<FeedStorageProto> journal) {
if (!success) {
DVLOG(1) << "FeedStorageDatabase load journal failed.";
std::move(callback).Run(success);
return;
}
if (journal == nullptr) {
// The journal does not exist, create a new one.
journal = std::make_unique<FeedStorageProto>();
journal->set_key(key);
}
DCHECK_EQ(journal->key(), key);
for (const std::string& entry : entries) {
journal->add_journal_data(entry);
}
auto journals_to_save = std::make_unique<StorageEntryVector>();
journals_to_save->emplace_back(FormatJournalKeyToStorageKey(key),
std::move(*journal));
storage_database_->UpdateEntries(
std::move(journals_to_save), std::make_unique<std::vector<std::string>>(),
base::BindOnce(&FeedStorageDatabase::OnStorageCommitted,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedStorageDatabase::OnGetEntryForCopyJournal(
ConfirmationCallback callback,
const std::string& to_key,
bool success,
std::unique_ptr<FeedStorageProto> journal) {
if (!success || !journal) {
DVLOG_IF(1, !success) << "FeedStorageDatabase load journal failed.";
std::move(callback).Run(success);
return;
}
journal->set_key(to_key);
auto journal_to_save = std::make_unique<StorageEntryVector>();
journal_to_save->emplace_back(FormatJournalKeyToStorageKey(to_key),
std::move(*journal));
storage_database_->UpdateEntries(
std::move(journal_to_save), std::make_unique<std::vector<std::string>>(),
base::BindOnce(&FeedStorageDatabase::OnStorageCommitted,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedStorageDatabase::OnLoadKeysForLoadAllJournalKeys(
JournalLoadCallback callback,
bool success,
std::unique_ptr<std::vector<std::string>> keys) {
std::vector<std::string> results;
if (!success || !keys) {
DVLOG_IF(1, !success) << "FeedStorageDatabase load journal keys failed.";
std::move(callback).Run(std::move(results));
return;
}
// Filter out content keys, only keep journal keys.
for (const std::string& key : *keys) {
if (IsValidJournalKey(key))
results.emplace_back(ParseJournalKey(key));
}
std::move(callback).Run(std::move(results));
}
void FeedStorageDatabase::OnStorageCommitted(ConfirmationCallback callback,
bool success) {
DVLOG_IF(1, !success) << "FeedStorageDatabase committed failed.";
std::move(callback).Run(success);
}
} // namespace feed
// 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.
#ifndef COMPONENTS_FEED_CORE_FEED_STORAGE_DATABASE_H_
#define COMPONENTS_FEED_CORE_FEED_STORAGE_DATABASE_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
#include "components/leveldb_proto/proto_database.h"
namespace feed {
class FeedStorageProto;
// FeedStorageDatabase is leveldb backed store for feed's content storage data
// and jounal storage data.
class FeedStorageDatabase {
public:
enum State {
UNINITIALIZED,
INITIALIZED,
INIT_FAILURE,
};
using KeyAndData = std::pair<std::string, std::string>;
// Returns the storage data as a vector of key-value pairs when calling
// loading data.
using ContentLoadCallback = base::OnceCallback<void(std::vector<KeyAndData>)>;
// Returns the content keys as a vector when calling loading all content keys.
using ContentKeyCallback = base::OnceCallback<void(std::vector<std::string>)>;
// Returns the journal data as a vector of strings when calling loading data
// or keys.
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)>;
// Initializes the database with |database_folder|.
explicit FeedStorageDatabase(const base::FilePath& database_folder);
// Initializes the database with |database_folder|. Creates storage using the
// given |storage_database| for local storage. Useful for testing.
FeedStorageDatabase(
const base::FilePath& database_folder,
std::unique_ptr<leveldb_proto::ProtoDatabase<FeedStorageProto>>
storage_database);
~FeedStorageDatabase();
// Returns true if initialization has finished successfully, else false.
// While this is false, initialization may already started, or initialization
// failed.
bool IsInitialized() const;
// Loads the content data for the |keys| and passes them to |callback|.
void LoadContent(const std::vector<std::string>& keys,
ContentLoadCallback callback);
// Loads the content data whose key matches |prefix|, and passes them to
// |callback|.
void LoadContentByPrefix(const std::string& prefix,
ContentLoadCallback callback);
// Loads all content keys in the storage, and passes them to |callback|.
void LoadAllContentKeys(ContentKeyCallback callback);
// Inserts or updates the content data |pairs|, |callback| will be called when
// the data are saved or if there is an error. The fields in |pairs| will be
// std::move.
void SaveContent(std::vector<KeyAndData> pairs,
ConfirmationCallback callback);
// Deletes the content data for |keys_to_delete|, |callback| will be called
// when the data are deleted or if there is an error.
void DeleteContent(const std::vector<std::string>& keys_to_delete,
ConfirmationCallback callback);
// Deletes the content data whose key matches |prefix_to_delete|, |callback|
// will be called when the content are deleted or if there is an error.
void DeleteContentByPrefix(const std::string& prefix_to_delete,
ConfirmationCallback callback);
// Delete all content, |callback| will be called when all content is deleted
// or if there is an error.
void DeleteAllContent(ConfirmationCallback callback);
// Loads the journal data for the |key| and passes it to |callback|.
void LoadJournal(const std::string& key, JournalLoadCallback callback);
// Checks if the journal for the |key| exists, and return the result to
// |callback|.
void DoesJournalExist(const std::string& key, ConfirmationCallback callback);
// Loads all journal keys in the storage, and passes them to |callback|.
void LoadAllJournalKeys(JournalLoadCallback callback);
// Appends |entries| to a journal whose key is |key|, if there the journal do
// not exist, create one. |callback| will be called when the data are saved or
// if there is an error.
void AppendToJournal(const std::string& key,
std::vector<std::string> entries,
ConfirmationCallback callback);
// Creates a new journal with name |to_key|, and copys all data from the
// journal with |from_key| to it. |callback| will be called when the data are
// saved or if there is an error.
void CopyJournal(const std::string& from_key,
const std::string& to_key,
ConfirmationCallback callback);
// Deletes the journal with |key|, |callback| will be called when the journal
// is deleted or if there is an error.
void DeleteJournal(const std::string& key, ConfirmationCallback callback);
// Delete all journals, |callback| will be called when all journals are
// deleted or if there is an error.
void DeleteAllJournals(ConfirmationCallback callback);
private:
// Callback methods given to |storage_database_| for async responses.
void OnDatabaseInitialized(bool success);
void OnLoadEntriesForLoadContent(
ContentLoadCallback callback,
bool success,
std::unique_ptr<std::vector<FeedStorageProto>> content);
void OnLoadKeysForLoadAllContentKeys(
ContentKeyCallback callback,
bool success,
std::unique_ptr<std::vector<std::string>> keys);
void OnGetEntryForLoadJournal(JournalLoadCallback callback,
bool success,
std::unique_ptr<FeedStorageProto> journal);
void OnGetEntryForDoesJournalExist(ConfirmationCallback callback,
bool success,
std::unique_ptr<FeedStorageProto> journal);
void OnGetEntryAppendToJournal(ConfirmationCallback callback,
const std::string& key,
std::vector<std::string> entries,
bool success,
std::unique_ptr<FeedStorageProto> journal);
void OnGetEntryForCopyJournal(ConfirmationCallback callback,
const std::string& to_key,
bool success,
std::unique_ptr<FeedStorageProto> journal);
void OnLoadKeysForLoadAllJournalKeys(
JournalLoadCallback callback,
bool success,
std::unique_ptr<std::vector<std::string>> keys);
void OnStorageCommitted(ConfirmationCallback callback, bool success);
State database_status_;
std::unique_ptr<leveldb_proto::ProtoDatabase<FeedStorageProto>>
storage_database_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<FeedStorageDatabase> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(FeedStorageDatabase);
};
} // namespace feed
#endif // COMPONENTS_FEED_CORE_FEED_STORAGE_DATABASE_H_
// 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(JournalExist, void(bool));
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, OnJournalEntryReceived(_))
.WillOnce([](std::vector<std::string> results) {
ASSERT_EQ(results.size(), 3U);
});
db()->LoadAllJournalKeys(
base::BindOnce(&FeedStorageDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->LoadKeysCallback(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, DoesJournalExist) {
CreateDatabase(/*init_database=*/true);
// Store |kJournalKey1|.
InjectJournalStorageProto(kJournalKey1,
{kJournalData1, kJournalData2, kJournalData3});
// Check if |kJournalKey1| exists.
EXPECT_CALL(*this, JournalExist(true));
db()->DoesJournalExist(kJournalKey1,
base::BindOnce(&FeedStorageDatabaseTest::JournalExist,
base::Unretained(this)));
storage_db()->GetCallback(true);
Mock::VerifyAndClearExpectations(this);
// Check if |kJournalKey2| exists.
EXPECT_CALL(*this, JournalExist(false));
db()->DoesJournalExist(kJournalKey2,
base::BindOnce(&FeedStorageDatabaseTest::JournalExist,
base::Unretained(this)));
storage_db()->GetCallback(true);
}
TEST_F(FeedStorageDatabaseTest, LoadAllJournalKeys) {
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, OnJournalEntryReceived(_))
.WillOnce([](std::vector<std::string> results) {
ASSERT_EQ(results.size(), 3U);
EXPECT_EQ(results[0], kJournalKey1);
EXPECT_EQ(results[1], kJournalKey2);
EXPECT_EQ(results[2], kJournalKey3);
});
db()->LoadAllJournalKeys(
base::BindOnce(&FeedStorageDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->LoadKeysCallback(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, OnJournalEntryReceived(_))
.WillOnce([](std::vector<std::string> results) {
ASSERT_EQ(results.size(), 2U);
EXPECT_EQ(results[0], kJournalKey1);
EXPECT_EQ(results[1], kJournalKey3);
});
db()->LoadAllJournalKeys(
base::BindOnce(&FeedStorageDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->LoadKeysCallback(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, OnJournalEntryReceived(_))
.WillOnce([](std::vector<std::string> results) {
ASSERT_EQ(results.size(), 0U);
});
db()->LoadAllJournalKeys(
base::BindOnce(&FeedStorageDatabaseTest::OnJournalEntryReceived,
base::Unretained(this)));
storage_db()->LoadKeysCallback(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
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