Commit 02c703e7 authored by Gang Wu's avatar Gang Wu Committed by Commit Bot

[Feed] Implement error handling in content storage

Implement error handling in content storage, and change callback in java
to lambda.

Bug: 884230

Change-Id: I0dd9999dc221e7fb4d030d2b8f56d16482b04985
Reviewed-on: https://chromium-review.googlesource.com/1226079Reviewed-by: default avatarFilip Gorski <fgorski@chromium.org>
Commit-Queue: Gang Wu <gangwu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#591503}
parent ac2672cc
...@@ -49,20 +49,24 @@ public class FeedContentBridge { ...@@ -49,20 +49,24 @@ public class FeedContentBridge {
mNativeFeedContentBridge = 0; mNativeFeedContentBridge = 0;
} }
public void loadContent(List<String> keys, Callback<Map<String, byte[]>> callback) { public void loadContent(List<String> keys, Callback<Map<String, byte[]>> successCallback,
Callback<Map<String, byte[]>> failureCallback) {
assert mNativeFeedContentBridge != 0; assert mNativeFeedContentBridge != 0;
String[] keysArray = keys.toArray(new String[keys.size()]); String[] keysArray = keys.toArray(new String[keys.size()]);
nativeLoadContent(mNativeFeedContentBridge, keysArray, callback); nativeLoadContent(mNativeFeedContentBridge, keysArray, successCallback, failureCallback);
} }
public void loadContentByPrefix(String prefix, Callback<Map<String, byte[]>> callback) { public void loadContentByPrefix(String prefix, Callback<Map<String, byte[]>> successCallback,
Callback<Map<String, byte[]>> failureCallback) {
assert mNativeFeedContentBridge != 0; assert mNativeFeedContentBridge != 0;
nativeLoadContentByPrefix(mNativeFeedContentBridge, prefix, callback); nativeLoadContentByPrefix(
mNativeFeedContentBridge, prefix, successCallback, failureCallback);
} }
public void loadAllContentKeys(Callback<String[]> callback) { public void loadAllContentKeys(
Callback<String[]> successCallback, Callback<String[]> failureCallback) {
assert mNativeFeedContentBridge != 0; assert mNativeFeedContentBridge != 0;
nativeLoadAllContentKeys(mNativeFeedContentBridge, callback); nativeLoadAllContentKeys(mNativeFeedContentBridge, successCallback, failureCallback);
} }
public void commitContentMutation(ContentMutation contentMutation, Callback<Boolean> callback) { public void commitContentMutation(ContentMutation contentMutation, Callback<Boolean> callback) {
...@@ -111,12 +115,14 @@ public class FeedContentBridge { ...@@ -111,12 +115,14 @@ public class FeedContentBridge {
private native long nativeInit(Profile profile); private native long nativeInit(Profile profile);
private native void nativeDestroy(long nativeFeedContentBridge); private native void nativeDestroy(long nativeFeedContentBridge);
private native void nativeLoadContent( private native void nativeLoadContent(long nativeFeedContentBridge, String[] keys,
long nativeFeedContentBridge, String[] keys, Callback<Map<String, byte[]>> callback); Callback<Map<String, byte[]>> successCallback,
private native void nativeLoadContentByPrefix( Callback<Map<String, byte[]>> failureCallback);
long nativeFeedContentBridge, String prefix, Callback<Map<String, byte[]>> callback); private native void nativeLoadContentByPrefix(long nativeFeedContentBridge, String prefix,
private native void nativeLoadAllContentKeys( Callback<Map<String, byte[]>> successCallback,
long nativeFeedContentBridge, Callback<String[]> callback); Callback<Map<String, byte[]>> failureCallback);
private native void nativeLoadAllContentKeys(long nativeFeedContentBridge,
Callback<String[]> successCallback, Callback<String[]> failureCallback);
private native void nativeCommitContentMutation( private native void nativeCommitContentMutation(
long nativeFeedContentBridge, Callback<Boolean> callback); long nativeFeedContentBridge, Callback<Boolean> callback);
private native void nativeCreateContentMutation(long nativeFeedContentBridge); private native void nativeCreateContentMutation(long nativeFeedContentBridge);
......
...@@ -10,7 +10,8 @@ import com.google.android.libraries.feed.host.storage.CommitResult; ...@@ -10,7 +10,8 @@ import com.google.android.libraries.feed.host.storage.CommitResult;
import com.google.android.libraries.feed.host.storage.ContentMutation; import com.google.android.libraries.feed.host.storage.ContentMutation;
import com.google.android.libraries.feed.host.storage.ContentStorage; import com.google.android.libraries.feed.host.storage.ContentStorage;
import org.chromium.base.Callback; import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.profiles.Profile;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
...@@ -22,56 +23,22 @@ import java.util.Map; ...@@ -22,56 +23,22 @@ import java.util.Map;
public class FeedContentStorage implements ContentStorage { public class FeedContentStorage implements ContentStorage {
private FeedContentBridge mFeedContentBridge; private FeedContentBridge mFeedContentBridge;
private static class StorageCallback<T> implements Callback<T> { /**
private final Consumer<Result<T>> mConsumer; * Creates a {@link FeedContentStorage} for storing content for the current user.
*
public StorageCallback(Consumer<Result<T>> consumer) { * @param profile {@link Profile} of the user we are rendering the Feed for.
mConsumer = consumer; */
} public FeedContentStorage(Profile profile) {
mFeedContentBridge = new FeedContentBridge();
@Override mFeedContentBridge.init(profile);
public void onResult(T data) {
// TODO(gangwu): Need to handle failure case.
mConsumer.accept(Result.success(data));
}
}
private static class GetAllKeysCallback implements Callback<String[]> {
private final Consumer < Result < List<String>>> mConsumer;
public GetAllKeysCallback(Consumer < Result < List<String>>> consumer) {
mConsumer = consumer;
}
@Override
public void onResult(String[] keys) {
// TODO(gangwu): Need to handle failure case.
mConsumer.accept(Result.success(Arrays.asList(keys)));
}
}
private static class CommitCallback implements Callback<Boolean> {
private final Consumer<CommitResult> mConsumer;
CommitCallback(Consumer<CommitResult> consumer) {
mConsumer = consumer;
}
@Override
public void onResult(Boolean result) {
if (result) {
mConsumer.accept(CommitResult.SUCCESS);
} else {
mConsumer.accept(CommitResult.FAILURE);
}
}
} }
/** /**
* Creates a {@link FeedContentStorage} for storing content for the current user. * Creates a {@link FeedContentStorage} for testing.
* *
* @param bridge {@link FeedContentBridge} implementation can handle content storage request. * @param bridge {@link FeedContentBridge} implementation can handle content storage request.
*/ */
@VisibleForTesting
public FeedContentStorage(FeedContentBridge bridge) { public FeedContentStorage(FeedContentBridge bridge) {
mFeedContentBridge = bridge; mFeedContentBridge = bridge;
} }
...@@ -86,25 +53,35 @@ public class FeedContentStorage implements ContentStorage { ...@@ -86,25 +53,35 @@ public class FeedContentStorage implements ContentStorage {
@Override @Override
public void get(List<String> keys, Consumer < Result < Map<String, byte[]>>> consumer) { public void get(List<String> keys, Consumer < Result < Map<String, byte[]>>> consumer) {
assert mFeedContentBridge != null; assert mFeedContentBridge != null;
mFeedContentBridge.loadContent(keys, new StorageCallback<Map<String, byte[]>>(consumer)); mFeedContentBridge.loadContent(keys,
(Map<String, byte[]> data)
-> { consumer.accept(Result.success(data)); },
(Map<String, byte[]> data) -> { consumer.accept(Result.failure()); });
} }
@Override @Override
public void getAll(String prefix, Consumer < Result < Map<String, byte[]>>> consumer) { public void getAll(String prefix, Consumer < Result < Map<String, byte[]>>> consumer) {
assert mFeedContentBridge != null; assert mFeedContentBridge != null;
mFeedContentBridge.loadContentByPrefix( mFeedContentBridge.loadContentByPrefix(prefix,
prefix, new StorageCallback<Map<String, byte[]>>(consumer)); (Map<String, byte[]> data)
-> { consumer.accept(Result.success(data)); },
(Map<String, byte[]> data) -> { consumer.accept(Result.failure()); });
} }
@Override @Override
public void commit(ContentMutation mutation, Consumer<CommitResult> consumer) { public void commit(ContentMutation mutation, Consumer<CommitResult> consumer) {
assert mFeedContentBridge != null; assert mFeedContentBridge != null;
mFeedContentBridge.commitContentMutation(mutation, new CommitCallback(consumer)); mFeedContentBridge.commitContentMutation(mutation, (Boolean result) -> {
consumer.accept(result ? CommitResult.SUCCESS : CommitResult.FAILURE);
});
} }
@Override @Override
public void getAllKeys(Consumer < Result < List<String>>> consumer) { public void getAllKeys(Consumer < Result < List<String>>> consumer) {
assert mFeedContentBridge != null; assert mFeedContentBridge != null;
mFeedContentBridge.loadAllContentKeys(new GetAllKeysCallback(consumer)); mFeedContentBridge.loadAllContentKeys(
(String[] keys)
-> { consumer.accept(Result.success(Arrays.asList(keys))); },
(String[] keys) -> { consumer.accept(Result.failure()); });
} }
} }
...@@ -80,27 +80,51 @@ public class FeedContentStorageTest { ...@@ -80,27 +80,51 @@ public class FeedContentStorageTest {
@Captor @Captor
private ArgumentCaptor<Callback<Boolean>> mBooleanCallbackArgument; private ArgumentCaptor<Callback<Boolean>> mBooleanCallbackArgument;
@Captor @Captor
private ArgumentCaptor<Callback<String[]>> mArrayOfStringCallbackArgument; private ArgumentCaptor<Callback<String[]>> mArrayOfStringSuccessCallbackArgument;
@Captor @Captor
private ArgumentCaptor < Callback < Map<String, byte[]>>> mMapCallbackArgument; private ArgumentCaptor<Callback<String[]>> mArrayOfStringFailureCallbackArgument;
@Captor
private ArgumentCaptor < Callback < Map<String, byte[]>>> mMapSuccessCallbackArgument;
@Captor
private ArgumentCaptor < Callback < Map<String, byte[]>>> mMapFailureCallbackArgument;
private FeedContentStorage mContentStorage; private FeedContentStorage mContentStorage;
private Answer<Void> createMapAnswer(Map<String, byte[]> map) { private Answer<Void> createMapSuccessAnswer(Map<String, byte[]> map) {
return new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) {
mMapSuccessCallbackArgument.getValue().onResult(map);
return null;
}
};
}
private Answer<Void> createMapFailureAnswer(Map<String, byte[]> map) {
return new Answer<Void>() { return new Answer<Void>() {
@Override @Override
public Void answer(InvocationOnMock invocation) { public Void answer(InvocationOnMock invocation) {
mMapCallbackArgument.getValue().onResult(map); mMapFailureCallbackArgument.getValue().onResult(map);
return null; return null;
} }
}; };
} }
private Answer<Void> createArrayOfStringAnswer(String[] arrayOfString) { private Answer<Void> createArrayOfStringSuccessAnswer(String[] arrayOfString) {
return new Answer<Void>() { return new Answer<Void>() {
@Override @Override
public Void answer(InvocationOnMock invocation) { public Void answer(InvocationOnMock invocation) {
mArrayOfStringCallbackArgument.getValue().onResult(arrayOfString); mArrayOfStringSuccessCallbackArgument.getValue().onResult(arrayOfString);
return null;
}
};
}
private Answer<Void> createArrayOfStringFailureAnswer(String[] arrayOfString) {
return new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) {
mArrayOfStringFailureCallbackArgument.getValue().onResult(arrayOfString);
return null; return null;
} }
}; };
...@@ -155,17 +179,36 @@ public class FeedContentStorageTest { ...@@ -155,17 +179,36 @@ public class FeedContentStorageTest {
public void getTest() { public void getTest() {
Map<String, byte[]> answerMap = new HashMap<>(); Map<String, byte[]> answerMap = new HashMap<>();
answerMap.put(CONTENT_KEY1, CONTENT_DATA1); answerMap.put(CONTENT_KEY1, CONTENT_DATA1);
Answer<Void> answer = createMapAnswer(answerMap); Answer<Void> answer = createMapSuccessAnswer(answerMap);
doAnswer(answer).when(mBridge).loadContent( doAnswer(answer).when(mBridge).loadContent(mStringListArgument.capture(),
mStringListArgument.capture(), mMapCallbackArgument.capture()); mMapSuccessCallbackArgument.capture(), mMapFailureCallbackArgument.capture());
List<String> keys = Arrays.asList(CONTENT_KEY1, CONTENT_KEY2); List<String> keys = Arrays.asList(CONTENT_KEY1, CONTENT_KEY2);
mContentStorage.get(keys, mMapConsumer); mContentStorage.get(keys, mMapConsumer);
verify(mBridge, times(1)).loadContent(eq(keys), mMapCallbackArgument.capture()); verify(mBridge, times(1))
.loadContent(eq(keys), mMapSuccessCallbackArgument.capture(),
mMapFailureCallbackArgument.capture());
verify(mMapConsumer, times(1)).accept(mMapCaptor.capture()); verify(mMapConsumer, times(1)).accept(mMapCaptor.capture());
verifyMapResult(answerMap, true, mMapCaptor.getValue()); verifyMapResult(answerMap, true, mMapCaptor.getValue());
} }
@Test
@SmallTest
public void getFailureTest() {
Map<String, byte[]> answerMap = new HashMap<>();
Answer<Void> answer = createMapFailureAnswer(answerMap);
doAnswer(answer).when(mBridge).loadContent(mStringListArgument.capture(),
mMapSuccessCallbackArgument.capture(), mMapFailureCallbackArgument.capture());
List<String> keys = Arrays.asList(CONTENT_KEY1, CONTENT_KEY2);
mContentStorage.get(keys, mMapConsumer);
verify(mBridge, times(1))
.loadContent(eq(keys), mMapSuccessCallbackArgument.capture(),
mMapFailureCallbackArgument.capture());
verify(mMapConsumer, times(1)).accept(mMapCaptor.capture());
verifyMapResult(answerMap, false, mMapCaptor.getValue());
}
@Test @Test
@SmallTest @SmallTest
public void getAllTest() { public void getAllTest() {
...@@ -173,13 +216,14 @@ public class FeedContentStorageTest { ...@@ -173,13 +216,14 @@ public class FeedContentStorageTest {
answerMap.put(CONTENT_KEY1, CONTENT_DATA1); answerMap.put(CONTENT_KEY1, CONTENT_DATA1);
answerMap.put(CONTENT_KEY2, CONTENT_DATA2); answerMap.put(CONTENT_KEY2, CONTENT_DATA2);
answerMap.put(CONTENT_KEY3, CONTENT_DATA3); answerMap.put(CONTENT_KEY3, CONTENT_DATA3);
Answer<Void> answer = createMapAnswer(answerMap); Answer<Void> answer = createMapSuccessAnswer(answerMap);
doAnswer(answer).when(mBridge).loadContentByPrefix( doAnswer(answer).when(mBridge).loadContentByPrefix(mStringArgument.capture(),
mStringArgument.capture(), mMapCallbackArgument.capture()); mMapSuccessCallbackArgument.capture(), mMapFailureCallbackArgument.capture());
mContentStorage.getAll(CONTENT_KEY1, mMapConsumer); mContentStorage.getAll(CONTENT_KEY1, mMapConsumer);
verify(mBridge, times(1)) verify(mBridge, times(1))
.loadContentByPrefix(eq(CONTENT_KEY1), mMapCallbackArgument.capture()); .loadContentByPrefix(eq(CONTENT_KEY1), mMapSuccessCallbackArgument.capture(),
mMapFailureCallbackArgument.capture());
verify(mMapConsumer, times(1)).accept(mMapCaptor.capture()); verify(mMapConsumer, times(1)).accept(mMapCaptor.capture());
verifyMapResult(answerMap, true, mMapCaptor.getValue()); verifyMapResult(answerMap, true, mMapCaptor.getValue());
} }
...@@ -188,15 +232,36 @@ public class FeedContentStorageTest { ...@@ -188,15 +232,36 @@ public class FeedContentStorageTest {
@SmallTest @SmallTest
public void getAllKeysTest() { public void getAllKeysTest() {
String[] answerStrings = {CONTENT_KEY1, CONTENT_KEY2, CONTENT_KEY3}; String[] answerStrings = {CONTENT_KEY1, CONTENT_KEY2, CONTENT_KEY3};
Answer<Void> answer = createArrayOfStringAnswer(answerStrings); Answer<Void> answer = createArrayOfStringSuccessAnswer(answerStrings);
doAnswer(answer).when(mBridge).loadAllContentKeys(mArrayOfStringCallbackArgument.capture()); doAnswer(answer).when(mBridge).loadAllContentKeys(
mArrayOfStringSuccessCallbackArgument.capture(),
mArrayOfStringFailureCallbackArgument.capture());
mContentStorage.getAllKeys(mListConsumer); mContentStorage.getAllKeys(mListConsumer);
verify(mBridge, times(1)).loadAllContentKeys(mArrayOfStringCallbackArgument.capture()); verify(mBridge, times(1))
.loadAllContentKeys(mArrayOfStringSuccessCallbackArgument.capture(),
mArrayOfStringFailureCallbackArgument.capture());
verify(mListConsumer, times(1)).accept(mStringListCaptor.capture()); verify(mListConsumer, times(1)).accept(mStringListCaptor.capture());
verifyArrayOfStringResult(answerStrings, true, mStringListCaptor.getValue()); verifyArrayOfStringResult(answerStrings, true, mStringListCaptor.getValue());
} }
@Test
@SmallTest
public void getAllKeysFailureTest() {
String[] answerStrings = {CONTENT_KEY1, CONTENT_KEY2, CONTENT_KEY3};
Answer<Void> answer = createArrayOfStringFailureAnswer(answerStrings);
doAnswer(answer).when(mBridge).loadAllContentKeys(
mArrayOfStringSuccessCallbackArgument.capture(),
mArrayOfStringFailureCallbackArgument.capture());
mContentStorage.getAllKeys(mListConsumer);
verify(mBridge, times(1))
.loadAllContentKeys(mArrayOfStringSuccessCallbackArgument.capture(),
mArrayOfStringFailureCallbackArgument.capture());
verify(mListConsumer, times(1)).accept(mStringListCaptor.capture());
verifyArrayOfStringResult(answerStrings, false, mStringListCaptor.getValue());
}
@Test @Test
@SmallTest @SmallTest
public void commitTest() { public void commitTest() {
......
...@@ -65,40 +65,50 @@ void FeedContentBridge::Destroy(JNIEnv* env, const JavaRef<jobject>& j_this) { ...@@ -65,40 +65,50 @@ void FeedContentBridge::Destroy(JNIEnv* env, const JavaRef<jobject>& j_this) {
delete this; delete this;
} }
void FeedContentBridge::LoadContent(JNIEnv* j_env, void FeedContentBridge::LoadContent(
const JavaRef<jobject>& j_this, JNIEnv* j_env,
const JavaRef<jobjectArray>& j_keys, const JavaRef<jobject>& j_this,
const JavaRef<jobject>& j_callback) { const JavaRef<jobjectArray>& j_keys,
const JavaRef<jobject>& j_success_callback,
const JavaRef<jobject>& j_failure_callback) {
std::vector<std::string> keys; std::vector<std::string> keys;
AppendJavaStringArrayToStringVector(j_env, j_keys.obj(), &keys); AppendJavaStringArrayToStringVector(j_env, j_keys.obj(), &keys);
ScopedJavaGlobalRef<jobject> callback(j_callback); ScopedJavaGlobalRef<jobject> success_callback(j_success_callback);
ScopedJavaGlobalRef<jobject> failure_callback(j_failure_callback);
feed_content_database_->LoadContent( feed_content_database_->LoadContent(
keys, base::BindOnce(&FeedContentBridge::OnLoadContentDone, keys, base::BindOnce(&FeedContentBridge::OnLoadContentDone,
weak_ptr_factory_.GetWeakPtr(), callback)); weak_ptr_factory_.GetWeakPtr(), success_callback,
failure_callback));
} }
void FeedContentBridge::LoadContentByPrefix( void FeedContentBridge::LoadContentByPrefix(
JNIEnv* j_env, JNIEnv* j_env,
const JavaRef<jobject>& j_this, const JavaRef<jobject>& j_this,
const JavaRef<jstring>& j_prefix, const JavaRef<jstring>& j_prefix,
const JavaRef<jobject>& j_callback) { const JavaRef<jobject>& j_success_callback,
const JavaRef<jobject>& j_failure_callback) {
std::string prefix = ConvertJavaStringToUTF8(j_env, j_prefix); std::string prefix = ConvertJavaStringToUTF8(j_env, j_prefix);
ScopedJavaGlobalRef<jobject> callback(j_callback); ScopedJavaGlobalRef<jobject> success_callback(j_success_callback);
ScopedJavaGlobalRef<jobject> failure_callback(j_failure_callback);
feed_content_database_->LoadContentByPrefix( feed_content_database_->LoadContentByPrefix(
prefix, base::BindOnce(&FeedContentBridge::OnLoadContentDone, prefix, base::BindOnce(&FeedContentBridge::OnLoadContentDone,
weak_ptr_factory_.GetWeakPtr(), callback)); weak_ptr_factory_.GetWeakPtr(), success_callback,
failure_callback));
} }
void FeedContentBridge::LoadAllContentKeys(JNIEnv* j_env, void FeedContentBridge::LoadAllContentKeys(
const JavaRef<jobject>& j_this, JNIEnv* j_env,
const JavaRef<jobject>& j_callback) { const JavaRef<jobject>& j_this,
ScopedJavaGlobalRef<jobject> callback(j_callback); const JavaRef<jobject>& j_success_callback,
const JavaRef<jobject>& j_failure_callback) {
feed_content_database_->LoadAllContentKeys( ScopedJavaGlobalRef<jobject> success_callback(j_success_callback);
base::BindOnce(&FeedContentBridge::OnLoadAllContentKeysDone, ScopedJavaGlobalRef<jobject> failure_callback(j_failure_callback);
weak_ptr_factory_.GetWeakPtr(), callback));
feed_content_database_->LoadAllContentKeys(base::BindOnce(
&FeedContentBridge::OnLoadAllContentKeysDone,
weak_ptr_factory_.GetWeakPtr(), success_callback, failure_callback));
} }
void FeedContentBridge::CommitContentMutation( void FeedContentBridge::CommitContentMutation(
...@@ -168,7 +178,9 @@ void FeedContentBridge::AppendDeleteAllOperation( ...@@ -168,7 +178,9 @@ void FeedContentBridge::AppendDeleteAllOperation(
} }
void FeedContentBridge::OnLoadContentDone( void FeedContentBridge::OnLoadContentDone(
ScopedJavaGlobalRef<jobject> callback, ScopedJavaGlobalRef<jobject> success_callback,
ScopedJavaGlobalRef<jobject> failure_callback,
bool success,
std::vector<FeedContentDatabase::KeyAndData> pairs) { std::vector<FeedContentDatabase::KeyAndData> pairs) {
std::vector<std::string> keys; std::vector<std::string> keys;
std::vector<std::string> data; std::vector<std::string> data;
...@@ -184,16 +196,27 @@ void FeedContentBridge::OnLoadContentDone( ...@@ -184,16 +196,27 @@ void FeedContentBridge::OnLoadContentDone(
// Create Java Map by JNI call. // Create Java Map by JNI call.
ScopedJavaLocalRef<jobject> j_pairs = ScopedJavaLocalRef<jobject> j_pairs =
Java_FeedContentBridge_createKeyAndDataMap(env, j_keys, j_data); Java_FeedContentBridge_createKeyAndDataMap(env, j_keys, j_data);
RunObjectCallbackAndroid(callback, j_pairs);
if (!success) {
RunObjectCallbackAndroid(failure_callback, j_pairs);
return;
}
RunObjectCallbackAndroid(success_callback, j_pairs);
} }
void FeedContentBridge::OnLoadAllContentKeysDone( void FeedContentBridge::OnLoadAllContentKeysDone(
ScopedJavaGlobalRef<jobject> callback, ScopedJavaGlobalRef<jobject> success_callback,
ScopedJavaGlobalRef<jobject> failure_callback,
bool success,
std::vector<std::string> keys) { std::vector<std::string> keys) {
JNIEnv* env = AttachCurrentThread(); JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobjectArray> j_keys = ToJavaArrayOfStrings(env, keys); ScopedJavaLocalRef<jobjectArray> j_keys = ToJavaArrayOfStrings(env, keys);
RunObjectCallbackAndroid(callback, j_keys); if (!success) {
RunObjectCallbackAndroid(failure_callback, j_keys);
return;
}
RunObjectCallbackAndroid(success_callback, j_keys);
} }
void FeedContentBridge::OnStorageCommitDone( void FeedContentBridge::OnStorageCommitDone(
......
...@@ -33,14 +33,19 @@ class FeedContentBridge { ...@@ -33,14 +33,19 @@ class FeedContentBridge {
void LoadContent(JNIEnv* j_env, void LoadContent(JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this, const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jobjectArray>& j_keys, const base::android::JavaRef<jobjectArray>& j_keys,
const base::android::JavaRef<jobject>& j_callback); const base::android::JavaRef<jobject>& j_success_callback,
void LoadContentByPrefix(JNIEnv* j_env, const base::android::JavaRef<jobject>& j_failure_callback);
const base::android::JavaRef<jobject>& j_this, void LoadContentByPrefix(
const base::android::JavaRef<jstring>& j_prefix, JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_callback); const base::android::JavaRef<jobject>& j_this,
void LoadAllContentKeys(JNIEnv* j_env, const base::android::JavaRef<jstring>& j_prefix,
const base::android::JavaRef<jobject>& j_this, const base::android::JavaRef<jobject>& j_success_callback,
const base::android::JavaRef<jobject>& j_callback); const base::android::JavaRef<jobject>& j_failure_callback);
void LoadAllContentKeys(
JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jobject>& j_success_callback,
const base::android::JavaRef<jobject>& j_failure_callback);
void CommitContentMutation(JNIEnv* j_env, void CommitContentMutation(JNIEnv* j_env,
const base::android::JavaRef<jobject>& j_this, const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jobject>& j_callback); const base::android::JavaRef<jobject>& j_callback);
...@@ -64,10 +69,15 @@ class FeedContentBridge { ...@@ -64,10 +69,15 @@ class FeedContentBridge {
const base::android::JavaRef<jobject>& j_this); const base::android::JavaRef<jobject>& j_this);
private: private:
void OnLoadContentDone(base::android::ScopedJavaGlobalRef<jobject> callback, void OnLoadContentDone(
std::vector<FeedContentDatabase::KeyAndData> pairs); base::android::ScopedJavaGlobalRef<jobject> success_callback,
base::android::ScopedJavaGlobalRef<jobject> failure_callback,
bool success,
std::vector<FeedContentDatabase::KeyAndData> pairs);
void OnLoadAllContentKeysDone( void OnLoadAllContentKeysDone(
base::android::ScopedJavaGlobalRef<jobject> callback, base::android::ScopedJavaGlobalRef<jobject> success_callback,
base::android::ScopedJavaGlobalRef<jobject> failure_callback,
bool success,
std::vector<std::string> keys); std::vector<std::string> keys);
void OnStorageCommitDone(base::android::ScopedJavaGlobalRef<jobject> callback, void OnStorageCommitDone(base::android::ScopedJavaGlobalRef<jobject> callback,
bool success); bool success);
......
...@@ -236,14 +236,9 @@ void FeedContentDatabase::OnLoadEntriesForLoadContent( ...@@ -236,14 +236,9 @@ void FeedContentDatabase::OnLoadEntriesForLoadContent(
ContentLoadCallback callback, ContentLoadCallback callback,
bool success, bool success,
std::unique_ptr<std::vector<ContentStorageProto>> content) { std::unique_ptr<std::vector<ContentStorageProto>> content) {
std::vector<KeyAndData> results; DVLOG_IF(1, !success) << "FeedContentDatabase load content failed.";
if (!success || !content) {
DVLOG_IF(1, !success) << "FeedContentDatabase load content failed.";
std::move(callback).Run(std::move(results));
return;
}
std::vector<KeyAndData> results;
for (const auto& proto : *content) { for (const auto& proto : *content) {
DCHECK(proto.has_key()); DCHECK(proto.has_key());
DCHECK(proto.has_content_data()); DCHECK(proto.has_content_data());
...@@ -251,24 +246,19 @@ void FeedContentDatabase::OnLoadEntriesForLoadContent( ...@@ -251,24 +246,19 @@ void FeedContentDatabase::OnLoadEntriesForLoadContent(
results.emplace_back(proto.key(), proto.content_data()); results.emplace_back(proto.key(), proto.content_data());
} }
std::move(callback).Run(std::move(results)); std::move(callback).Run(success, std::move(results));
} }
void FeedContentDatabase::OnLoadKeysForLoadAllContentKeys( void FeedContentDatabase::OnLoadKeysForLoadAllContentKeys(
ContentKeyCallback callback, ContentKeyCallback callback,
bool success, bool success,
std::unique_ptr<std::vector<std::string>> keys) { std::unique_ptr<std::vector<std::string>> keys) {
if (!success || !keys) { DVLOG_IF(1, !success) << "FeedContentDatabase load content keys failed.";
DVLOG_IF(1, !success) << "FeedContentDatabase load content keys failed.";
std::vector<std::string> results;
std::move(callback).Run(std::move(results));
return;
}
// We std::move the |*keys|'s entries to |callback|, after that, |keys| become // We std::move the |*keys|'s entries to |callback|, after that, |keys| become
// a pointer holding an empty vector, then we can safely delete unique_ptr // a pointer holding an empty vector, then we can safely delete unique_ptr
// |keys| when it out of scope. // |keys| when it out of scope.
std::move(callback).Run(std::move(*keys)); std::move(callback).Run(success, std::move(*keys));
} }
void FeedContentDatabase::OnOperationCommitted( void FeedContentDatabase::OnOperationCommitted(
......
...@@ -34,10 +34,12 @@ class FeedContentDatabase { ...@@ -34,10 +34,12 @@ class FeedContentDatabase {
// Returns the storage data as a vector of key-value pairs when calling // Returns the storage data as a vector of key-value pairs when calling
// loading data. // loading data.
using ContentLoadCallback = base::OnceCallback<void(std::vector<KeyAndData>)>; using ContentLoadCallback =
base::OnceCallback<void(bool, std::vector<KeyAndData>)>;
// Returns the content keys as a vector when calling loading all content keys. // Returns the content keys as a vector when calling loading all content keys.
using ContentKeyCallback = base::OnceCallback<void(std::vector<std::string>)>; using ContentKeyCallback =
base::OnceCallback<void(bool, std::vector<std::string>)>;
// Returns whether the commit operation succeeded when calling for database // Returns whether the commit operation succeeded when calling for database
// operations, or return whether the entry exists when calling for checking // operations, or return whether the entry exists when calling for checking
......
...@@ -66,9 +66,9 @@ class FeedContentDatabaseTest : public testing::Test { ...@@ -66,9 +66,9 @@ class FeedContentDatabaseTest : public testing::Test {
FeedContentDatabase* db() { return feed_db_.get(); } FeedContentDatabase* db() { return feed_db_.get(); }
MOCK_METHOD1(OnContentEntriesReceived, MOCK_METHOD2(OnContentEntriesReceived,
void(std::vector<std::pair<std::string, std::string>>)); void(bool, std::vector<std::pair<std::string, std::string>>));
MOCK_METHOD1(OnContentKeyReceived, void(std::vector<std::string>)); MOCK_METHOD2(OnContentKeyReceived, void(bool, std::vector<std::string>));
MOCK_METHOD1(OnStorageCommitted, void(bool)); MOCK_METHOD1(OnStorageCommitted, void(bool));
private: private:
...@@ -96,7 +96,7 @@ TEST_F(FeedContentDatabaseTest, Init) { ...@@ -96,7 +96,7 @@ TEST_F(FeedContentDatabaseTest, Init) {
TEST_F(FeedContentDatabaseTest, LoadContentAfterInitSuccess) { TEST_F(FeedContentDatabaseTest, LoadContentAfterInitSuccess) {
CreateDatabase(/*init_database=*/true); CreateDatabase(/*init_database=*/true);
EXPECT_CALL(*this, OnContentEntriesReceived(_)); EXPECT_CALL(*this, OnContentEntriesReceived(_, _));
db()->LoadContent( db()->LoadContent(
{kContentKey1}, {kContentKey1},
base::BindOnce(&FeedContentDatabaseTest::OnContentEntriesReceived, base::BindOnce(&FeedContentDatabaseTest::OnContentEntriesReceived,
...@@ -113,8 +113,10 @@ TEST_F(FeedContentDatabaseTest, LoadContentsEntries) { ...@@ -113,8 +113,10 @@ TEST_F(FeedContentDatabaseTest, LoadContentsEntries) {
// Try to Load |kContentKey2| and |kContentKey3|, only |kContentKey2| should // Try to Load |kContentKey2| and |kContentKey3|, only |kContentKey2| should
// return. // return.
EXPECT_CALL(*this, OnContentEntriesReceived(_)) EXPECT_CALL(*this, OnContentEntriesReceived(_, _))
.WillOnce([](std::vector<std::pair<std::string, std::string>> results) { .WillOnce([](bool success,
std::vector<std::pair<std::string, std::string>> results) {
EXPECT_TRUE(success);
ASSERT_EQ(results.size(), 1U); ASSERT_EQ(results.size(), 1U);
EXPECT_EQ(results[0].first, kContentKey2); EXPECT_EQ(results[0].first, kContentKey2);
EXPECT_EQ(results[0].second, kContentData2); EXPECT_EQ(results[0].second, kContentData2);
...@@ -135,8 +137,10 @@ TEST_F(FeedContentDatabaseTest, LoadContentsEntriesByPrefix) { ...@@ -135,8 +137,10 @@ TEST_F(FeedContentDatabaseTest, LoadContentsEntriesByPrefix) {
// Try to Load "ContentKey", both |kContentKey1| and |kContentKey2| should // Try to Load "ContentKey", both |kContentKey1| and |kContentKey2| should
// return. // return.
EXPECT_CALL(*this, OnContentEntriesReceived(_)) EXPECT_CALL(*this, OnContentEntriesReceived(_, _))
.WillOnce([](std::vector<std::pair<std::string, std::string>> results) { .WillOnce([](bool success,
std::vector<std::pair<std::string, std::string>> results) {
EXPECT_TRUE(success);
ASSERT_EQ(results.size(), 2U); ASSERT_EQ(results.size(), 2U);
EXPECT_EQ(results[0].first, kContentKey1); EXPECT_EQ(results[0].first, kContentKey1);
EXPECT_EQ(results[0].second, kContentData1); EXPECT_EQ(results[0].second, kContentData1);
...@@ -157,8 +161,9 @@ TEST_F(FeedContentDatabaseTest, LoadAllContentKeys) { ...@@ -157,8 +161,9 @@ TEST_F(FeedContentDatabaseTest, LoadAllContentKeys) {
InjectContentStorageProto(kContentKey1, kContentData1); InjectContentStorageProto(kContentKey1, kContentData1);
InjectContentStorageProto(kContentKey2, kContentData2); InjectContentStorageProto(kContentKey2, kContentData2);
EXPECT_CALL(*this, OnContentKeyReceived(_)) EXPECT_CALL(*this, OnContentKeyReceived(_, _))
.WillOnce([](std::vector<std::string> results) { .WillOnce([](bool success, std::vector<std::string> results) {
EXPECT_TRUE(success);
ASSERT_EQ(results.size(), 2U); ASSERT_EQ(results.size(), 2U);
EXPECT_EQ(results[0], kContentKey1); EXPECT_EQ(results[0], kContentKey1);
EXPECT_EQ(results[1], kContentKey2); EXPECT_EQ(results[1], kContentKey2);
...@@ -185,8 +190,10 @@ TEST_F(FeedContentDatabaseTest, SaveContent) { ...@@ -185,8 +190,10 @@ TEST_F(FeedContentDatabaseTest, SaveContent) {
storage_db()->UpdateCallback(true); storage_db()->UpdateCallback(true);
// Make sure they're there. // Make sure they're there.
EXPECT_CALL(*this, OnContentEntriesReceived(_)) EXPECT_CALL(*this, OnContentEntriesReceived(_, _))
.WillOnce([](std::vector<std::pair<std::string, std::string>> results) { .WillOnce([](bool success,
std::vector<std::pair<std::string, std::string>> results) {
EXPECT_TRUE(success);
ASSERT_EQ(results.size(), 2U); ASSERT_EQ(results.size(), 2U);
EXPECT_EQ(results[0].first, kContentKey1); EXPECT_EQ(results[0].first, kContentKey1);
EXPECT_EQ(results[0].second, kContentData1); EXPECT_EQ(results[0].second, kContentData1);
...@@ -221,8 +228,10 @@ TEST_F(FeedContentDatabaseTest, DeleteContent) { ...@@ -221,8 +228,10 @@ TEST_F(FeedContentDatabaseTest, DeleteContent) {
storage_db()->UpdateCallback(true); storage_db()->UpdateCallback(true);
// Make sure only |kContentKey2| got deleted. // Make sure only |kContentKey2| got deleted.
EXPECT_CALL(*this, OnContentEntriesReceived(_)) EXPECT_CALL(*this, OnContentEntriesReceived(_, _))
.WillOnce([](std::vector<std::pair<std::string, std::string>> results) { .WillOnce([](bool success,
std::vector<std::pair<std::string, std::string>> results) {
EXPECT_TRUE(success);
EXPECT_EQ(results.size(), 1U); EXPECT_EQ(results.size(), 1U);
EXPECT_EQ(results[0].first, kContentKey1); EXPECT_EQ(results[0].first, kContentKey1);
EXPECT_EQ(results[0].second, kContentData1); EXPECT_EQ(results[0].second, kContentData1);
...@@ -253,8 +262,10 @@ TEST_F(FeedContentDatabaseTest, DeleteContentByPrefix) { ...@@ -253,8 +262,10 @@ TEST_F(FeedContentDatabaseTest, DeleteContentByPrefix) {
storage_db()->UpdateCallback(true); storage_db()->UpdateCallback(true);
// Make sure |kContentKey1| and |kContentKey2| got deleted. // Make sure |kContentKey1| and |kContentKey2| got deleted.
EXPECT_CALL(*this, OnContentEntriesReceived(_)) EXPECT_CALL(*this, OnContentEntriesReceived(_, _))
.WillOnce([](std::vector<std::pair<std::string, std::string>> results) { .WillOnce([](bool success,
std::vector<std::pair<std::string, std::string>> results) {
EXPECT_TRUE(success);
EXPECT_EQ(results.size(), 0U); EXPECT_EQ(results.size(), 0U);
}); });
db()->LoadContent( db()->LoadContent(
...@@ -284,8 +295,10 @@ TEST_F(FeedContentDatabaseTest, DeleteAllContent) { ...@@ -284,8 +295,10 @@ TEST_F(FeedContentDatabaseTest, DeleteAllContent) {
storage_db()->UpdateCallback(true); storage_db()->UpdateCallback(true);
// Make sure |kContentKey1| and |kContentKey2| got deleted. // Make sure |kContentKey1| and |kContentKey2| got deleted.
EXPECT_CALL(*this, OnContentEntriesReceived(_)) EXPECT_CALL(*this, OnContentEntriesReceived(_, _))
.WillOnce([](std::vector<std::pair<std::string, std::string>> results) { .WillOnce([](bool success,
std::vector<std::pair<std::string, std::string>> results) {
EXPECT_TRUE(success);
EXPECT_EQ(results.size(), 0U); EXPECT_EQ(results.size(), 0U);
}); });
db()->LoadContent( db()->LoadContent(
...@@ -316,8 +329,10 @@ TEST_F(FeedContentDatabaseTest, SaveAndDeleteContent) { ...@@ -316,8 +329,10 @@ TEST_F(FeedContentDatabaseTest, SaveAndDeleteContent) {
storage_db()->UpdateCallback(true); storage_db()->UpdateCallback(true);
// Make sure only |kContentKey2| got deleted. // Make sure only |kContentKey2| got deleted.
EXPECT_CALL(*this, OnContentEntriesReceived(_)) EXPECT_CALL(*this, OnContentEntriesReceived(_, _))
.WillOnce([](std::vector<std::pair<std::string, std::string>> results) { .WillOnce([](bool success,
std::vector<std::pair<std::string, std::string>> results) {
EXPECT_TRUE(success);
EXPECT_EQ(results.size(), 1U); EXPECT_EQ(results.size(), 1U);
EXPECT_EQ(results[0].first, kContentKey1); EXPECT_EQ(results[0].first, kContentKey1);
EXPECT_EQ(results[0].second, kContentData1); EXPECT_EQ(results[0].second, kContentData1);
...@@ -329,4 +344,40 @@ TEST_F(FeedContentDatabaseTest, SaveAndDeleteContent) { ...@@ -329,4 +344,40 @@ TEST_F(FeedContentDatabaseTest, SaveAndDeleteContent) {
storage_db()->LoadCallback(true); storage_db()->LoadCallback(true);
} }
TEST_F(FeedContentDatabaseTest, LoadContentsFail) {
CreateDatabase(/*init_database=*/true);
// Store |kContentKey1| and |kContentKey2|.
InjectContentStorageProto(kContentKey1, kContentData1);
InjectContentStorageProto(kContentKey2, kContentData2);
// Try to Load |kContentKey2| and |kContentKey3|,.
EXPECT_CALL(*this, OnContentEntriesReceived(_, _))
.WillOnce([](bool success,
std::vector<std::pair<std::string, std::string>> results) {
EXPECT_FALSE(success);
});
db()->LoadContent(
{kContentKey2, kContentKey3},
base::BindOnce(&FeedContentDatabaseTest::OnContentEntriesReceived,
base::Unretained(this)));
storage_db()->LoadCallback(false);
}
TEST_F(FeedContentDatabaseTest, LoadAllContentKeysFail) {
CreateDatabase(/*init_database=*/true);
// Store |kContentKey1|, |kContentKey2|.
InjectContentStorageProto(kContentKey1, kContentData1);
InjectContentStorageProto(kContentKey2, kContentData2);
EXPECT_CALL(*this, OnContentKeyReceived(_, _))
.WillOnce([](bool success, std::vector<std::string> results) {
EXPECT_FALSE(success);
});
db()->LoadAllContentKeys(base::BindOnce(
&FeedContentDatabaseTest::OnContentKeyReceived, base::Unretained(this)));
storage_db()->LoadKeysCallback(false);
}
} // namespace feed } // 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