/*
* Copyright 2011-2013 the original author or authors.
*
* 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 org.springframework.data.gemfire;
import static org.assertj.core.api.Assertions.*;
import static org.hamcrest.Matchers.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.geode.GemFireCheckedException;
import org.apache.geode.GemFireException;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.RegionService;
import org.apache.geode.cache.Scope;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.query.Query;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.cache.query.SelectResults;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.gemfire.test.support.AbstractUnitAndIntegrationTestsWithMockSupport;
/**
* Unit tests for {@link GemfireTemplate}
*
* @author Costin Leau
* @author David Turanski
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.mockito.runners.MockitoJUnitRunner
* @see org.springframework.data.gemfire.GemfireTemplate
* @see AbstractUnitAndIntegrationTestsWithMockSupport
* @see org.springframework.data.gemfire.test.GemfireTestApplicationContextInitializer
* @see org.springframework.test.context.ContextConfiguration
*/
@RunWith(MockitoJUnitRunner.class)
@SuppressWarnings("unused")
public class GemfireTemplateUnitTests extends AbstractUnitAndIntegrationTestsWithMockSupport {
@Rule
public ExpectedException exception = ExpectedException.none();
private GemfireTemplate template;
@Mock
private Query mockQuery;
@Mock
private QueryService mockQueryService;
@Mock
private Region<?, ?> mockRegion;
@Mock
private RegionService mockRegionService;
@Before
public void setUp() throws Exception {
when(mockRegion.getRegionService()).thenReturn(mockRegionService);
when(mockRegionService.getQueryService()).thenReturn(mockQueryService);
when(mockQueryService.newQuery(anyString())).thenReturn(mockQuery);
template = new GemfireTemplate(mockRegion);
}
@Test
public void constructWithNonNullRegionIsSuccessful() {
GemfireTemplate localTemplate = new GemfireTemplate(mockRegion);
assertThat(localTemplate).isNotNull();
assertThat(localTemplate.getRegion()).isSameAs(mockRegion);
assertThat(localTemplate.isExposeNativeRegion()).isFalse();
}
@Test
public void constructWithNullRegionThrowsIllegalArgumentException() {
exception.expect(IllegalArgumentException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage("Region is required");
new GemfireTemplate(null);
}
@Test
public void executeWithGemfireCallbackUsesNativeRegion() {
template.setExposeNativeRegion(true);
assertThat(template.isExposeNativeRegion()).isTrue();
assertThat(template.getRegion()).isSameAs(mockRegion);
final AtomicBoolean callbackInvoked = new AtomicBoolean(false);
template.execute(new GemfireCallback<Object>() {
@Override
public Object doInGemfire(Region<?, ?> region) throws GemFireCheckedException, GemFireException {
callbackInvoked.set(true);
assertThat(region).isSameAs(mockRegion);
return null;
}
});
assertThat(callbackInvoked.get()).isTrue();
}
@Test
public void executeWithGemfireCallbackUsesProxyRegion() {
assertThat(template.isExposeNativeRegion()).isFalse();
final AtomicBoolean callbackInvoked = new AtomicBoolean(false);
template.execute(new GemfireCallback<Object>() {
@Override
public Object doInGemfire(Region<?, ?> region) throws GemFireCheckedException, GemFireException {
callbackInvoked.set(true);
assertThat(region).isNotSameAs(mockRegion);
return null;
}
});
assertThat(callbackInvoked.get()).isTrue();
}
@Test
public void queryCallsRegionQuery() throws Exception {
String expectedQuery = "SELECT * FROM /Example";
template.query(expectedQuery);
verify(mockRegion, times(1)).query(eq(expectedQuery));
}
@Test
public void findIsSuccessful() throws Exception {
Object[] expectedParams = { "arg" };
String expectedQuery = "SELECT * FROM /Example";
SelectResults mockSelectResults = mock(SelectResults.class);
when(mockQuery.execute(any(Object[].class))).thenReturn(mockSelectResults);
assertThat(template.find(expectedQuery, expectedParams)).isEqualTo(mockSelectResults);
verify(mockRegion, atLeastOnce()).getRegionService();
verify(mockRegionService, times(1)).getQueryService();
verify(mockQueryService, times(1)).newQuery(eq(expectedQuery));
verify(mockQuery, times(1)).execute(eq(expectedParams));
verifyZeroInteractions(mockSelectResults);
}
@Test(expected = InvalidDataAccessApiUsageException.class)
public void findWithSingleResultQueryThrowsInvalidDataAccessApiUsageException() throws Exception {
Object[] expectedParams = { "arg" };
String expectedQuery = "SELECT 1 FROM /Example";
when(mockQuery.execute(any(Object[].class))).thenReturn(1);
try {
template.find(expectedQuery, expectedParams);
}
finally {
verify(mockRegion, atLeastOnce()).getRegionService();
verify(mockRegionService, times(1)).getQueryService();
verify(mockQueryService, times(1)).newQuery(eq(expectedQuery));
verify(mockQuery, times(1)).execute(eq(expectedParams));
}
}
@Test
public void findUniqueReturnsSelectResultsIsSuccessful() throws Exception {
Object[] expectedParams = { "arg" };
String expectedQuery = "SELECT 1 FROM /Example";
SelectResults mockSelectResults = mock(SelectResults.class);
when(mockQuery.execute(eq(expectedParams))).thenReturn(mockSelectResults);
when(mockSelectResults.asList()).thenReturn(Collections.singletonList(1));
assertThat(template.<Integer>findUnique(expectedQuery, expectedParams)).isEqualTo(1);
verify(mockRegion, atLeastOnce()).getRegionService();
verify(mockRegionService, times(1)).getQueryService();
verify(mockQueryService, times(1)).newQuery(eq(expectedQuery));
verify(mockQuery, times(1)).execute(eq(expectedParams));
verify(mockSelectResults, times(1)).asList();
}
@Test
public void findUniqueReturnsObjectIsSuccessful() throws Exception {
Object[] expectedParams = { "arg" };
String expectedQuery = "SELECT 1 FROM /Example";
when(mockQuery.execute(eq(expectedParams))).thenReturn("test");
assertThat(template.<String>findUnique(expectedQuery, expectedParams)).isEqualTo("test");
verify(mockRegion, atLeastOnce()).getRegionService();
verify(mockRegionService, times(1)).getQueryService();
verify(mockQueryService, times(1)).newQuery(eq(expectedQuery));
verify(mockQuery, times(1)).execute(eq(expectedParams));
}
@Test(expected = InvalidDataAccessApiUsageException.class)
public void findUniqueWithMultiResultQueryThrowsInvalidDataAccessApiUsageException() throws Exception {
Object[] expectedParams = { "arg" };
String expectedQuery = "SELECT 1 FROM /Example";
SelectResults mockSelectResults = mock(SelectResults.class);
when(mockQuery.execute(eq(expectedParams))).thenReturn(mockSelectResults);
when(mockSelectResults.asList()).thenReturn(Arrays.asList(1, 2));
try {
assertThat(template.<Integer>findUnique(expectedQuery, expectedParams)).isEqualTo(1);
}
finally {
verify(mockRegion, atLeastOnce()).getRegionService();
verify(mockRegionService, times(1)).getQueryService();
verify(mockQueryService, times(1)).newQuery(eq(expectedQuery));
verify(mockQuery, times(1)).execute(eq(expectedParams));
verify(mockSelectResults, times(1)).asList();
}
}
@Test
@SuppressWarnings("unchecked")
public void resolveClientQueryService() {
ClientCache mockClientCache = mock(ClientCache.class);
Region<Object, Object> mockRegion = mock(Region.class);
RegionAttributes<Object, Object> mockRegionAttributes = mock(RegionAttributes.class);
when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
when(mockRegionAttributes.getScope()).thenReturn(Scope.GLOBAL);
when(mockRegion.getRegionService()).thenReturn(mockClientCache);
when(mockClientCache.getQueryService()).thenReturn(mockQueryService);
GemfireTemplate localTemplate = new GemfireTemplate(mockRegion) {
@Override boolean isLocalWithNoServerProxy(Region<?, ?> region) {
return false;
}
};
assertThat(localTemplate.resolveQueryService(mockRegion)).isSameAs(mockQueryService);
verify(mockClientCache, never()).getLocalQueryService();
verify(mockClientCache, times(1)).getQueryService();
verify(mockClientCache, never()).getQueryService(anyString());
verify(mockRegion, times(2)).getAttributes();
verify(mockRegion, times(3)).getRegionService();
verify(mockRegionAttributes, times(1)).getScope();
verifyZeroInteractions(mockQueryService);
}
@Test
@SuppressWarnings("unchecked")
public void resolvesClientLocalQueryService() {
ClientCache mockClientCache = mock(ClientCache.class);
Region<Object, Object> mockRegion = mock(Region.class);
RegionAttributes<Object, Object> mockRegionAttributes = mock(RegionAttributes.class);
when(mockClientCache.getLocalQueryService()).thenReturn(mockQueryService);
when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
when(mockRegion.getRegionService()).thenReturn(mockClientCache);
when(mockRegionAttributes.getScope()).thenReturn(Scope.LOCAL);
GemfireTemplate localTemplate = new GemfireTemplate(mockRegion) {
@Override boolean isLocalWithNoServerProxy(Region<?, ?> region) {
return true;
}
};
assertThat(localTemplate.resolveQueryService(mockRegion)).isSameAs(mockQueryService);
verify(mockClientCache, times(1)).getLocalQueryService();
verify(mockClientCache, never()).getQueryService();
verify(mockClientCache, never()).getQueryService(anyString());
verify(mockRegion, times(2)).getRegionService();
verify(mockRegionAttributes, times(1)).getScope();
verifyZeroInteractions(mockQueryService);
}
@Test
@SuppressWarnings("unchecked")
public void resolvesClientPooledQueryService() {
ClientCache mockClientCache = mock(ClientCache.class);
Region<Object, Object> mockRegion = mock(Region.class);
RegionAttributes<Object, Object> mockRegionAttributes = mock(RegionAttributes.class);
when(mockClientCache.getQueryService(anyString())).thenReturn(mockQueryService);
when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
when(mockRegion.getRegionService()).thenReturn(mockClientCache);
when(mockRegionAttributes.getPoolName()).thenReturn("TestPool");
when(mockRegionAttributes.getScope()).thenReturn(Scope.LOCAL);
GemfireTemplate localTemplate = new GemfireTemplate(mockRegion) {
@Override boolean isLocalWithNoServerProxy(Region<?, ?> region) {
return false;
}
};
assertThat(localTemplate.resolveQueryService(mockRegion)).isSameAs(mockQueryService);
verify(mockClientCache, never()).getLocalQueryService();
verify(mockClientCache, never()).getQueryService();
verify(mockClientCache, times(1)).getQueryService(eq("TestPool"));
verify(mockRegion, times(2)).getRegionService();
verify(mockRegionAttributes, times(2)).getPoolName();
verify(mockRegionAttributes, times(1)).getScope();
verifyZeroInteractions(mockQueryService);
}
@Test
public void resolvePeerQueryService() {
assertThat(template.resolveQueryService(mockRegion)).isEqualTo(mockQueryService);
verify(mockRegion, times(2)).getRegionService();
verify(mockRegion, never()).getAttributes();
verify(mockRegionService, times(1)).getQueryService();
}
}