/*
* Copyright 2002-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.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.apache.geode.cache.Region;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.gemfire.fork.ServerProcess;
import org.springframework.data.gemfire.function.annotation.GemfireFunction;
import org.springframework.data.gemfire.function.annotation.RegionData;
import org.springframework.data.gemfire.process.ProcessWrapper;
import org.springframework.data.gemfire.test.support.ClientServerIntegrationTestsSupport;
import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author David Turanski
* @author John Blum
*/
@RunWith(SpringRunner.class)
@ContextConfiguration
@SuppressWarnings("unused")
public class FunctionIntegrationTests extends ClientServerIntegrationTestsSupport {
private static ProcessWrapper gemfireServer;
@Resource(name = "test-region")
private Region<String, Integer> region;
@BeforeClass
public static void startGemFireServer() throws Exception {
int availablePort = findAvailablePort();
gemfireServer = run(ServerProcess.class,
String.format("-D%s=%d", GEMFIRE_CACHE_SERVER_PORT_PROPERTY, availablePort),
getServerContextXmlFileLocation(FunctionIntegrationTests.class));
waitForServerToStart(DEFAULT_HOSTNAME, availablePort);
System.setProperty(GEMFIRE_CACHE_SERVER_PORT_PROPERTY, String.valueOf(availablePort));
}
@AfterClass
public static void stopGemFireServer() {
System.clearProperty(GEMFIRE_CACHE_SERVER_PORT_PROPERTY);
stop(gemfireServer);
}
@Before
public void initializeRegion() {
region.put("one", 1);
region.put("two", 2);
region.put("three", 3);
}
@Test
//@Ignore
public void testVoidReturnType() {
GemfireOnRegionOperations template = new GemfireOnRegionFunctionTemplate(region);
// Should work either way but the first invocation traps an exception if there is a result.
template.execute("noResult");
template.executeWithNoResult("noResult");
}
@Test
//@Ignore
@SuppressWarnings("unchecked")
public void testCollectionReturnTypes() {
GemfireOnRegionOperations template = new GemfireOnRegionFunctionTemplate(region);
Object result = template.executeAndExtract("getMapWithNoArgs");
assertTrue(result.getClass().getName(), result instanceof Map);
Map<String, Integer> map = (Map<String, Integer>) result;
assertEquals(1, map.get("one").intValue());
assertEquals(2, map.get("two").intValue());
assertEquals(3, map.get("three").intValue());
result = template.executeAndExtract("collections", Arrays.asList(1, 2, 3, 4, 5));
assertTrue(result.getClass().getName(), result instanceof List);
List<?> list = (List<?>) result;
assertFalse(list.isEmpty());
assertEquals(5, list.size());
int expectedNumber = 1;
for (Object actualNumber : list) {
assertEquals(expectedNumber++, actualNumber);
}
}
@Test
@SuppressWarnings("all")
public void testArrayReturnTypes() {
Object result = new GemfireOnRegionFunctionTemplate(region)
.executeAndExtract("arrays", new int[] { 1, 2, 3, 4, 5 });
assertTrue(result.getClass().getName(), result instanceof int[]);
assertEquals(5, ((int[]) result).length);
}
@Test
//@Ignore
public void testOnRegionFunctionExecution() {
GemfireOnRegionOperations template = new GemfireOnRegionFunctionTemplate(region);
assertEquals(2, template.<Integer>execute("oneArg", "two").iterator().next().intValue());
assertFalse(template.<Integer>execute("oneArg", Collections.singleton("one"), "two").iterator().hasNext());
assertEquals(5, template.<Integer>execute("twoArg", "two", "three").iterator().next().intValue());
assertEquals(5, template.<Integer>executeAndExtract("twoArg", "two", "three").intValue());
}
/*
* This gets wrapped in a GemFire Function and registered on the forked server.
*/
@Component
@SuppressWarnings("unused")
public static class Foo {
@GemfireFunction(id = "oneArg")
public Integer oneArg(String key, @RegionData Map<String, Integer> region) {
return region.get(key);
}
@GemfireFunction(id = "twoArg")
public Integer twoArg(String keyOne, String keyTwo, @RegionData Map<String, Integer> region) {
if (region.get(keyOne) != null && region.get(keyTwo) != null) {
return region.get(keyOne) + region.get(keyTwo);
}
return null;
}
@GemfireFunction(id = "collections")
public List<Integer> collections(List<Integer> args) {
return args;
}
@GemfireFunction(id = "getMapWithNoArgs")
public Map<String, Integer> getMapWithNoArgs(@RegionData Map<String, Integer> region) {
if (region.size() == 0) {
return null;
}
return new HashMap<String, Integer>(region);
}
@GemfireFunction(id = "arrays")
// TODO causes OOME!
//@GemfireFunction(id = "arrays", batchSize = 2)
public int[] collections(int[] args) {
return args;
}
@GemfireFunction
public void noResult() {
}
}
}