/*******************************************************************************
* (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Apache License v2.0 which accompany this distribution.
*
* The Apache License is available at
* http://www.apache.org/licenses/LICENSE-2.0
*
*******************************************************************************/
package io.cloudslang.lang.compiler.caching;
import com.google.common.cache.Cache;
import io.cloudslang.lang.compiler.SlangSource;
import io.cloudslang.lang.compiler.modeller.result.ExecutableModellingResult;
import java.lang.reflect.Field;
import junit.framework.Assert;
import org.apache.commons.lang3.tuple.MutablePair;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import static io.cloudslang.lang.compiler.caching.CacheValueState.OUTDATED;
import static io.cloudslang.lang.compiler.caching.CacheValueState.VALID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.same;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
/**
* @author Bonczidai Levente
* @since 11/13/2016
*/
@RunWith(MockitoJUnitRunner.class)
public class CachedPrecompileServiceImplTest {
public static final String CACHE = "cache";
@Spy
@InjectMocks
private CachedPrecompileServiceImpl cachedPrecompileServiceImpl;
@Mock
private Cache<String, CacheValue> cache;
@Test
public void testCacheValueSuccess() {
String myPath = "aaa";
ExecutableModellingResult executableModellingResult = mock(ExecutableModellingResult.class);
SlangSource slangSource = mock(SlangSource.class);
final MutablePair<CacheValue, Boolean> pair = new MutablePair<>();
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
pair.setLeft((CacheValue) invocation.getArguments()[1]);
return null;
}
}).when(cache).put(anyString(), any(CacheValue.class));
// Tested call
cachedPrecompileServiceImpl.cacheValue(myPath, executableModellingResult, slangSource);
verify(cache).put(eq(myPath), same(pair.getLeft()));
}
@Test
public void testCacheValueDoesNothingForNull() {
String myPath = null;
ExecutableModellingResult executableModellingResult = mock(ExecutableModellingResult.class);
SlangSource slangSource = mock(SlangSource.class);
final MutablePair<CacheValue, Boolean> pair = new MutablePair<>();
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
pair.setLeft((CacheValue) invocation.getArguments()[1]);
return null;
}
}).when(cache).put(anyString(), any(CacheValue.class));
// Tested call
cachedPrecompileServiceImpl.cacheValue(myPath, executableModellingResult, slangSource);
verify(cache, never()).put(anyString(), any(CacheValue.class));
}
@Test
public void testGetValueSuccessWithOutdated() {
final String myPath = "bb";
final SlangSource slangSource = mock(SlangSource.class);
SlangSource cachedSlangSource = mock(SlangSource.class);
CacheValue mockCacheValue = mock(CacheValue.class);
doReturn(mockCacheValue).when(cache).getIfPresent(anyObject());
doReturn(cachedSlangSource).when(mockCacheValue).getSource();
doReturn(true).when(cachedPrecompileServiceImpl)
.hasChangedSinceCached(any(SlangSource.class), any(SlangSource.class));
// Tested call
final CacheResult valueFromCache = cachedPrecompileServiceImpl.getValueFromCache(myPath, slangSource);
InOrder inOrder = Mockito.inOrder(cache, cachedPrecompileServiceImpl);
inOrder.verify(cache).getIfPresent(eq(myPath));
inOrder.verify(cachedPrecompileServiceImpl)
.hasChangedSinceCached(eq(slangSource), eq(cachedSlangSource));
inOrder.verifyNoMoreInteractions();
assertEquals(OUTDATED, valueFromCache.getState());
assertNull(valueFromCache.getExecutableModellingResult());
}
@Test
public void testGetValueSuccessWithValid() {
final String myPath = "cc";
final SlangSource slangSource = mock(SlangSource.class);
SlangSource cachedSlangSource = mock(SlangSource.class);
CacheValue mockCacheValue = mock(CacheValue.class);
doReturn(mockCacheValue).when(cache).getIfPresent(anyObject());
doReturn(cachedSlangSource).when(mockCacheValue).getSource();
doReturn(false).when(cachedPrecompileServiceImpl)
.hasChangedSinceCached(any(SlangSource.class), any(SlangSource.class));
ExecutableModellingResult mockExecutionModellingResult = mock(ExecutableModellingResult.class);
doReturn(mockExecutionModellingResult).when(mockCacheValue).getExecutableModellingResult();
// Tested call
final CacheResult valueFromCache = cachedPrecompileServiceImpl.getValueFromCache(myPath, slangSource);
InOrder inOrder = Mockito.inOrder(cache, cachedPrecompileServiceImpl);
inOrder.verify(cache).getIfPresent(eq(myPath));
inOrder.verify(cachedPrecompileServiceImpl)
.hasChangedSinceCached(eq(slangSource), eq(cachedSlangSource));
inOrder.verifyNoMoreInteractions();
assertEquals(VALID, valueFromCache.getState());
assertSame(mockExecutionModellingResult, valueFromCache.getExecutableModellingResult());
}
@Test
public void testInvalidateEntryWithRealPath() {
String myPath = "invalidatepath";
doNothing().when(cache).invalidate(anyString());
// Tested call
cachedPrecompileServiceImpl.invalidateEntry(myPath);
verify(cache).invalidate(eq(myPath));
}
@Test
public void testInvalidateEntryWithNullPath() {
doNothing().when(cache).invalidate(anyString());
// Tested call
cachedPrecompileServiceImpl.invalidateEntry(null);
verify(cache, never()).invalidate(anyString());
}
@Test
public void testInvalidateAll() {
doNothing().when(cache).invalidateAll();
// Tested call
cachedPrecompileServiceImpl.invalidateAll();
verify(cache).invalidateAll();
}
@Test
public void testInvalidateAllThrowsException() {
RuntimeException whatever = new RuntimeException("whatever");
doThrow(whatever).when(cache).invalidateAll();
// Tested call
try {
cachedPrecompileServiceImpl.invalidateAll();
fail("Expecting to throw exception");
} catch (Exception exc) {
assertSame(whatever, exc);
}
}
@Test
public void testInit() throws Exception {
CachedPrecompileServiceImpl cachedPrecompileService = new CachedPrecompileServiceImpl();
cachedPrecompileService.init();
Class<? extends CachedPrecompileServiceImpl> cachePrecompileClass = cachedPrecompileService.getClass();
Field cachePrecompileClassField = cachePrecompileClass.getDeclaredField(CACHE);
cachePrecompileClassField.setAccessible(true);
@SuppressWarnings("unchecked")
Cache<String, CacheValue> internalCache = (Cache<String, CacheValue>) cachePrecompileClassField
.get(cachedPrecompileService);
Assert.assertNotNull(internalCache);
}
}