SGF-423 - Handle improper ClassCastException thrown from SDG's Function Execution interface and annotation-based support when a GemFire Function throws an Exception.
Additional refactoring and added serveral unit tests. (cherry picked from commit a806f1540e6fc995410671f34382d14389ace90a) Signed-off-by: John Blum <jblum@pivotal.io>
This commit is contained in:
@@ -71,7 +71,9 @@ abstract class AbstractFunctionExecutionConfigurationSource implements FunctionE
|
||||
}
|
||||
|
||||
public Collection<ScannedGenericBeanDefinition> getCandidates(ResourceLoader loader) {
|
||||
ClassPathScanningCandidateComponentProvider scanner = new FunctionExecutionComponentProvider(getIncludeFilters(),functionExecutionAnnotationTypes);
|
||||
ClassPathScanningCandidateComponentProvider scanner = new FunctionExecutionComponentProvider(
|
||||
getIncludeFilters(), getFunctionExecutionAnnotationTypes());
|
||||
|
||||
scanner.setResourceLoader(loader);
|
||||
|
||||
for (TypeFilter filter : getExcludeFilters()) {
|
||||
@@ -84,9 +86,11 @@ abstract class AbstractFunctionExecutionConfigurationSource implements FunctionE
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("scanning package " + basePackage);
|
||||
}
|
||||
Collection<BeanDefinition> components = scanner.findCandidateComponents(basePackage);
|
||||
for (BeanDefinition definition : components) {
|
||||
result.add((ScannedGenericBeanDefinition)definition);
|
||||
|
||||
Collection<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
|
||||
|
||||
for (BeanDefinition beanDefinition : candidateComponents) {
|
||||
result.add((ScannedGenericBeanDefinition) beanDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
*/
|
||||
package org.springframework.data.gemfire.function.config;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
@@ -21,7 +19,6 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -52,7 +49,9 @@ class FunctionExecutionBeanDefinitionRegistrar implements ImportBeanDefinitionRe
|
||||
void registerBeanDefinitions(AbstractFunctionExecutionConfigurationSource functionExecutionConfigurationSource,
|
||||
BeanDefinitionRegistry registry) {
|
||||
|
||||
for (ScannedGenericBeanDefinition beanDefinition : functionExecutionConfigurationSource.getCandidates(new DefaultResourceLoader())) {
|
||||
for (ScannedGenericBeanDefinition beanDefinition : functionExecutionConfigurationSource.getCandidates(
|
||||
new DefaultResourceLoader())) {
|
||||
|
||||
String functionExecutionAnnotation = getFunctionExecutionAnnotation(beanDefinition,
|
||||
AnnotationFunctionExecutionConfigurationSource.getFunctionExecutionAnnotationTypeNames());
|
||||
|
||||
|
||||
@@ -31,6 +31,12 @@ class FunctionExecutionConfiguration {
|
||||
|
||||
private final String annotationType;
|
||||
|
||||
/* constructor for testing purposes only! */
|
||||
FunctionExecutionConfiguration() {
|
||||
this.annotationType = null;
|
||||
this.attributes = null;
|
||||
}
|
||||
|
||||
FunctionExecutionConfiguration(ScannedGenericBeanDefinition beanDefinition, String annotationType) {
|
||||
try {
|
||||
this.annotationType = annotationType;
|
||||
|
||||
@@ -44,7 +44,7 @@ abstract class ServerBasedExecutionBeanDefinitionBuilder extends AbstractFunctio
|
||||
String cache = (String) configuration.getAttribute("cache");
|
||||
String pool = (String) configuration.getAttribute("pool");
|
||||
|
||||
Assert.state(StringUtils.hasText(cache) && !(StringUtils.hasText(pool)), String.format(
|
||||
Assert.state(!(StringUtils.hasText(cache) && StringUtils.hasText(pool)), String.format(
|
||||
"invalid configuration for interface %s; cannot specify both 'pool' and 'cache'",
|
||||
configuration.getFunctionExecutionInterface().getName()));
|
||||
|
||||
|
||||
@@ -29,22 +29,27 @@ import com.gemstone.gemfire.cache.execute.FunctionService;
|
||||
import com.gemstone.gemfire.cache.execute.ResultCollector;
|
||||
|
||||
/**
|
||||
* Base class for * Creating a GemFire {@link Execution} using {@link FunctionService}
|
||||
* Protected setters support method chaining
|
||||
* @author David Turanski
|
||||
* Base class for * Creating a GemFire {@link Execution} using {@link FunctionService}. Protected setters support
|
||||
* method chaining.
|
||||
*
|
||||
* @author David Turanski
|
||||
* @author John Blum
|
||||
*/
|
||||
|
||||
abstract class AbstractFunctionExecution {
|
||||
|
||||
private final static String NO_RESULT_MESSAGE = "Cannot return any result as the Function#hasResult() is false";
|
||||
|
||||
private long timeout;
|
||||
|
||||
private Function function;
|
||||
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private volatile ResultCollector<?, ?> resultCollector;
|
||||
private Object[] args;
|
||||
private Function function;
|
||||
|
||||
private volatile ResultCollector<?, ?> resultCollector;
|
||||
|
||||
private String functionId;
|
||||
private long timeout;
|
||||
|
||||
public AbstractFunctionExecution(Function function, Object... args) {
|
||||
Assert.notNull(function, "function cannot be null");
|
||||
@@ -62,22 +67,22 @@ abstract class AbstractFunctionExecution {
|
||||
AbstractFunctionExecution() {
|
||||
}
|
||||
|
||||
ResultCollector<?, ?> getCollector() {
|
||||
return resultCollector;
|
||||
}
|
||||
|
||||
Object[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
String getFunctionId() {
|
||||
return functionId;
|
||||
ResultCollector<?, ?> getCollector() {
|
||||
return resultCollector;
|
||||
}
|
||||
|
||||
Function getFunction() {
|
||||
return function;
|
||||
}
|
||||
|
||||
String getFunctionId() {
|
||||
return functionId;
|
||||
}
|
||||
|
||||
long getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
@@ -88,33 +93,31 @@ abstract class AbstractFunctionExecution {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> Iterable<T> execute(Boolean returnResult) {
|
||||
Execution execution = this.getExecution();
|
||||
if (getKeys() != null) {
|
||||
execution = execution.withFilter(getKeys());
|
||||
}
|
||||
if (getCollector() != null) {
|
||||
execution = execution.withCollector(getCollector());
|
||||
}
|
||||
|
||||
ResultCollector<?, ?> resultCollector = null;
|
||||
Execution execution = getExecution();
|
||||
|
||||
execution = execution.withArgs(getArgs());
|
||||
execution = (getCollector() == null ? execution : execution.withCollector(getCollector()));
|
||||
execution = (getKeys() == null ? execution : execution.withFilter(getKeys()));
|
||||
|
||||
ResultCollector<?, ?> resultCollector;
|
||||
|
||||
if (isRegisteredFunction()) {
|
||||
resultCollector = (ResultCollector<?, ?>) execution.execute(functionId);
|
||||
} else {
|
||||
resultCollector = (ResultCollector<?, ?>) execution.execute(function);
|
||||
resultCollector = execution.execute(functionId);
|
||||
}
|
||||
else {
|
||||
resultCollector = execution.execute(function);
|
||||
|
||||
if (!function.hasResult()) {
|
||||
return (Iterable<T>) null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!returnResult) {
|
||||
return (Iterable<T>) null;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("using ResultsCollector:" + resultCollector.getClass().getName());
|
||||
logger.debug("using ResultsCollector " + resultCollector.getClass().getName());
|
||||
}
|
||||
|
||||
Iterable<T> results = null;
|
||||
@@ -123,41 +126,53 @@ abstract class AbstractFunctionExecution {
|
||||
if (this.timeout > 0) {
|
||||
try {
|
||||
results = (Iterable<T>) resultCollector.getResult(this.timeout, TimeUnit.MILLISECONDS);
|
||||
} catch (FunctionException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
catch (FunctionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
|
||||
catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
results = (Iterable<T>) resultCollector.getResult();
|
||||
}
|
||||
|
||||
return replaceSingletonNullCollectionWithEmptyList(results);
|
||||
|
||||
} catch (FunctionException e) {
|
||||
//TODO: Come up with a better way to determine that the function should not return a result;
|
||||
}
|
||||
catch (FunctionException e) {
|
||||
//TODO Come up with a better way to determine that the function should not return a result;
|
||||
if (!e.getMessage().equals(NO_RESULT_MESSAGE)) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> T executeAndExtract() {
|
||||
Iterable<T> results = this.execute();
|
||||
Iterable<T> results = execute();
|
||||
|
||||
if (results == null || !results.iterator().hasNext()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return results.iterator().next();
|
||||
Object result = results.iterator().next();
|
||||
|
||||
if (result instanceof Throwable) {
|
||||
throw new FunctionException(String.format("Execution of Function %1$s failed",
|
||||
(function != null ? function.getClass().getName() : String.format("with ID '%1$s'", functionId))),
|
||||
(Throwable) result);
|
||||
}
|
||||
|
||||
return (T) result;
|
||||
}
|
||||
|
||||
protected abstract Execution getExecution();
|
||||
|
||||
protected AbstractFunctionExecution setFunctionId(String functionId) {
|
||||
this.functionId = functionId;
|
||||
protected AbstractFunctionExecution setArgs(Object... args) {
|
||||
this.args = args;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -166,17 +181,8 @@ abstract class AbstractFunctionExecution {
|
||||
return this;
|
||||
}
|
||||
|
||||
protected AbstractFunctionExecution setArgs(Object... args) {
|
||||
this.args = args;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected Set<?> getKeys() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected AbstractFunctionExecution setTimeout(long timeout) {
|
||||
this.timeout = timeout;
|
||||
protected AbstractFunctionExecution setFunctionId(String functionId) {
|
||||
this.functionId = functionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -185,29 +191,33 @@ abstract class AbstractFunctionExecution {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
protected AbstractFunctionExecution setTimeout(long timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected Set<?> getKeys() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isRegisteredFunction() {
|
||||
return function == null;
|
||||
}
|
||||
|
||||
private <T> Iterable<T> replaceSingletonNullCollectionWithEmptyList(Iterable<T> results) {
|
||||
if (results == null) {
|
||||
return results;
|
||||
}
|
||||
Iterator<T> it = results.iterator();
|
||||
if (results != null) {
|
||||
Iterator<T> it = results.iterator();
|
||||
|
||||
if (!it.hasNext()) {
|
||||
return results;
|
||||
}
|
||||
if (!it.hasNext()) {
|
||||
return results;
|
||||
}
|
||||
|
||||
if (it.next() == null && !it.hasNext()) {
|
||||
return new ArrayList<T>();
|
||||
if (it.next() == null && !it.hasNext()) {
|
||||
return new ArrayList<T>();
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,100 +15,79 @@ package org.springframework.data.gemfire.function.execution;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.gemstone.gemfire.cache.execute.Execution;
|
||||
import com.gemstone.gemfire.cache.execute.Function;
|
||||
import com.gemstone.gemfire.cache.execute.ResultCollector;
|
||||
|
||||
/**
|
||||
*
|
||||
* The base class for Gemfire function templates used to invoke Gemfire functions
|
||||
* @author David Turanski
|
||||
* The base class for GemFire FunctionTemplates used to invoke GemFire Functions.
|
||||
*
|
||||
* @author David Turanski
|
||||
* @author John Blum
|
||||
* @see com.gemstone.gemfire.cache.execute.Function
|
||||
* @see com.gemstone.gemfire.cache.execute.ResultCollector
|
||||
*/
|
||||
abstract class AbstractFunctionTemplate implements GemfireFunctionOperations {
|
||||
abstract class AbstractFunctionTemplate implements GemfireFunctionOperations {
|
||||
|
||||
protected Log log = LogFactory.getLog(this.getClass());
|
||||
|
||||
|
||||
protected long timeout;
|
||||
|
||||
protected volatile ResultCollector<?, ?> resultCollector;
|
||||
|
||||
|
||||
@Override
|
||||
public <T> Iterable<T> execute(Function function, Object... args) {
|
||||
AbstractFunctionExecution functionExecution = getFunctionExecution()
|
||||
.setArgs(args)
|
||||
.setFunction(function);
|
||||
return execute(functionExecution);
|
||||
return execute(getFunctionExecution().setArgs(args).setFunction(function));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T executeAndExtract(Function function, Object... args) {
|
||||
AbstractFunctionExecution functionExecution = getFunctionExecution()
|
||||
.setArgs(args)
|
||||
.setFunction(function);
|
||||
|
||||
return this.<T> executeAndExtract(functionExecution);
|
||||
return executeAndExtract(getFunctionExecution().setArgs(args).setFunction(function));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Iterable<T> execute(String functionId, Object... args) {
|
||||
AbstractFunctionExecution functionExecution = getFunctionExecution()
|
||||
.setArgs(args)
|
||||
.setFunctionId(functionId);
|
||||
return execute(functionExecution);
|
||||
return execute(getFunctionExecution().setArgs(args).setFunctionId(functionId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeWithNoResult(String functionId, Object... args) {
|
||||
AbstractFunctionExecution functionExecution = getFunctionExecution()
|
||||
.setArgs(args)
|
||||
.setFunctionId(functionId);
|
||||
execute(functionExecution,false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T executeAndExtract(String functionId, Object... args) {
|
||||
AbstractFunctionExecution functionExecution = getFunctionExecution()
|
||||
.setArgs(args)
|
||||
.setFunctionId(functionId);
|
||||
return this.<T>executeAndExtract(functionExecution);
|
||||
return executeAndExtract(getFunctionExecution().setArgs(args).setFunctionId(functionId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeWithNoResult(String functionId, Object... args) {
|
||||
execute(getFunctionExecution().setArgs(args).setFunctionId(functionId), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T execute(GemfireFunctionCallback<T> callback) {
|
||||
Execution execution = getFunctionExecution().getExecution();
|
||||
return callback.doInGemfire(execution);
|
||||
return callback.doInGemfire(getFunctionExecution().getExecution());
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected <T> Iterable<T> execute(AbstractFunctionExecution execution) {
|
||||
execution.setTimeout(timeout)
|
||||
.setResultCollector(resultCollector);
|
||||
return execution.execute();
|
||||
return execution.setTimeout(timeout).setResultCollector(resultCollector).execute();
|
||||
}
|
||||
|
||||
protected <T> Iterable<T> execute(AbstractFunctionExecution execution, boolean returnResult) {
|
||||
execution.setTimeout(timeout)
|
||||
.setResultCollector(resultCollector);
|
||||
return execution.execute(returnResult);
|
||||
return execution.setTimeout(timeout).setResultCollector(resultCollector).execute(returnResult);
|
||||
}
|
||||
|
||||
|
||||
protected <T> T executeAndExtract(AbstractFunctionExecution execution) {
|
||||
execution.setTimeout(timeout)
|
||||
.setResultCollector(resultCollector);
|
||||
return execution.<T>executeAndExtract();
|
||||
return execution.setTimeout(timeout).setResultCollector(resultCollector).executeAndExtract();
|
||||
}
|
||||
|
||||
public void setTimeout(long timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
|
||||
public void setResultCollector(ResultCollector<?,?> resultCollector) {
|
||||
this.resultCollector = resultCollector;
|
||||
}
|
||||
|
||||
|
||||
public ResultCollector<?,?> getResultCollector() {
|
||||
return this.resultCollector;
|
||||
}
|
||||
|
||||
|
||||
public void setTimeout(long timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
protected abstract AbstractFunctionExecution getFunctionExecution();
|
||||
|
||||
}
|
||||
|
||||
@@ -75,9 +75,8 @@ public class GemfireFunctionProxyFactoryBean implements FactoryBean<Object>, Met
|
||||
|
||||
@Override
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
|
||||
if (AopUtils.isToStringMethod(invocation.getMethod())) {
|
||||
return "Gemfire function proxy for service interface [" + this.functionExecutionInterface + "]";
|
||||
return "GemFire Function Proxy for service interface [" + this.functionExecutionInterface + "]";
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
|
||||
@@ -18,30 +18,26 @@ import com.gemstone.gemfire.cache.client.Pool;
|
||||
|
||||
/**
|
||||
* @author David Turanski
|
||||
*
|
||||
* @author John Blum
|
||||
*/
|
||||
public class GemfireOnServerFunctionTemplate extends AbstractFunctionTemplate {
|
||||
|
||||
private final RegionService cache;
|
||||
private final Pool pool;
|
||||
|
||||
|
||||
public GemfireOnServerFunctionTemplate (RegionService cache) {
|
||||
private final Pool pool;
|
||||
private final RegionService cache;
|
||||
|
||||
public GemfireOnServerFunctionTemplate(RegionService cache) {
|
||||
this.cache = cache;
|
||||
this.pool = null;
|
||||
}
|
||||
|
||||
public GemfireOnServerFunctionTemplate (Pool pool) {
|
||||
this.pool = pool;
|
||||
public GemfireOnServerFunctionTemplate(Pool pool) {
|
||||
this.cache = null;
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected AbstractFunctionExecution getFunctionExecution() {
|
||||
if (this.pool == null) {
|
||||
return new ServerFunctionExecution(this.cache);
|
||||
}
|
||||
return new PoolServerFunctionExecution(this.pool);
|
||||
return (pool != null ? new PoolServerFunctionExecution(this.pool) : new ServerFunctionExecution(this.cache));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,20 +24,17 @@ import com.gemstone.gemfire.cache.execute.FunctionService;
|
||||
*
|
||||
*/
|
||||
class ServerFunctionExecution extends AbstractFunctionExecution {
|
||||
|
||||
|
||||
private RegionService regionService;
|
||||
private final RegionService regionService;
|
||||
|
||||
|
||||
public ServerFunctionExecution(RegionService regionService) {
|
||||
super();
|
||||
Assert.notNull(regionService,"regionService cannot be null");
|
||||
Assert.notNull(regionService, "RegionService must not be null");
|
||||
this.regionService = regionService;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected Execution getExecution() {
|
||||
return FunctionService.onServer(this.regionService);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2010-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.function;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.isA;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.gemfire.fork.ServerProcess;
|
||||
import org.springframework.data.gemfire.function.annotation.GemfireFunction;
|
||||
import org.springframework.data.gemfire.function.sample.ExceptionThrowingFunctionExecution;
|
||||
import org.springframework.data.gemfire.process.ProcessExecutor;
|
||||
import org.springframework.data.gemfire.process.ProcessWrapper;
|
||||
import org.springframework.data.gemfire.test.support.FileSystemUtils;
|
||||
import org.springframework.data.gemfire.test.support.ThreadUtils;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.gemstone.gemfire.cache.execute.FunctionAdapter;
|
||||
import com.gemstone.gemfire.cache.execute.FunctionContext;
|
||||
import com.gemstone.gemfire.cache.execute.FunctionException;
|
||||
|
||||
/**
|
||||
* The ExceptionThrowingFunctionExecutionIntegrationTest class is a test suite of test cases testing the invocation
|
||||
* of a GemFire Function using Spring Data GemFire Function Execution Annotation support when that Function throws
|
||||
* an Exception.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Rule
|
||||
* @see org.junit.Test
|
||||
* @see org.junit.runner.RunWith
|
||||
* @see org.springframework.data.gemfire.fork.ServerProcess
|
||||
* @see org.springframework.data.gemfire.function.annotation.GemfireFunction
|
||||
* @see org.springframework.data.gemfire.function.sample.ExceptionThrowingFunctionExecution
|
||||
* @see org.springframework.data.gemfire.process.ProcessExecutor
|
||||
* @see org.springframework.data.gemfire.process.ProcessWrapper
|
||||
* @see org.springframework.test.context.ContextConfiguration
|
||||
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
|
||||
* @since 1.7.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@SuppressWarnings("unused")
|
||||
public class ExceptionThrowingFunctionExecutionIntegrationTest {
|
||||
|
||||
private static ProcessWrapper serverProcess;
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
@Autowired
|
||||
private ExceptionThrowingFunctionExecution exceptionThrowingFunctionExecution;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() throws IOException {
|
||||
String serverName = ExceptionThrowingFunctionExecutionIntegrationTest.class.getSimpleName().concat("Server");
|
||||
|
||||
File serverWorkingDirectory = new File(FileSystemUtils.WORKING_DIRECTORY, serverName.toLowerCase());
|
||||
|
||||
Assert.isTrue(serverWorkingDirectory.isDirectory() || serverWorkingDirectory.mkdirs());
|
||||
|
||||
List<String> arguments = new ArrayList<String>();
|
||||
|
||||
arguments.add("-Dgemfire.name=" + serverName);
|
||||
arguments.add(ExceptionThrowingFunctionExecutionIntegrationTest.class.getName().replaceAll("\\.",
|
||||
File.separator)
|
||||
.concat("-server-context.xml"));
|
||||
|
||||
serverProcess = ProcessExecutor.launch(serverWorkingDirectory, ServerProcess.class,
|
||||
arguments.toArray(new String[arguments.size()]));
|
||||
|
||||
waitForServerStart(TimeUnit.SECONDS.toMillis(20));
|
||||
|
||||
System.out.println("GemFire Cache Server Process for ClientCache Indexing should be running...");
|
||||
}
|
||||
|
||||
private static void waitForServerStart(final long milliseconds) {
|
||||
ThreadUtils.timedWait(milliseconds, TimeUnit.MILLISECONDS.toMillis(500), new ThreadUtils.WaitCondition() {
|
||||
private File serverPidControlFile = new File(serverProcess.getWorkingDirectory(),
|
||||
ServerProcess.getServerProcessControlFilename());
|
||||
|
||||
@Override public boolean waiting() {
|
||||
return !serverPidControlFile.isFile();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDown() {
|
||||
serverProcess.shutdown();
|
||||
|
||||
if (Boolean.valueOf(System.getProperty("spring.gemfire.fork.clean", Boolean.TRUE.toString()))) {
|
||||
org.springframework.util.FileSystemUtils.deleteRecursively(serverProcess.getWorkingDirectory());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exceptionThrowingFunctionExecutionRethrowsException() {
|
||||
expectedException.expect(FunctionException.class);
|
||||
expectedException.expectCause(isA(IllegalArgumentException.class));
|
||||
expectedException.expectMessage(containsString("Execution of Function with ID 'exceptionThrowingFunction' failed"));
|
||||
exceptionThrowingFunctionExecution.exceptionThrowingFunction();
|
||||
}
|
||||
|
||||
public static class ExceptionThrowingFunction extends FunctionAdapter {
|
||||
@Override
|
||||
public String getId() {
|
||||
return "exceptionThrowingFunction";
|
||||
}
|
||||
@Override
|
||||
public void execute(final FunctionContext context) {
|
||||
context.getResultSender().sendException(new IllegalArgumentException("TEST"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright 2010-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.function.config;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.data.gemfire.config.GemfireConstants;
|
||||
|
||||
/**
|
||||
* The ServerBasedExecutionBeanDefinitionBuilderTest class is test suite of test cases testing the contract
|
||||
* and functionality of the ServerBasedExecutionBeanDefinitionBuilder class.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.data.gemfire.function.config.ServerBasedExecutionBeanDefinitionBuilder
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public class ServerBasedExecutionBeanDefinitionBuilderTest {
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getGemfireFunctionOperationsBeanDefinitionBuilder() {
|
||||
FunctionExecutionConfiguration mockFunctionExecutionConfiguration =
|
||||
mock(FunctionExecutionConfiguration.class, "MockFunctionExecutionConfiguration");
|
||||
|
||||
when(mockFunctionExecutionConfiguration.getAttribute(eq("cache"))).thenReturn(null);
|
||||
when(mockFunctionExecutionConfiguration.getAttribute(eq("pool"))).thenReturn(" ");
|
||||
when(mockFunctionExecutionConfiguration.getFunctionExecutionInterface()).thenAnswer(new Answer<Class<?>>() {
|
||||
@Override public Class<?> answer(final InvocationOnMock invocation) throws Throwable {
|
||||
return Object.class;
|
||||
}
|
||||
});
|
||||
|
||||
ServerBasedExecutionBeanDefinitionBuilder builder = new ServerBasedExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) {
|
||||
@Override protected Class<?> getGemfireFunctionOperationsClass() {
|
||||
return Object.class;
|
||||
}
|
||||
};
|
||||
|
||||
BeanDefinitionBuilder beanDefinitionBuilder = builder.getGemfireFunctionOperationsBeanDefinitionBuilder(null);
|
||||
|
||||
assertThat(beanDefinitionBuilder, is(notNullValue()));
|
||||
|
||||
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
|
||||
|
||||
assertThat(beanDefinition, is(notNullValue()));
|
||||
assertThat((Class<Object>) beanDefinition.getBeanClass(), is(equalTo(Object.class)));
|
||||
assertThat(String.valueOf(beanDefinition.getConstructorArgumentValues()
|
||||
.getArgumentValue(0, RuntimeBeanReference.class).getValue()),
|
||||
containsString(GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME));
|
||||
|
||||
verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("cache"));
|
||||
verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("pool"));
|
||||
verify(mockFunctionExecutionConfiguration, times(1)).getFunctionExecutionInterface();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getGemfireFunctionOperationsBeanDefinitionBuilderWithCache() {
|
||||
FunctionExecutionConfiguration mockFunctionExecutionConfiguration =
|
||||
mock(FunctionExecutionConfiguration.class, "MockFunctionExecutionConfiguration");
|
||||
|
||||
when(mockFunctionExecutionConfiguration.getAttribute(eq("cache"))).thenReturn("TestCache");
|
||||
when(mockFunctionExecutionConfiguration.getAttribute(eq("pool"))).thenReturn(" ");
|
||||
when(mockFunctionExecutionConfiguration.getFunctionExecutionInterface()).thenAnswer(new Answer<Class<?>>() {
|
||||
@Override public Class<?> answer(final InvocationOnMock invocation) throws Throwable {
|
||||
return Object.class;
|
||||
}
|
||||
});
|
||||
|
||||
ServerBasedExecutionBeanDefinitionBuilder builder = new ServerBasedExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) {
|
||||
@Override protected Class<?> getGemfireFunctionOperationsClass() {
|
||||
return Object.class;
|
||||
}
|
||||
};
|
||||
|
||||
BeanDefinitionBuilder beanDefinitionBuilder = builder.getGemfireFunctionOperationsBeanDefinitionBuilder(null);
|
||||
|
||||
assertThat(beanDefinitionBuilder, is(notNullValue()));
|
||||
|
||||
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
|
||||
|
||||
assertThat(beanDefinition, is(notNullValue()));
|
||||
assertThat((Class<Object>) beanDefinition.getBeanClass(), is(equalTo(Object.class)));
|
||||
assertThat(String.valueOf(beanDefinition.getConstructorArgumentValues()
|
||||
.getArgumentValue(0, RuntimeBeanReference.class).getValue()), containsString("TestCache"));
|
||||
|
||||
verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("cache"));
|
||||
verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("pool"));
|
||||
verify(mockFunctionExecutionConfiguration, times(1)).getFunctionExecutionInterface();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getGemfireFunctionOperationsBeanDefinitionBuilderWithPool() {
|
||||
FunctionExecutionConfiguration mockFunctionExecutionConfiguration =
|
||||
mock(FunctionExecutionConfiguration.class, "MockFunctionExecutionConfiguration");
|
||||
|
||||
when(mockFunctionExecutionConfiguration.getAttribute(eq("cache"))).thenReturn(null);
|
||||
when(mockFunctionExecutionConfiguration.getAttribute(eq("pool"))).thenReturn("TestPool");
|
||||
when(mockFunctionExecutionConfiguration.getFunctionExecutionInterface()).thenAnswer(new Answer<Class<?>>() {
|
||||
@Override public Class<?> answer(final InvocationOnMock invocation) throws Throwable {
|
||||
return Object.class;
|
||||
}
|
||||
});
|
||||
|
||||
ServerBasedExecutionBeanDefinitionBuilder builder = new ServerBasedExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) {
|
||||
@Override protected Class<?> getGemfireFunctionOperationsClass() {
|
||||
return Object.class;
|
||||
}
|
||||
};
|
||||
|
||||
BeanDefinitionBuilder beanDefinitionBuilder = builder.getGemfireFunctionOperationsBeanDefinitionBuilder(null);
|
||||
|
||||
assertThat(beanDefinitionBuilder, is(notNullValue()));
|
||||
|
||||
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
|
||||
|
||||
assertThat(beanDefinition, is(notNullValue()));
|
||||
assertThat((Class<Object>) beanDefinition.getBeanClass(), is(equalTo(Object.class)));
|
||||
assertThat(String.valueOf(beanDefinition.getConstructorArgumentValues()
|
||||
.getArgumentValue(0, RuntimeBeanReference.class).getValue()), containsString("TestPool"));
|
||||
|
||||
verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("cache"));
|
||||
verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("pool"));
|
||||
verify(mockFunctionExecutionConfiguration, times(1)).getFunctionExecutionInterface();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getGemfireFunctionOperationsBeanDefinitionBuilderWithCacheAndPool() {
|
||||
FunctionExecutionConfiguration mockFunctionExecutionConfiguration =
|
||||
mock(FunctionExecutionConfiguration.class, "MockFunctionExecutionConfiguration");
|
||||
|
||||
when(mockFunctionExecutionConfiguration.getAttribute(eq("cache"))).thenReturn("TestCache");
|
||||
when(mockFunctionExecutionConfiguration.getAttribute(eq("pool"))).thenReturn("TestPool");
|
||||
when(mockFunctionExecutionConfiguration.getFunctionExecutionInterface()).thenAnswer(new Answer<Class<?>>() {
|
||||
@Override public Class<?> answer(final InvocationOnMock invocation) throws Throwable {
|
||||
return Object.class;
|
||||
}
|
||||
});
|
||||
|
||||
ServerBasedExecutionBeanDefinitionBuilder builder = new ServerBasedExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) {
|
||||
@Override protected Class<?> getGemfireFunctionOperationsClass() {
|
||||
return Object.class;
|
||||
}
|
||||
};
|
||||
|
||||
expectedException.expect(IllegalStateException.class);
|
||||
expectedException.expectCause(is(nullValue(Throwable.class)));
|
||||
expectedException.expectMessage(is(equalTo("invalid configuration for interface java.lang.Object;"
|
||||
+ " cannot specify both 'pool' and 'cache'")));
|
||||
builder.getGemfireFunctionOperationsBeanDefinitionBuilder(null);
|
||||
|
||||
verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("cache"));
|
||||
verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("pool"));
|
||||
verify(mockFunctionExecutionConfiguration, times(1)).getFunctionExecutionInterface();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright 2010-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.function.execution;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.isA;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
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.runners.MockitoJUnitRunner;
|
||||
|
||||
import com.gemstone.gemfire.cache.execute.Execution;
|
||||
import com.gemstone.gemfire.cache.execute.Function;
|
||||
import com.gemstone.gemfire.cache.execute.FunctionException;
|
||||
import com.gemstone.gemfire.cache.execute.ResultCollector;
|
||||
|
||||
/**
|
||||
* The AbstractFunctionExecutionTest class is a test suite of test cases testing the contract and functionality
|
||||
* of the AbstractFunctionExecution class.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.junit.runner.RunWith
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.runners.MockitoJUnitRunner
|
||||
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionExecution
|
||||
* @see com.gemstone.gemfire.cache.execute.Execution
|
||||
* @since 1.7.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AbstractFunctionExecutionTest {
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
@Mock
|
||||
private Execution mockExecution;
|
||||
|
||||
// TODO add more tests!!!
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void executeWithResults() throws Exception {
|
||||
Object[] args = { "one", "two", "three" };
|
||||
List<Object> results = Arrays.asList(args);
|
||||
|
||||
Function mockFunction = mock(Function.class, "MockFunction");
|
||||
ResultCollector mockResultCollector = mock(ResultCollector.class, "MockResultCollector");
|
||||
|
||||
when(mockExecution.withArgs(eq(args))).thenReturn(mockExecution);
|
||||
when(mockExecution.execute(eq(mockFunction))).thenReturn(mockResultCollector);
|
||||
when(mockFunction.hasResult()).thenReturn(true);
|
||||
when(mockResultCollector.getResult(500, TimeUnit.MILLISECONDS)).thenReturn(results);
|
||||
|
||||
AbstractFunctionExecution functionExecution = new AbstractFunctionExecution() {
|
||||
@Override protected Execution getExecution() {
|
||||
return mockExecution;
|
||||
}
|
||||
};
|
||||
|
||||
Iterable<Object> actualResults = functionExecution.setFunction(mockFunction)
|
||||
.setArgs(args).setTimeout(500).execute();
|
||||
|
||||
assertThat(actualResults, is(notNullValue()));
|
||||
assertThat(actualResults, is(equalTo((Iterable<Object>) results)));
|
||||
|
||||
verify(mockExecution, times(1)).withArgs(eq(args));
|
||||
verify(mockExecution, never()).withCollector(any(ResultCollector.class));
|
||||
verify(mockExecution, never()).withFilter(any(Set.class));
|
||||
verify(mockExecution, times(1)).execute(eq(mockFunction));
|
||||
verify(mockExecution, never()).execute(any(String.class));
|
||||
verify(mockResultCollector, times(1)).getResult(500, TimeUnit.MILLISECONDS);
|
||||
verify(mockResultCollector, never()).getResult();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeAndExtractWithSingleResult() {
|
||||
final List<String> results = Collections.singletonList("test");
|
||||
|
||||
AbstractFunctionExecution functionExecution = new AbstractFunctionExecution() {
|
||||
@Override protected Execution getExecution() {
|
||||
return mockExecution;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override <T> Iterable<T> execute() {
|
||||
return (Iterable<T>) results;
|
||||
}
|
||||
};
|
||||
|
||||
assertThat(String.valueOf(functionExecution.executeAndExtract()), is(equalTo("test")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeAndExtractWithMultipleResults() {
|
||||
final List<String> results = Arrays.asList("one", "two", "three");
|
||||
|
||||
AbstractFunctionExecution functionExecution = new AbstractFunctionExecution() {
|
||||
@Override protected Execution getExecution() {
|
||||
return mockExecution;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override <T> Iterable<T> execute() {
|
||||
return (Iterable<T>) results;
|
||||
}
|
||||
};
|
||||
|
||||
assertThat(String.valueOf(functionExecution.executeAndExtract()), is(equalTo("one")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeAndExtractWithNullResults() {
|
||||
AbstractFunctionExecution functionExecution = new AbstractFunctionExecution() {
|
||||
@Override protected Execution getExecution() {
|
||||
return mockExecution;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override <T> Iterable<T> execute() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
assertThat(functionExecution.executeAndExtract(), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeAndExtractWithNoResults() {
|
||||
AbstractFunctionExecution functionExecution = new AbstractFunctionExecution() {
|
||||
@Override protected Execution getExecution() {
|
||||
return mockExecution;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override <T> Iterable<T> execute() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
};
|
||||
|
||||
assertThat(functionExecution.executeAndExtract(), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeAndExtractWithThrowsException() {
|
||||
AbstractFunctionExecution functionExecution = new AbstractFunctionExecution() {
|
||||
@Override protected Execution getExecution() {
|
||||
return mockExecution;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override <T> Iterable<T> execute() {
|
||||
return Collections.singletonList((T) new IllegalArgumentException("test"));
|
||||
}
|
||||
};
|
||||
|
||||
expectedException.expect(FunctionException.class);
|
||||
expectedException.expectCause(isA(IllegalArgumentException.class));
|
||||
expectedException.expectMessage(containsString("Execution of Function with ID 'TestFunction' failed"));
|
||||
|
||||
functionExecution.setFunctionId("TestFunction").executeAndExtract();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright 2010-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.function.execution;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import com.gemstone.gemfire.cache.execute.Function;
|
||||
import com.gemstone.gemfire.cache.execute.ResultCollector;
|
||||
|
||||
/**
|
||||
* The AbstractFunctionTemplateTest class is a test suite of test cases testing the contract and functionality
|
||||
* of the AbstractFunctionTemplate class.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionExecution
|
||||
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionTemplate
|
||||
* @see com.gemstone.gemfire.cache.execute.Function
|
||||
* @see com.gemstone.gemfire.cache.execute.ResultCollector
|
||||
* @since 1.7.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AbstractFunctionTemplateTest {
|
||||
|
||||
@Mock
|
||||
private AbstractFunctionExecution mockFunctionExecution;
|
||||
|
||||
@Mock
|
||||
Function mockFunction;
|
||||
|
||||
@Mock
|
||||
private ResultCollector mockResultCollector;
|
||||
|
||||
@Test
|
||||
public void executeWithFunctionAndArgs() {
|
||||
Object[] args = { "test", "testing", "tested" };
|
||||
List<Object> results = Arrays.asList(args);
|
||||
|
||||
when(mockFunctionExecution.setArgs(args)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.setFunction(mockFunction)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.setResultCollector(mockResultCollector)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.setTimeout(500)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.execute()).thenReturn(results);
|
||||
|
||||
AbstractFunctionTemplate functionTemplate = new AbstractFunctionTemplate() {
|
||||
@Override protected AbstractFunctionExecution getFunctionExecution() {
|
||||
return mockFunctionExecution;
|
||||
}
|
||||
};
|
||||
|
||||
functionTemplate.setResultCollector(mockResultCollector);
|
||||
functionTemplate.setTimeout(500);
|
||||
|
||||
Iterable<Object> actualResults = functionTemplate.execute(mockFunction, args);
|
||||
|
||||
assertThat(functionTemplate.getResultCollector(), is(equalTo(mockResultCollector)));
|
||||
assertThat(actualResults, is(notNullValue()));
|
||||
assertThat(actualResults, is(equalTo((Iterable<Object>) results)));
|
||||
|
||||
verify(mockFunctionExecution, times(1)).setArgs(args);
|
||||
verify(mockFunctionExecution, times(1)).setFunction(mockFunction);
|
||||
verify(mockFunctionExecution, times(1)).setResultCollector(eq(mockResultCollector));
|
||||
verify(mockFunctionExecution, times(1)).setTimeout(500);
|
||||
verify(mockFunctionExecution, times(1)).execute();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeAndExtractWithFunctionAndArgs() {
|
||||
Object[] args = { "test", "testing", "tested" };
|
||||
|
||||
when(mockFunctionExecution.setArgs(args)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.setFunction(mockFunction)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.setResultCollector(mockResultCollector)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.setTimeout(500)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.executeAndExtract()).thenReturn(args[0]);
|
||||
|
||||
AbstractFunctionTemplate functionTemplate = new AbstractFunctionTemplate() {
|
||||
@Override protected AbstractFunctionExecution getFunctionExecution() {
|
||||
return mockFunctionExecution;
|
||||
}
|
||||
};
|
||||
|
||||
functionTemplate.setResultCollector(mockResultCollector);
|
||||
functionTemplate.setTimeout(500);
|
||||
|
||||
String result = functionTemplate.executeAndExtract(mockFunction, args);
|
||||
|
||||
assertThat(functionTemplate.getResultCollector(), is(equalTo(mockResultCollector)));
|
||||
assertThat(result, is(notNullValue()));
|
||||
assertThat(result, is(equalTo("test")));
|
||||
|
||||
verify(mockFunctionExecution, times(1)).setArgs(args);
|
||||
verify(mockFunctionExecution, times(1)).setFunction(mockFunction);
|
||||
verify(mockFunctionExecution, times(1)).setResultCollector(eq(mockResultCollector));
|
||||
verify(mockFunctionExecution, times(1)).setTimeout(500);
|
||||
verify(mockFunctionExecution, times(1)).executeAndExtract();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeWithFunctionIdAndArgs() {
|
||||
Object[] args = { "test", "testing", "tested" };
|
||||
List<Object> results = Arrays.asList(args);
|
||||
|
||||
when(mockFunctionExecution.setArgs(args)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.setFunctionId("TestFunction")).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.setResultCollector(mockResultCollector)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.setTimeout(500)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.execute()).thenReturn(results);
|
||||
|
||||
AbstractFunctionTemplate functionTemplate = new AbstractFunctionTemplate() {
|
||||
@Override protected AbstractFunctionExecution getFunctionExecution() {
|
||||
return mockFunctionExecution;
|
||||
}
|
||||
};
|
||||
|
||||
functionTemplate.setResultCollector(mockResultCollector);
|
||||
functionTemplate.setTimeout(500);
|
||||
|
||||
Iterable<Object> actualResults = functionTemplate.execute("TestFunction", args);
|
||||
|
||||
assertThat(functionTemplate.getResultCollector(), is(equalTo(mockResultCollector)));
|
||||
assertThat(actualResults, is(notNullValue()));
|
||||
assertThat(actualResults, is(equalTo((Iterable<Object>) results)));
|
||||
|
||||
verify(mockFunctionExecution, times(1)).setArgs(args);
|
||||
verify(mockFunctionExecution, times(1)).setFunctionId("TestFunction");
|
||||
verify(mockFunctionExecution, times(1)).setResultCollector(eq(mockResultCollector));
|
||||
verify(mockFunctionExecution, times(1)).setTimeout(500);
|
||||
verify(mockFunctionExecution, times(1)).execute();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeAndExtractWithFunctionIdAndArgs() {
|
||||
Object[] args = { "test", "testing", "tested" };
|
||||
|
||||
when(mockFunctionExecution.setArgs(args)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.setFunctionId("TestFunction")).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.setResultCollector(mockResultCollector)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.setTimeout(500)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.executeAndExtract()).thenReturn(args[0]);
|
||||
|
||||
AbstractFunctionTemplate functionTemplate = new AbstractFunctionTemplate() {
|
||||
@Override protected AbstractFunctionExecution getFunctionExecution() {
|
||||
return mockFunctionExecution;
|
||||
}
|
||||
};
|
||||
|
||||
functionTemplate.setResultCollector(mockResultCollector);
|
||||
functionTemplate.setTimeout(500);
|
||||
|
||||
String result = functionTemplate.executeAndExtract("TestFunction", args);
|
||||
|
||||
assertThat(functionTemplate.getResultCollector(), is(equalTo(mockResultCollector)));
|
||||
assertThat(result, is(notNullValue()));
|
||||
assertThat(result, is(equalTo("test")));
|
||||
|
||||
verify(mockFunctionExecution, times(1)).setArgs(args);
|
||||
verify(mockFunctionExecution, times(1)).setFunctionId("TestFunction");
|
||||
verify(mockFunctionExecution, times(1)).setResultCollector(eq(mockResultCollector));
|
||||
verify(mockFunctionExecution, times(1)).setTimeout(500);
|
||||
verify(mockFunctionExecution, times(1)).executeAndExtract();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeWithNoResultWithFunctionIdAndArgs() {
|
||||
Object[] args = { "test", "testing", "tested" };
|
||||
|
||||
when(mockFunctionExecution.setArgs(args)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.setFunctionId("TestFunction")).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.setResultCollector(mockResultCollector)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.setTimeout(500)).thenReturn(mockFunctionExecution);
|
||||
when(mockFunctionExecution.execute(eq(false))).thenReturn(null);
|
||||
|
||||
AbstractFunctionTemplate functionTemplate = new AbstractFunctionTemplate() {
|
||||
@Override protected AbstractFunctionExecution getFunctionExecution() {
|
||||
return mockFunctionExecution;
|
||||
}
|
||||
};
|
||||
|
||||
functionTemplate.setResultCollector(mockResultCollector);
|
||||
functionTemplate.setTimeout(500);
|
||||
|
||||
functionTemplate.executeWithNoResult("TestFunction", args);
|
||||
|
||||
assertThat(functionTemplate.getResultCollector(), is(equalTo(mockResultCollector)));
|
||||
|
||||
verify(mockFunctionExecution, times(1)).setArgs(args);
|
||||
verify(mockFunctionExecution, times(1)).setFunctionId("TestFunction");
|
||||
verify(mockFunctionExecution, times(1)).setResultCollector(eq(mockResultCollector));
|
||||
verify(mockFunctionExecution, times(1)).setTimeout(500);
|
||||
verify(mockFunctionExecution, times(1)).execute(eq(false));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2010-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.function.sample;
|
||||
|
||||
import org.springframework.data.gemfire.function.annotation.OnServer;
|
||||
|
||||
/**
|
||||
* The ExceptionThrowingFunctionExecution interface defines a GemFire Function that throws a RuntimeException.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.data.gemfire.function.annotation.OnServer
|
||||
* @since 1.7.0
|
||||
*/
|
||||
@OnServer
|
||||
@SuppressWarnings("unused")
|
||||
public interface ExceptionThrowingFunctionExecution {
|
||||
|
||||
Integer exceptionThrowingFunction();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:gfe="http://www.springframework.org/schema/gemfire"
|
||||
xmlns:gfe-data="http://www.springframework.org/schema/data/gemfire"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/gemfire http://www.springframework.org/schema/gemfire/spring-gemfire.xsd
|
||||
http://www.springframework.org/schema/data/gemfire http://www.springframework.org/schema/data/gemfire/spring-data-gemfire.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
|
||||
">
|
||||
|
||||
<util:properties id="gemfireProperties">
|
||||
<prop key="log-level">config</prop>
|
||||
</util:properties>
|
||||
|
||||
<gfe:pool id="serverPool">
|
||||
<gfe:server host="localhost" port="12480"/>
|
||||
</gfe:pool>
|
||||
|
||||
<gfe:client-cache properties-ref="gemfireProperties" pool-name="serverPool"/>
|
||||
|
||||
<gfe-data:function-executions base-package="org.springframework.data.gemfire.function.sample">
|
||||
<gfe-data:include-filter type="assignable" expression="org.springframework.data.gemfire.function.sample.ExceptionThrowingFunctionExecution"/>
|
||||
</gfe-data:function-executions>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:gfe="http://www.springframework.org/schema/gemfire"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
|
||||
http://www.springframework.org/schema/gemfire http://www.springframework.org/schema/gemfire/spring-gemfire.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
|
||||
">
|
||||
|
||||
<util:properties id="serverProperties">
|
||||
<prop key="server.bind-address">localhost</prop>
|
||||
<prop key="server.hostname-for-clients">localhost</prop>
|
||||
<prop key="server.max-connections">1</prop>
|
||||
<prop key="server.port">12480</prop>
|
||||
</util:properties>
|
||||
|
||||
<context:property-placeholder properties-ref="serverProperties"/>
|
||||
|
||||
<util:properties id="gemfireProperties">
|
||||
<prop key="name">ExceptionThrowingFunctionExecutionIntegrationTestServer</prop>
|
||||
<prop key="mcast-port">0</prop>
|
||||
<prop key="log-level">warning</prop>
|
||||
</util:properties>
|
||||
|
||||
<gfe:cache properties-ref="gemfireProperties" lazy-init="false"/>
|
||||
|
||||
<gfe:cache-server auto-startup="true" bind-address="${server.bind-address}" port="${server.port}"
|
||||
host-name-for-clients="${server.hostname-for-clients}" max-connections="${server.max-connections}"/>
|
||||
|
||||
<gfe:function-service>
|
||||
<gfe:function>
|
||||
<bean class="org.springframework.data.gemfire.function.ExceptionThrowingFunctionExecutionIntegrationTest$ExceptionThrowingFunction"/>
|
||||
</gfe:function>
|
||||
</gfe:function-service>
|
||||
|
||||
</beans>
|
||||
Reference in New Issue
Block a user