/*
* Copyright 2014 Netflix, Inc.
*
* 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 com.netflix.ribbon.evache;
import com.netflix.evcache.EVCache;
import com.netflix.evcache.EVCacheException;
import com.netflix.evcache.EVCacheImpl;
import com.netflix.evcache.EVCacheTranscoder;
import com.netflix.ribbon.testutils.TestUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.api.easymock.annotation.Mock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import rx.Notification;
import rx.Observable;
import rx.Subscription;
import rx.functions.Func0;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static org.easymock.EasyMock.*;
import static org.powermock.api.easymock.PowerMock.*;
/**
* @author Tomasz Bak
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({EVCache.Builder.class, EVCacheImpl.class})
public class EvCacheProviderTest {
@Mock
private EVCacheImpl evCacheImplMock;
@Mock
private Future<String> cacheFutureMock;
@Mock
private EVCacheTranscoder<String> transcoderMock;
@Before
public void setUp() throws Exception {
PowerMock.mockStatic(EVCacheImpl.class);
expectNew(EVCacheImpl.class,
new Class[]{String.class, String.class, int.class, EVCacheTranscoder.class, boolean.class},
anyObject(String.class), anyObject(String.class), anyInt(), anyObject(EVCacheTranscoder.class), anyBoolean()
).andReturn(evCacheImplMock);
}
@Test
public void testAsynchronousAccessFromCache() throws Exception {
expect(evCacheImplMock.<String>getAsynchronous("test1")).andReturn(cacheFutureMock);
expect(cacheFutureMock.isDone()).andReturn(true);
expect(cacheFutureMock.isCancelled()).andReturn(false);
expect(cacheFutureMock.get()).andReturn("value1");
replayAll();
EvCacheOptions options = new EvCacheOptions("testApp", "test-cache", true, 100, null, "test{id}");
EvCacheProvider<Object> cacheProvider = new EvCacheProvider<Object>(options);
Observable<Object> cacheValue = cacheProvider.get("test1", null);
assertEquals("value1", cacheValue.toBlocking().first());
}
@Test
public void testAsynchronousAccessWithTranscoderFromCache() throws Exception {
expect(evCacheImplMock.getAsynchronous("test1", transcoderMock)).andReturn(cacheFutureMock);
expect(cacheFutureMock.isDone()).andReturn(true);
expect(cacheFutureMock.isCancelled()).andReturn(false);
expect(cacheFutureMock.get()).andReturn("value1");
replayAll();
EvCacheOptions options = new EvCacheOptions("testApp", "test-cache", true, 100, transcoderMock, "test{id}");
EvCacheProvider<Object> cacheProvider = new EvCacheProvider<Object>(options);
Observable<Object> cacheValue = cacheProvider.get("test1", null);
assertEquals("value1", cacheValue.toBlocking().first());
}
@Test
public void testCacheMiss() throws Exception {
expect(evCacheImplMock.<String>getAsynchronous("test1")).andReturn(cacheFutureMock);
expect(cacheFutureMock.isDone()).andReturn(true);
expect(cacheFutureMock.isCancelled()).andReturn(false);
expect(cacheFutureMock.get()).andReturn(null);
replayAll();
EvCacheOptions options = new EvCacheOptions("testApp", "test-cache", true, 100, null, "test{id}");
EvCacheProvider<Object> cacheProvider = new EvCacheProvider<Object>(options);
Observable<Object> cacheValue = cacheProvider.get("test1", null);
assertTrue(cacheValue.materialize().toBlocking().first().getThrowable() instanceof CacheMissException);
}
@Test
public void testFailedAsynchronousAccessFromCache() throws Exception {
expect(evCacheImplMock.<String>getAsynchronous("test1")).andThrow(new EVCacheException("cache error"));
replayAll();
EvCacheOptions options = new EvCacheOptions("testApp", "test-cache", true, 100, null, "test{id}");
EvCacheProvider<Object> cacheProvider = new EvCacheProvider<Object>(options);
Observable<Object> cacheValue = cacheProvider.get("test1", null);
Notification<Object> notification = cacheValue.materialize().toBlocking().first();
assertTrue(notification.getThrowable() instanceof CacheFaultException);
}
@Test
public void testCanceledFuture() throws Exception {
expect(evCacheImplMock.getAsynchronous("test1", transcoderMock)).andReturn(cacheFutureMock);
expect(cacheFutureMock.isDone()).andReturn(true);
expect(cacheFutureMock.isCancelled()).andReturn(true);
replayAll();
EvCacheOptions options = new EvCacheOptions("testApp", "test-cache", true, 100, transcoderMock, "test{id}");
EvCacheProvider<Object> cacheProvider = new EvCacheProvider<Object>(options);
Observable<Object> cacheValue = cacheProvider.get("test1", null);
assertTrue(cacheValue.materialize().toBlocking().first().getThrowable() instanceof CacheFaultException);
}
@Test
public void testExceptionResultInFuture() throws Exception {
expect(evCacheImplMock.getAsynchronous("test1", transcoderMock)).andReturn(cacheFutureMock);
expect(cacheFutureMock.isDone()).andReturn(true);
expect(cacheFutureMock.isCancelled()).andReturn(false);
expect(cacheFutureMock.get()).andThrow(new ExecutionException(new RuntimeException("operation failed")));
replayAll();
EvCacheOptions options = new EvCacheOptions("testApp", "test-cache", true, 100, transcoderMock, "test{id}");
EvCacheProvider<Object> cacheProvider = new EvCacheProvider<Object>(options);
Observable<Object> cacheValue = cacheProvider.get("test1", null);
assertTrue(cacheValue.materialize().toBlocking().first().getThrowable() instanceof RuntimeException);
}
@Test
public void testUnsubscribedBeforeFutureCompletes() throws Exception {
expect(evCacheImplMock.getAsynchronous("test1", transcoderMock)).andReturn(cacheFutureMock);
expect(cacheFutureMock.cancel(true)).andReturn(true);
replayAll();
EvCacheOptions options = new EvCacheOptions("testApp", "test-cache", true, 100, transcoderMock, "test{id}");
EvCacheProvider<Object> cacheProvider = new EvCacheProvider<Object>(options);
Observable<Object> cacheValue = cacheProvider.get("test1", null);
Subscription subscription = cacheValue.subscribe();
subscription.unsubscribe();
TestUtils.waitUntilTrueOrTimeout(10000, new Func0<Boolean>() {
@Override
public Boolean call() {
try {
verifyAll();
return true;
} catch (Throwable e) {
e.printStackTrace();
return false;
}
}
});
}
}