/*
* Copyright 2015 Victor Albertos
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.rx_cache2.internal;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import io.reactivex.Observable;
import io.reactivex.functions.Function;
import io.reactivex.observers.TestObserver;
import io.rx_cache2.DynamicKey;
import io.rx_cache2.EvictProvider;
import io.rx_cache2.ProviderHelper;
import io.rx_cache2.Reply;
import io.rx_cache2.Source;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hamcrest.CoreMatchers;
import org.junit.ClassRule;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runners.MethodSorters;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
/**
* Created by victor on 28/12/15.
*/
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ProvidersRxCacheTest {
@ClassRule public static TemporaryFolder temporaryFolder = new TemporaryFolder();
private ProvidersRxCache providersRxCache;
private RxCache rxCache;
private final static int SIZE = 100;
private void initProviders(boolean useExpiredDataIfLoaderNotAvailable) {
rxCache = new RxCache.Builder()
.useExpiredDataIfLoaderNotAvailable(useExpiredDataIfLoaderNotAvailable)
.persistence(temporaryFolder.getRoot(), Jolyglot$.newInstance());
providersRxCache = rxCache
.using(ProvidersRxCache.class);
}
@Test public void _00_Use_Expired_Data() {
initProviders(true);
TestObserver<Reply<List<io.rx_cache2.internal.Mock>>> observer;
observer = new TestObserver<>();
providersRxCache.getMocksListResponseOneSecond(createObservableMocks(SIZE))
.subscribe(observer);
observer.awaitTerminalEvent();
waitTime(1500);
observer = new TestObserver<>();
providersRxCache.getMocksListResponseOneSecond(Observable.just(Arrays.asList(new io.rx_cache2.internal.Mock())))
.subscribe(observer);
observer.awaitTerminalEvent();
Reply<List<io.rx_cache2.internal.Mock>> reply = observer.values().get(0);
assertThat(reply.getData().size(), is(SIZE));
assertThat(observer.errors().size(), is(0));
}
@Test public void _01_Before_Destroy_Memory() {
initProviders(false);
TestObserver<Reply<List<io.rx_cache2.internal.Mock>>> subscriber;
subscriber = new TestObserver<>();
providersRxCache.getMocksWithDetailResponse(createObservableMocks(SIZE)).subscribe(subscriber);
subscriber.awaitTerminalEvent();
Reply<List<io.rx_cache2.internal.Mock>> reply = subscriber.values().get(0);
assertThat(reply.getSource(), CoreMatchers.is(Source.CLOUD));
assertThat(subscriber.values().get(0).getData().size(), is(SIZE));
subscriber = new TestObserver<>();
providersRxCache.getMocksWithDetailResponse(createObservableMocks(SIZE)).subscribe(subscriber);
subscriber.awaitTerminalEvent();
reply = subscriber.values().get(0);
assertThat(reply.getSource(), is(Source.MEMORY));
assertThat(reply.getData().size(), is(SIZE));
}
@Test public void _02_After_Memory_Destroyed() {
initProviders(false);
TestObserver<Reply<List<io.rx_cache2.internal.Mock>>> subscriber;
subscriber = new TestObserver<>();
providersRxCache.getMocksWithDetailResponse(createObservableMocks(SIZE)).subscribe(subscriber);
subscriber.awaitTerminalEvent();
Reply<List<io.rx_cache2.internal.Mock>> reply = subscriber.values().get(0);
assertThat(reply.getSource(), is(Source.PERSISTENCE));
assertThat(subscriber.values().get(0).getData().size(), is(SIZE));
subscriber = new TestObserver<>();
providersRxCache.getMocksListResponseOneSecond(createObservableMocks(SIZE))
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
reply = subscriber.values().get(0);
assertThat(reply.getSource(), is(Source.CLOUD));
assertThat(subscriber.values().get(0).getData().size(), is(SIZE));
waitTime(1100);
subscriber = new TestObserver<>();
providersRxCache.getMocksListResponseOneSecond(createObservableMocks(SIZE))
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
reply = subscriber.values().get(0);
assertThat(reply.getSource(), is(Source.CLOUD));
assertThat(subscriber.values().get(0).getData().size(), is(SIZE));
subscriber = new TestObserver<>();
providersRxCache.getMocksListResponseOneSecond(createObservableMocks(SIZE))
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
reply = subscriber.values().get(0);
assertThat(reply.getSource(), is(Source.MEMORY));
assertThat(subscriber.values().get(0).getData().size(), is(SIZE));
}
@Test public void _03_Evicting_Cache() {
initProviders(false);
TestObserver<Reply<List<io.rx_cache2.internal.Mock>>> subscriber;
subscriber = new TestObserver<>();
providersRxCache.getMocksEvictProvider(createObservableMocks(SIZE), new EvictProvider(false))
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
Reply<List<io.rx_cache2.internal.Mock>> reply = subscriber.values().get(0);
assertThat(reply.getSource(), is(Source.CLOUD));
assertThat(subscriber.values().get(0).getData().size(), is(SIZE));
subscriber = new TestObserver<>();
providersRxCache.getMocksEvictProvider(createObservableMocks(SIZE), new EvictProvider(false))
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
reply = subscriber.values().get(0);
assertThat(reply.getSource(), is(Source.MEMORY));
assertThat(subscriber.values().get(0).getData().size(), is(SIZE));
subscriber = new TestObserver<>();
providersRxCache.getMocksEvictProvider(createObservableMocks(SIZE), new EvictProvider(true))
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
reply = subscriber.values().get(0);
assertThat(reply.getSource(), is(Source.CLOUD));
assertThat(subscriber.values().get(0).getData().size(), is(SIZE));
}
@Test public void _04_Session_Mock() {
initProviders(false);
TestObserver<io.rx_cache2.internal.Mock> subscriber = new TestObserver<>();
io.rx_cache2.internal.Mock mock = createMocks(SIZE).get(0);
//not logged mock
providersRxCache.getLoggedMock(ProviderHelper.<io.rx_cache2.internal.Mock>withoutLoader(), new EvictProvider(false))
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
assertThat(subscriber.values().size(), is(0));
assertThat(subscriber.errors().size(), is(1));
//login mock
subscriber = new TestObserver<>();
providersRxCache.getLoggedMock(Observable.just(mock), new EvictProvider(true))
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
assertNotNull(subscriber.values().get(0));
//logged mock
subscriber = new TestObserver<>();
providersRxCache.getLoggedMock(ProviderHelper.<io.rx_cache2.internal.Mock>withoutLoader(), new EvictProvider(false))
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
assertNotNull(subscriber.values().get(0));
//logout mock
subscriber = new TestObserver<>();
providersRxCache.getLoggedMock(ProviderHelper.<io.rx_cache2.internal.Mock>withoutLoader(), new EvictProvider(true))
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
assertThat(subscriber.values().size(), is(0));
assertThat(subscriber.errors().size(), is(1));
//not logged mock
subscriber = new TestObserver<>();
providersRxCache.getLoggedMock(ProviderHelper.<io.rx_cache2.internal.Mock>withoutLoader(), new EvictProvider(false))
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
assertThat(subscriber.values().size(), is(0));
assertThat(subscriber.errors().size(), is(1));
}
@Test public void _06_Not_Use_Expired_Data() {
initProviders(false);
TestObserver<Reply<List<io.rx_cache2.internal.Mock>>> subscriber;
subscriber = new TestObserver<>();
providersRxCache.getMocksListResponseOneSecond(createObservableMocks(SIZE))
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
waitTime(1100);
subscriber = new TestObserver<>();
providersRxCache.getMocksListResponseOneSecond(ProviderHelper.<List<io.rx_cache2.internal.Mock>>withoutLoader())
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
assertThat(subscriber.errors().size(), is(1));
assertThat(subscriber.values().size(), is(0));
}
@Test public void _07_When_Retrieve_Cached_Data_After_Remove_Item_List_Then_Item_Still_Remains() {
initProviders(false);
TestObserver<Reply<List<io.rx_cache2.internal.Mock>>> subscriber;
subscriber = new TestObserver<>();
providersRxCache.getMocksWithDetailResponse(createObservableMocks(SIZE)).subscribe(subscriber);
subscriber.awaitTerminalEvent();
Reply<List<io.rx_cache2.internal.Mock>> reply = subscriber.values().get(0);
assertThat(reply.getData().size(), is(SIZE));
reply.getData().remove(0);
assertThat(reply.getData().size(), is(SIZE - 1));
subscriber = new TestObserver<>();
providersRxCache.getMocksWithDetailResponse(ProviderHelper.<List<io.rx_cache2.internal.Mock>>withoutLoader())
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
assertThat(subscriber.errors().size(), is(0));
assertThat(subscriber.values().size(), is(1));
reply = subscriber.values().get(0);
assertThat(reply.getData().size(), is(SIZE));
}
@Test
public void _08_When_Retrieve_Cached_Data_After_Remove_Item_Array_Then_Item_Still_Remains() {
initProviders(false);
TestObserver<Reply<io.rx_cache2.internal.Mock[]>> subscriber;
subscriber = new TestObserver<>();
providersRxCache.getMocksArrayResponse(createObservableMocksArray(SIZE)).subscribe(subscriber);
subscriber.awaitTerminalEvent();
Reply<io.rx_cache2.internal.Mock[]> reply = subscriber.values().get(0);
assertThat(reply.getData().length, is(SIZE));
reply = new Reply<>(Arrays.copyOf(reply.getData(), reply.getData().length - 1), reply.getSource(), false);
assertThat(reply.getData().length, is(SIZE - 1));
subscriber = new TestObserver<>();
providersRxCache.getMocksArrayResponse(ProviderHelper.<io.rx_cache2.internal.Mock[]>withoutLoader()).subscribe(subscriber);
subscriber.awaitTerminalEvent();
assertThat(subscriber.errors().size(), is(0));
assertThat(subscriber.values().size(), is(1));
reply = subscriber.values().get(0);
assertThat(reply.getData().length, is(SIZE));
}
@Test public void _09_When_Retrieve_Cached_Data_After_Remove_Item_Map_Then_Item_Still_Remains() {
initProviders(false);
TestObserver<Reply<Map<Integer, io.rx_cache2.internal.Mock>>> subscriber;
subscriber = new TestObserver<>();
providersRxCache.getMocksMapResponse(createObservableMocksMap(SIZE)).subscribe(subscriber);
subscriber.awaitTerminalEvent();
Reply<Map<Integer, io.rx_cache2.internal.Mock>> reply = subscriber.values().get(0);
assertThat(reply.getData().size(), is(SIZE));
reply.getData().remove(0);
assertThat(reply.getData().size(), is(SIZE - 1));
subscriber = new TestObserver<>();
providersRxCache.getMocksMapResponse(ProviderHelper.<Map<Integer, io.rx_cache2.internal.Mock>>withoutLoader())
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
assertThat(subscriber.errors().size(), is(0));
assertThat(subscriber.values().size(), is(1));
reply = subscriber.values().get(0);
assertThat(reply.getData().size(), is(SIZE));
}
@Test
public void _10_When_Retrieve_Cached_Data_After_Modified_Object_On_Item_List_Then_Object_Preserves_Initial_State() {
initProviders(false);
TestObserver<Reply<List<io.rx_cache2.internal.Mock>>> subscriber;
subscriber = new TestObserver<>();
providersRxCache.getMocksWithDetailResponse(createObservableMocks(SIZE)).subscribe(subscriber);
subscriber.awaitTerminalEvent();
Reply<List<io.rx_cache2.internal.Mock>> reply = subscriber.values().get(0);
Type type = new TypeToken<Reply<List<io.rx_cache2.internal.Mock>>>() {
}.getType();
Reply<List<io.rx_cache2.internal.Mock>> replyOriginal = (Reply<List<io.rx_cache2.internal.Mock>>) deepCopy(reply, type);
assertThat(compare(reply, replyOriginal, type), is(true));
reply.getData().get(0).setMessage("modified");
assertThat(compare(reply, replyOriginal, type), is(false));
subscriber = new TestObserver<>();
providersRxCache.getMocksWithDetailResponse(ProviderHelper.<List<io.rx_cache2.internal.Mock>>withoutLoader())
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
assertThat(subscriber.errors().size(), is(0));
assertThat(subscriber.values().size(), is(1));
reply = subscriber.values().get(0);
type = new TypeToken<List<io.rx_cache2.internal.Mock>>() {
}.getType();
assertThat(compare(reply.getData(), replyOriginal.getData(), type), is(true));
}
@Test
public void _11_When_Retrieve_Cached_Data_After_Modified_Object_On_Item_Array_Then_Object_Preserves_Initial_State() {
initProviders(false);
TestObserver<Reply<io.rx_cache2.internal.Mock[]>> subscriber;
subscriber = new TestObserver<>();
providersRxCache.getMocksArrayResponse(createObservableMocksArray(SIZE)).subscribe(subscriber);
subscriber.awaitTerminalEvent();
Reply<io.rx_cache2.internal.Mock[]> reply = subscriber.values().get(0);
Type type = new TypeToken<Reply<io.rx_cache2.internal.Mock[]>>() {
}.getType();
Reply<io.rx_cache2.internal.Mock[]> replyOriginal = (Reply<io.rx_cache2.internal.Mock[]>) deepCopy(reply, type);
assertThat(compare(reply, replyOriginal, type), is(true));
reply.getData()[0].setMessage("modified");
assertThat(compare(reply, replyOriginal, type), is(false));
subscriber = new TestObserver<>();
providersRxCache.getMocksArrayResponse(ProviderHelper.<io.rx_cache2.internal.Mock[]>withoutLoader()).subscribe(subscriber);
subscriber.awaitTerminalEvent();
assertThat(subscriber.errors().size(), is(0));
assertThat(subscriber.values().size(), is(1));
reply = subscriber.values().get(0);
type = new TypeToken<io.rx_cache2.internal.Mock[]>() {
}.getType();
assertThat(compare(reply.getData(), replyOriginal.getData(), type), is(true));
}
@Test
public void _12_When_Retrieve_Cached_Data_After_Modified_Object_On_Item_Map_Then_Object_Preserves_Initial_State() {
initProviders(false);
TestObserver<Reply<Map<Integer, io.rx_cache2.internal.Mock>>> subscriber;
subscriber = new TestObserver<>();
providersRxCache.getMocksMapResponse(createObservableMocksMap(SIZE)).subscribe(subscriber);
subscriber.awaitTerminalEvent();
Reply<Map<Integer, io.rx_cache2.internal.Mock>> reply = subscriber.values().get(0);
Type type = new TypeToken<Reply<Map<Integer, io.rx_cache2.internal.Mock>>>() {
}.getType();
Reply<Map<Integer, io.rx_cache2.internal.Mock>> replyOriginal = (Reply<Map<Integer, io.rx_cache2.internal.Mock>>) deepCopy(reply, type);
assertThat(compare(reply, replyOriginal, type), is(true));
reply.getData().get(0).setMessage("modified");
assertThat(compare(reply, replyOriginal, type), is(false));
subscriber = new TestObserver<>();
providersRxCache.getMocksMapResponse(ProviderHelper.<Map<Integer, io.rx_cache2.internal.Mock>>withoutLoader())
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
assertThat(subscriber.errors().size(), is(0));
assertThat(subscriber.values().size(), is(1));
reply = subscriber.values().get(0);
type = new TypeToken<Map<Integer, io.rx_cache2.internal.Mock>>() {
}.getType();
assertThat(compare(reply.getData(), replyOriginal.getData(), type), is(true));
}
@Test
public void _13_When_Retrieve_Cached_Data_After_Modified_Object_Then_Object_Preserves_Initial_State() {
initProviders(false);
TestObserver<io.rx_cache2.internal.Mock> subscriber;
subscriber = new TestObserver<>();
providersRxCache.getLoggedMock(Observable.<io.rx_cache2.internal.Mock>just(createMocks(SIZE).get(0)),
new EvictProvider(true)).subscribe(subscriber);
subscriber.awaitTerminalEvent();
io.rx_cache2.internal.Mock mock = subscriber.values().get(0);
Type type = new TypeToken<io.rx_cache2.internal.Mock>() {
}.getType();
io.rx_cache2.internal.Mock mockOriginal = (io.rx_cache2.internal.Mock) deepCopy(mock, type);
assertThat(compare(mock, mockOriginal, type), is(true));
mock.setMessage("modified");
assertThat(compare(mock, mockOriginal, type), is(false));
subscriber = new TestObserver<>();
providersRxCache.getLoggedMock(ProviderHelper.<io.rx_cache2.internal.Mock>withoutLoader(), new EvictProvider(false))
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
assertThat(subscriber.errors().size(), is(0));
assertThat(subscriber.values().size(), is(1));
mock = subscriber.values().get(0);
assertThat(compare(mock, mockOriginal, type), is(true));
}
@Test public void _14_When_0_Is_The_Value_For_Life_Time_Not_Cached_Ad_Infinitum() {
initProviders(false);
TestObserver<Reply<List<io.rx_cache2.internal.Mock>>> subscriber;
subscriber = new TestObserver<>();
providersRxCache.getMocksLife0Minutes(createObservableMocks(10)).subscribe(subscriber);
subscriber.awaitTerminalEvent();
Reply<List<io.rx_cache2.internal.Mock>> reply = subscriber.values().get(0);
assertThat(reply.getSource(), is(Source.CLOUD));
subscriber = new TestObserver<>();
providersRxCache.getMocksLife0Minutes(createObservableMocks(10)).subscribe(subscriber);
subscriber.awaitTerminalEvent();
reply = subscriber.values().get(0);
assertThat(reply.getSource(), is(Source.CLOUD));
}
@Test public void _15_When_Evict_All_Evict_All() {
initProviders(false);
TestObserver<Void> subscriberEvict = new TestObserver<>();
rxCache.evictAll().subscribe(subscriberEvict);
subscriberEvict.awaitTerminalEvent();
for (int i = 0; i < SIZE; i++) {
TestObserver<List<io.rx_cache2.internal.Mock>> subscriber = new TestObserver<>();
providersRxCache.getMocksPaginate(createObservableMocks(1), new DynamicKey(i))
.subscribe(subscriber);
subscriber.awaitTerminalEvent();
}
assertThat(temporaryFolder.getRoot().listFiles().length, is(SIZE));
subscriberEvict = new TestObserver<>();
rxCache.evictAll().subscribe(subscriberEvict);
subscriberEvict.awaitTerminalEvent();
subscriberEvict.assertComplete();
subscriberEvict.assertNoErrors();
subscriberEvict.assertNoValues();
assertThat(temporaryFolder.getRoot().listFiles().length, is(0));
}
private Object deepCopy(Object object, Type type) {
return new Gson().fromJson(new Gson().toJson(object), type);
}
private boolean compare(Object object1, Object object2, Type type) {
return new Gson().toJson(object1, type).equals(new Gson().toJson(object2, type));
}
private void waitTime(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private Observable<List<io.rx_cache2.internal.Mock>> createObservableMocks(int size) {
long currentTime = System.currentTimeMillis();
List<io.rx_cache2.internal.Mock> mocks = new ArrayList(size);
for (int i = 0; i < size; i++) {
mocks.add(new io.rx_cache2.internal.Mock("mock" + currentTime));
}
return Observable.just(mocks);
}
private Observable<Map<Integer, io.rx_cache2.internal.Mock>> createObservableMocksMap(int size) {
long currentTime = System.currentTimeMillis();
Map<Integer, io.rx_cache2.internal.Mock> mocks = new HashMap<>();
for (int i = 0; i < size; i++) {
mocks.put(i, new io.rx_cache2.internal.Mock("mock" + currentTime));
}
return Observable.just(mocks);
}
private Observable<io.rx_cache2.internal.Mock[]> createObservableMocksArray(int size) {
return createObservableMocks(size)
.map(new Function<List<io.rx_cache2.internal.Mock>, io.rx_cache2.internal.Mock[]>() {
@Override
public io.rx_cache2.internal.Mock[] apply(List<io.rx_cache2.internal.Mock> mockList) throws Exception {
return mockList.toArray(new io.rx_cache2.internal.Mock[mockList.size()]);
}
});
}
private List<io.rx_cache2.internal.Mock> createMocks(int size) {
long currentTime = System.currentTimeMillis();
List<io.rx_cache2.internal.Mock> mocks = new ArrayList(size);
for (int i = 0; i < size; i++) {
mocks.add(new io.rx_cache2.internal.Mock("mock" + currentTime));
}
return mocks;
}
}