You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2016/03/01 01:09:19 UTC
[10/34] incubator-geode git commit: adding unit tests for REST API
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9b55879e/geode-assembly/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestAPIOnRegionFunctionExecutionDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-assembly/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestAPIOnRegionFunctionExecutionDUnitTest.java b/geode-assembly/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestAPIOnRegionFunctionExecutionDUnitTest.java
new file mode 100644
index 0000000..4a958ce
--- /dev/null
+++ b/geode-assembly/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestAPIOnRegionFunctionExecutionDUnitTest.java
@@ -0,0 +1,617 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.gemstone.gemfire.rest.internal.web.controllers;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+
+import com.gemstone.gemfire.LogWriter;
+import com.gemstone.gemfire.cache.AttributesFactory;
+import com.gemstone.gemfire.cache.DataPolicy;
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.RegionAttributes;
+import com.gemstone.gemfire.cache.Scope;
+import com.gemstone.gemfire.cache.execute.Function;
+import com.gemstone.gemfire.cache.execute.FunctionContext;
+import com.gemstone.gemfire.cache.execute.FunctionService;
+import com.gemstone.gemfire.cache.execute.RegionFunctionContext;
+import com.gemstone.gemfire.cache.partition.PartitionRegionHelper;
+import com.gemstone.gemfire.distributed.DistributedSystem;
+import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
+import com.gemstone.gemfire.internal.cache.PartitionAttributesImpl;
+import com.gemstone.gemfire.internal.cache.PartitionedRegion;
+import com.gemstone.gemfire.internal.cache.PartitionedRegionTestHelper;
+import com.gemstone.gemfire.internal.cache.functions.DistributedRegionFunction;
+import com.gemstone.gemfire.test.dunit.Host;
+import com.gemstone.gemfire.test.dunit.IgnoredException;
+import com.gemstone.gemfire.test.dunit.SerializableCallable;
+import com.gemstone.gemfire.test.dunit.VM;
+
+/**
+ * Dunit Test to validate OnRegion function execution with REST APIs
+ *
+ * @author Nilkanth Patel
+ * @since 8.0
+ */
+
+public class RestAPIOnRegionFunctionExecutionDUnitTest extends RestAPITestBase {
+
+ private static final long serialVersionUID = 1L;
+
+ public static final String REGION_NAME = "DistributedRegionFunctionExecutionDUnitTest";
+
+ public static final String PR_REGION_NAME = "samplePRRegion";
+
+ public static Region region = null;
+
+ public static List<String> restURLs = new ArrayList<String>();
+
+ public static String restEndPoint = null;
+
+ public static String getRestEndPoint() {
+ return restEndPoint;
+ }
+
+ public static void setRestEndPoint(String restEndPoint) {
+ RestAPIOnRegionFunctionExecutionDUnitTest.restEndPoint = restEndPoint;
+ }
+
+ public static final Function function = new DistributedRegionFunction();
+
+ public static final Function functionWithNoResultThrowsException = new MyFunctionException();
+
+ public RestAPIOnRegionFunctionExecutionDUnitTest(String name) {
+ super(name);
+ }
+
+ public void setUp() throws Exception {
+ super.setUp();
+ final Host host = Host.getHost(0);
+ }
+
+ static class FunctionWithNoLastResult implements Function {
+ private static final long serialVersionUID = -1032915440862585532L;
+ public static final String Id = "FunctionWithNoLastResult";
+ public static int invocationCount;
+
+ @Override
+ public void execute(FunctionContext context) {
+ invocationCount++;
+ InternalDistributedSystem
+ .getConnectedInstance()
+ .getLogWriter()
+ .info(
+ "<ExpectedException action=add>did not send last result"
+ + "</ExpectedException>");
+ context.getResultSender().sendResult(
+ (Serializable) context.getArguments());
+ }
+
+ @Override
+ public String getId() {
+ return Id;
+ }
+
+ @Override
+ public boolean hasResult() {
+ return true;
+ }
+
+ @Override
+ public boolean optimizeForWrite() {
+ return false;
+ }
+
+ @Override
+ public boolean isHA() {
+ return false;
+ }
+ }
+
+ static class SampleFunction implements Function {
+ private static final long serialVersionUID = -1032915440862585534L;
+ public static final String Id = "SampleFunction";
+ public static int invocationCount;
+
+ @Override
+ public void execute(FunctionContext context) {
+ invocationCount++;
+ if (context instanceof RegionFunctionContext) {
+ RegionFunctionContext rfContext = (RegionFunctionContext) context;
+ rfContext.getDataSet().getCache().getLogger()
+ .info("Executing function : TestFunction2.execute " + rfContext);
+ if (rfContext.getArguments() instanceof Boolean) {
+ /* return rfContext.getArguments(); */
+ if (hasResult()) {
+ rfContext.getResultSender().lastResult(
+ (Serializable) rfContext.getArguments());
+ } else {
+ rfContext
+ .getDataSet()
+ .getCache()
+ .getLogger()
+ .info(
+ "Executing function : TestFunction2.execute " + rfContext);
+ while (true && !rfContext.getDataSet().isDestroyed()) {
+ rfContext.getDataSet().getCache().getLogger()
+ .info("For Bug43513 ");
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ie) {
+ Thread.currentThread().interrupt();
+ return;
+ }
+ }
+ }
+ } else if (rfContext.getArguments() instanceof String) {
+ String key = (String) rfContext.getArguments();
+ if (key.equals("TestingTimeOut")) { // for test
+ // PRFunctionExecutionDUnitTest#testRemoteMultiKeyExecution_timeout
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ rfContext.getDataSet().getCache().getLogger()
+ .warning("Got Exception : Thread Interrupted" + e);
+ }
+ }
+ if (PartitionRegionHelper.isPartitionedRegion(rfContext.getDataSet())) {
+ /*
+ * return
+ * (Serializable)PartitionRegionHelper.getLocalDataForContext(
+ * rfContext).get(key);
+ */
+ rfContext.getResultSender().lastResult(
+ (Serializable) PartitionRegionHelper.getLocalDataForContext(
+ rfContext).get(key));
+ } else {
+ rfContext.getResultSender().lastResult(
+ (Serializable) rfContext.getDataSet().get(key));
+ }
+ /* return (Serializable)rfContext.getDataSet().get(key); */
+ } else if (rfContext.getArguments() instanceof Set) {
+ Set origKeys = (Set) rfContext.getArguments();
+ ArrayList vals = new ArrayList();
+ for (Object key : origKeys) {
+ Object val = PartitionRegionHelper
+ .getLocalDataForContext(rfContext).get(key);
+ if (val != null) {
+ vals.add(val);
+ }
+ }
+ rfContext.getResultSender().lastResult(vals);
+ /* return vals; */
+ } else if (rfContext.getArguments() instanceof HashMap) {
+ HashMap putData = (HashMap) rfContext.getArguments();
+ for (Iterator i = putData.entrySet().iterator(); i.hasNext();) {
+ Map.Entry me = (Map.Entry) i.next();
+ rfContext.getDataSet().put(me.getKey(), me.getValue());
+ }
+ rfContext.getResultSender().lastResult(Boolean.TRUE);
+ } else {
+ rfContext.getResultSender().lastResult(Boolean.FALSE);
+ }
+ } else {
+ if (hasResult()) {
+ context.getResultSender().lastResult(Boolean.FALSE);
+ } else {
+ DistributedSystem ds = InternalDistributedSystem.getAnyInstance();
+ LogWriter logger = ds.getLogWriter();
+ logger.info("Executing in TestFunction on Server : "
+ + ds.getDistributedMember() + "with Context : " + context);
+ while (ds.isConnected()) {
+ logger
+ .fine("Just executing function in infinite loop for Bug43513");
+ try {
+ Thread.sleep(250);
+ } catch (InterruptedException e) {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public String getId() {
+ return Id;
+ }
+
+ @Override
+ public boolean hasResult() {
+ return true;
+ }
+
+ @Override
+ public boolean optimizeForWrite() {
+ return false;
+ }
+
+ @Override
+ public boolean isHA() {
+ return false;
+ }
+ }
+
+ private int getInvocationCount(VM vm) {
+ return (Integer) vm.invoke(new SerializableCallable() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Object call() throws Exception {
+ SampleFunction f = (SampleFunction) FunctionService
+ .getFunction(SampleFunction.Id);
+ int count = f.invocationCount;
+ f.invocationCount = 0;
+ return count;
+ }
+ });
+ }
+
+ private void verifyAndResetInvocationCount(VM vm, final int count) {
+ vm.invoke(new SerializableCallable() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Object call() throws Exception {
+ SampleFunction f = (SampleFunction) FunctionService
+ .getFunction(SampleFunction.Id);
+ assertEquals(count, f.invocationCount);
+ // assert succeeded, reset count
+ f.invocationCount = 0;
+ return null;
+ }
+ });
+ }
+
+ public static void createPeer(DataPolicy policy) {
+ AttributesFactory factory = new AttributesFactory();
+ factory.setScope(Scope.DISTRIBUTED_ACK);
+ factory.setDataPolicy(policy);
+ assertNotNull(cache);
+ region = cache.createRegion(REGION_NAME, factory.create());
+ com.gemstone.gemfire.test.dunit.LogWriterUtils.getLogWriter().info("Region Created :" + region);
+ assertNotNull(region);
+ }
+
+ public static boolean createPeerWithPR() {
+ RegionAttributes ra = PartitionedRegionTestHelper.createRegionAttrsForPR(0,
+ 10);
+ AttributesFactory raf = new AttributesFactory(ra);
+ PartitionAttributesImpl pa = new PartitionAttributesImpl();
+ pa.setAll(ra.getPartitionAttributes());
+ pa.setTotalNumBuckets(17);
+ raf.setPartitionAttributes(pa);
+
+ if (cache == null || cache.isClosed()) {
+ // Cache not available
+ }
+ assertNotNull(cache);
+
+ region = cache.createRegion(PR_REGION_NAME, raf.create());
+ com.gemstone.gemfire.test.dunit.LogWriterUtils.getLogWriter().info("Region Created :" + region);
+ assertNotNull(region);
+ return Boolean.TRUE;
+ }
+
+ public static void populateRegion() {
+ assertNotNull(cache);
+ region = cache.getRegion(REGION_NAME);
+ assertNotNull(region);
+ for (int i = 1; i <= 200; i++) {
+ region.put("execKey-" + i, new Integer(i));
+ }
+ }
+
+ public static void populatePRRegion() {
+ assertNotNull(cache);
+ region = cache.getRegion(REGION_NAME);
+
+ PartitionedRegion pr = (PartitionedRegion) cache.getRegion(PR_REGION_NAME);
+ DistributedSystem.setThreadsSocketPolicy(false);
+ final HashSet testKeys = new HashSet();
+
+ for (int i = (pr.getTotalNumberOfBuckets() * 3); i > 0; i--) {
+ testKeys.add("execKey-" + i);
+ }
+ int j = 0;
+ for (Iterator i = testKeys.iterator(); i.hasNext();) {
+ Integer val = new Integer(j++);
+ pr.put(i.next(), val);
+ }
+ // Assert there is data in each bucket
+ for (int bid = 0; bid < pr.getTotalNumberOfBuckets(); bid++) {
+ assertTrue(pr.getBucketKeys(bid).size() > 0);
+ }
+ }
+
+ public static void populateRRRegion() {
+ assertNotNull(cache);
+ region = cache.getRegion(REGION_NAME);
+ assertNotNull(region);
+
+ final HashSet testKeys = new HashSet();
+ for (int i = 17 * 3; i > 0; i--) {
+ testKeys.add("execKey-" + i);
+ }
+ int j = 0;
+ for (Iterator i = testKeys.iterator(); i.hasNext();) {
+ Integer val = new Integer(j++);
+ region.put(i.next(), val);
+ }
+
+ }
+
+ public static void executeFunction_NoLastResult(String regionName) {
+
+ try {
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ CloseableHttpResponse response = null;
+ Random randomGenerator = new Random();
+ int index = randomGenerator.nextInt(restURLs.size());
+ HttpPost post = new HttpPost(restURLs.get(index) + "/functions/"
+ + "FunctionWithNoLastResult" + "?onRegion=" + regionName);
+ post.addHeader("Content-Type", "application/json");
+ post.addHeader("Accept", "application/json");
+ response = httpclient.execute(post);
+ } catch (Exception e) {
+ throw new RuntimeException("unexpected exception", e);
+ }
+
+ }
+
+ public static void executeFunctionThroughRestCall(String regionName) {
+ com.gemstone.gemfire.test.dunit.LogWriterUtils.getLogWriter().info("Entering executeFunctionThroughRestCall");
+ try {
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ CloseableHttpResponse response = null;
+ Random randomGenerator = new Random();
+ int index = randomGenerator.nextInt(restURLs.size());
+
+ HttpPost post = new HttpPost(restURLs.get(index) + "/functions/"
+ + "SampleFunction" + "?onRegion=" + regionName);
+ post.addHeader("Content-Type", "application/json");
+ post.addHeader("Accept", "application/json");
+
+ com.gemstone.gemfire.test.dunit.LogWriterUtils.getLogWriter().info("Request: POST " + post.toString());
+ response = httpclient.execute(post);
+ com.gemstone.gemfire.test.dunit.LogWriterUtils.getLogWriter().info("Response: POST " + response.toString());
+
+ assertEquals(response.getStatusLine().getStatusCode(), 200);
+ assertNotNull(response.getEntity());
+ } catch (Exception e) {
+ throw new RuntimeException("unexpected exception", e);
+ }
+ com.gemstone.gemfire.test.dunit.LogWriterUtils.getLogWriter().info("Exiting executeFunctionThroughRestCall");
+
+ }
+
+ private void registerFunction(VM vm) {
+ vm.invoke(new SerializableCallable() {
+ private static final long serialVersionUID = 1L;
+ @Override
+ public Object call() throws Exception {
+ FunctionService.registerFunction(new FunctionWithNoLastResult());
+ return null;
+ }
+ });
+ }
+
+ private void registerSampleFunction(VM vm) {
+ vm.invoke(new SerializableCallable() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Object call() throws Exception {
+ FunctionService.registerFunction(new SampleFunction());
+ return null;
+ }
+ });
+ }
+
+ public void __testOnRegionExecutionOnDataPolicyEmpty_NoLastResult() {
+ // Step-1 : create cache on each VM, this will start HTTP service in
+ // embedded mode and deploy REST APIs web app on it.
+
+ fail("This test is trying to invoke non existent methods");
+// String url1 = (String) vm3.invoke(() -> createCacheInVm( vm3 ));
+// restURLs.add(url1);
+//
+// String url2 = (String) vm0.invoke(() -> createCacheInVm( vm0 ));
+// restURLs.add(url2);
+//
+// String url3 = (String) vm1.invoke(() -> createCacheInVm( vm1 ));
+// restURLs.add(url3);
+//
+// String url4 = (String) vm2.invoke(() -> createCacheInVm( vm2 ));
+// restURLs.add(url4);
+
+ // Step-2: Register function in all VMs
+ registerFunction(vm3);
+ registerFunction(vm0);
+ registerFunction(vm1);
+ registerFunction(vm2);
+
+ // Step-3: Create and configure Region on all VMs
+ vm3.invoke(() -> createPeer( DataPolicy.EMPTY ));
+ vm0.invoke(() -> createPeer( DataPolicy.REPLICATE ));
+ vm1.invoke(() -> createPeer( DataPolicy.REPLICATE ));
+ vm2.invoke(() -> createPeer( DataPolicy.REPLICATE ));
+
+ // Step-4 : Do some puts on region created earlier
+ vm3.invoke(() -> populateRegion());
+
+ // add expected exception to avoid suspect strings
+ final IgnoredException ex = IgnoredException.addIgnoredException("did not send last result");
+
+ // Step-5 : Execute function randomly (in iteration) on all available (per
+ // VM) REST end-points and verify its result
+ for (int i = 0; i < 10; i++) {
+ executeFunction_NoLastResult(REGION_NAME);
+ }
+ ex.remove();
+
+ restURLs.clear();
+ }
+
+ public void testOnRegionExecutionWithRR() {
+ // Step-1 : create cache on each VM, this will start HTTP service in
+ // embedded mode and deploy REST APIs web app on it.
+ //
+ String url1 = (String) vm3.invoke(() -> RestAPITestBase.createCache( vm3 ));
+ restURLs.add(url1);
+
+ String url2 = (String) vm0.invoke(() -> RestAPITestBase.createCache( vm0 ));
+ restURLs.add(url2);
+
+ String url3 = (String) vm1.invoke(() -> RestAPITestBase.createCache( vm1 ));
+ restURLs.add(url3);
+
+ String url4 = (String) vm2.invoke(() -> RestAPITestBase.createCache( vm2 ));
+ restURLs.add(url4);
+
+ // Step-2: Register function in all VMs
+ registerSampleFunction(vm3);
+ registerSampleFunction(vm0);
+ registerSampleFunction(vm1);
+ registerSampleFunction(vm2);
+
+ // Step-3: Create and configure PR on all VMs
+ vm3.invoke(() -> createPeer( DataPolicy.EMPTY ));
+ vm0.invoke(() -> createPeer( DataPolicy.REPLICATE ));
+ vm1.invoke(() -> createPeer( DataPolicy.REPLICATE ));
+ vm2.invoke(() -> createPeer( DataPolicy.REPLICATE ));
+
+ // Step-4 : Do some puts in Replicated region on vm3
+ vm3.invoke(() -> populateRRRegion());
+
+ // Step-5 : Execute function randomly (in iteration) on all available (per
+ // VM) REST end-points and verify its result
+ executeFunctionThroughRestCall(REGION_NAME);
+ int c0 = getInvocationCount(vm0);
+ int c1 = getInvocationCount(vm1);
+ int c2 = getInvocationCount(vm2);
+ int c3 = getInvocationCount(vm3);
+
+ assertEquals(1, c0 + c1 + c2 + c3);
+
+ // remove the expected exception
+ restURLs.clear();
+ }
+
+ public void testOnRegionExecutionWithPR() throws Exception {
+ final String rName = getUniqueName();
+
+ // Step-1 : create cache on each VM, this will start HTTP service in
+ // embedded mode and deploy REST APIs web app on it.
+ String url1 = (String) vm3.invoke(() -> RestAPITestBase.createCache( vm3 ));
+ restURLs.add(url1);
+
+ String url2 = (String) vm0.invoke(() -> RestAPITestBase.createCache( vm0 ));
+ restURLs.add(url2);
+
+ String url3 = (String) vm1.invoke(() -> RestAPITestBase.createCache( vm1 ));
+ restURLs.add(url3);
+
+ String url4 = (String) vm2.invoke(() -> RestAPITestBase.createCache( vm2 ));
+ restURLs.add(url4);
+
+ // Step-2: Register function in all VMs
+ registerSampleFunction(vm3);
+ registerSampleFunction(vm0);
+ registerSampleFunction(vm1);
+ registerSampleFunction(vm2);
+
+ // Step-3: Create and configure PR on all VMs
+ vm3.invoke(() -> createPeerWithPR());
+ vm0.invoke(() -> createPeerWithPR());
+ vm1.invoke(() -> createPeerWithPR());
+ vm2.invoke(() -> createPeerWithPR());
+
+ // Step-4: Do some puts such that data exist in each bucket
+ vm3.invoke(() -> populatePRRegion());
+
+ // Step-5 : Execute function randomly (in iteration) on all available (per
+ // VM) REST end-points and verify its result
+ executeFunctionThroughRestCall(PR_REGION_NAME);
+
+ // Assert that each node has executed the function once.
+ verifyAndResetInvocationCount(vm0, 1);
+ verifyAndResetInvocationCount(vm1, 1);
+ verifyAndResetInvocationCount(vm2, 1);
+ verifyAndResetInvocationCount(vm3, 1);
+
+ int c0 = getInvocationCount(vm0);
+ int c1 = getInvocationCount(vm1);
+ int c2 = getInvocationCount(vm2);
+ int c3 = getInvocationCount(vm3);
+
+ restURLs.clear();
+ }
+
+}
+
+class MyFunctionException implements Function {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void execute(FunctionContext context) {
+ throw new RuntimeException("failure");
+ }
+
+ @Override
+ public String getId() {
+ return this.getClass().getName();
+ }
+
+ @Override
+ public boolean hasResult() {
+ return true;
+ }
+
+ @Override
+ public boolean isHA() {
+ return false;
+ }
+
+ @Override
+ public boolean optimizeForWrite() {
+ return false;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9b55879e/geode-assembly/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestAPITestBase.java
----------------------------------------------------------------------
diff --git a/geode-assembly/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestAPITestBase.java b/geode-assembly/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestAPITestBase.java
new file mode 100644
index 0000000..3709475
--- /dev/null
+++ b/geode-assembly/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestAPITestBase.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.gemstone.gemfire.rest.internal.web.controllers;
+
+import java.util.Properties;
+
+import com.gemstone.gemfire.cache.Cache;
+import com.gemstone.gemfire.cache.CacheClosedException;
+import com.gemstone.gemfire.cache.CacheFactory;
+import com.gemstone.gemfire.cache.RegionShortcut;
+import com.gemstone.gemfire.distributed.internal.DistributionConfig;
+import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
+import com.gemstone.gemfire.internal.AvailablePortHelper;
+import com.gemstone.gemfire.internal.GemFireVersion;
+import com.gemstone.gemfire.management.internal.AgentUtil;
+import com.gemstone.gemfire.test.dunit.DistributedTestCase;
+import com.gemstone.gemfire.test.dunit.Host;
+import com.gemstone.gemfire.test.dunit.Invoke;
+import com.gemstone.gemfire.test.dunit.VM;
+import com.gemstone.gemfire.test.dunit.Wait;
+
+public class RestAPITestBase extends DistributedTestCase {
+ private static final long serialVersionUID = 1L;
+ public static Cache cache = null;
+ VM vm0 = null;
+ VM vm1 = null;
+ VM vm2 = null;
+ VM vm3 = null;
+
+ public RestAPITestBase(String name) {
+ super(name);
+ }
+
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ disconnectAllFromDS();
+ AgentUtil agentUtil = new AgentUtil(GemFireVersion.getGemFireVersion());
+ if (agentUtil.findWarLocation("geode-web-api") == null) {
+ fail("unable to locate geode-web-api WAR file");
+ }
+ Wait.pause(5000);
+ final Host host = Host.getHost(0);
+ vm0 = host.getVM(0);
+ vm1 = host.getVM(1);
+ vm2 = host.getVM(2);
+ vm3 = host.getVM(3);
+ // gradle sets a property telling us where the build is located
+ final String buildDir = System.getProperty("geode.build.dir", System.getProperty("user.dir"));
+ Invoke.invokeInEveryVM(()-> System.setProperty("geode.build.dir", buildDir));
+ }
+
+ /**
+ * close the clients and teh servers
+ */
+ @Override
+ protected final void preTearDown() throws Exception {
+ vm0.invoke(() -> closeCache());
+ vm1.invoke(() -> closeCache());
+ vm2.invoke(() -> closeCache());
+ vm3.invoke(() -> closeCache());
+ }
+
+ /**
+ * close the cache
+ *
+ */
+ public static void closeCache() {
+ if (cache != null && !cache.isClosed()) {
+ cache.close();
+ cache.getDistributedSystem().disconnect();
+ }
+ }
+
+ protected static String createCache(VM currentVM) {
+
+ RestAPITestBase test = new RestAPITestBase(getTestMethodName());
+
+ final String hostName = currentVM.getHost().getHostName();
+ final int serverPort = AvailablePortHelper.getRandomAvailableTCPPort();
+
+ Properties props = new Properties();
+
+ props.setProperty(DistributionConfig.START_DEV_REST_API_NAME, "true");
+ props.setProperty(DistributionConfig.HTTP_SERVICE_BIND_ADDRESS_NAME, hostName);
+ props.setProperty(DistributionConfig.HTTP_SERVICE_PORT_NAME,String.valueOf(serverPort));
+
+
+ InternalDistributedSystem ds = test.getSystem(props);
+ cache = CacheFactory.create(ds);
+ return "http://" + hostName + ":" + serverPort + "/gemfire-api/v1";
+
+ }
+
+ public static String createCacheWithGroups (VM vm, final String groups, final String regionName ) {
+ RestAPITestBase test = new RestAPITestBase(getTestMethodName());
+
+ final String hostName = vm.getHost().getHostName();
+ final int serverPort = AvailablePortHelper.getRandomAvailableTCPPort();
+
+ Properties props = new Properties();
+
+ if(groups != null) {
+ props.put("groups", groups);
+ }
+
+ props.setProperty(DistributionConfig.START_DEV_REST_API_NAME, "true");
+ props.setProperty(DistributionConfig.HTTP_SERVICE_BIND_ADDRESS_NAME, hostName);
+ props.setProperty(DistributionConfig.HTTP_SERVICE_PORT_NAME, String.valueOf(serverPort));
+
+ InternalDistributedSystem ds = test.getSystem(props);
+ cache = CacheFactory.create(ds);
+
+ String restEndPoint = "http://" + hostName + ":" + serverPort + "/gemfire-api/v1";
+ return restEndPoint;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9b55879e/geode-assembly/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestAPIsAndInterOpsDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-assembly/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestAPIsAndInterOpsDUnitTest.java b/geode-assembly/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestAPIsAndInterOpsDUnitTest.java
new file mode 100644
index 0000000..0245fa0
--- /dev/null
+++ b/geode-assembly/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestAPIsAndInterOpsDUnitTest.java
@@ -0,0 +1,915 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.gemstone.gemfire.rest.internal.web.controllers;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import com.gemstone.gemfire.cache.AttributesFactory;
+import com.gemstone.gemfire.cache.Cache;
+import com.gemstone.gemfire.cache.CacheFactory;
+import com.gemstone.gemfire.cache.DataPolicy;
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.RegionAttributes;
+import com.gemstone.gemfire.cache.RegionFactory;
+import com.gemstone.gemfire.cache.RegionShortcut;
+import com.gemstone.gemfire.cache.client.ClientCache;
+import com.gemstone.gemfire.cache.client.ClientCacheFactory;
+import com.gemstone.gemfire.cache.client.ClientRegionFactory;
+import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
+import com.gemstone.gemfire.cache.client.internal.LocatorTestBase;
+import com.gemstone.gemfire.cache.server.CacheServer;
+import com.gemstone.gemfire.cache.server.ServerLoadProbe;
+import com.gemstone.gemfire.distributed.DistributedSystem;
+import com.gemstone.gemfire.distributed.internal.DistributionConfig;
+import com.gemstone.gemfire.internal.AvailablePort;
+import com.gemstone.gemfire.internal.AvailablePortHelper;
+import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
+import com.gemstone.gemfire.management.ManagementTestBase;
+import com.gemstone.gemfire.pdx.PdxInstance;
+import com.gemstone.gemfire.test.dunit.Host;
+import com.gemstone.gemfire.test.dunit.NetworkUtils;
+import com.gemstone.gemfire.test.dunit.SerializableCallable;
+import com.gemstone.gemfire.test.dunit.SerializableRunnable;
+import com.gemstone.gemfire.test.dunit.VM;
+
+/**
+ * Dunit Test containing inter - operations between REST Client and Gemfire cache client
+ * @author Nilkanth Patel
+ * @since 8.0
+ */
+
+public class RestAPIsAndInterOpsDUnitTest extends LocatorTestBase {
+
+ private static final long serialVersionUID = -254776154266339226L;
+
+ private ManagementTestBase helper;
+
+ public static final String PEOPLE_REGION_NAME = "People";
+
+ //private static RestTemplate restTemplate;
+
+ private static final String findAllPeopleQuery = "/queries?id=findAllPeople&q=SELECT%20*%20FROM%20/People";
+ private static final String findPeopleByGenderQuery = "/queries?id=filterByGender&q=SELECT%20*%20from%20/People%20where%20gender=$1";
+ private static final String findPeopleByLastNameQuery = "/queries?id=filterByLastName&q=SELECT%20*%20from%20/People%20where%20lastName=$1";
+
+ private static final String[] PARAM_QUERY_IDS_ARRAY = { "findAllPeople",
+ "filterByGender", "filterByLastName" };
+
+ final static String QUERY_ARGS = "["
+ + "{"
+ + "\"@type\": \"string\","
+ + "\"@value\": \"Patel\""
+ + "}"
+ + "]";
+
+ final static String PERSON_AS_JSON_CAS = "{"
+ + "\"@old\" :"
+ + "{"
+ + "\"@type\": \"com.gemstone.gemfire.rest.internal.web.controllers.Person\","
+ + "\"id\": 101," + " \"firstName\": \"Mithali\","
+ + " \"middleName\": \"Dorai\"," + " \"lastName\": \"Raj\","
+ + " \"birthDate\": \"12/04/1982\"," + "\"gender\": \"FEMALE\""
+ + "},"
+ + "\"@new\" :"
+ + "{"
+ + "\"@type\": \"com.gemstone.gemfire.rest.internal.web.controllers.Person\","
+ + "\"id\": 1101," + " \"firstName\": \"Virat\","
+ + " \"middleName\": \"Premkumar\"," + " \"lastName\": \"Kohli\","
+ + " \"birthDate\": \"08/11/1988\"," + "\"gender\": \"MALE\""
+ + "}"
+ + "}";
+
+ final static String PERSON_AS_JSON_REPLACE = "{"
+ + "\"@type\": \"com.gemstone.gemfire.rest.internal.web.controllers.Person\","
+ + "\"id\": 501," + " \"firstName\": \"Barack\","
+ + " \"middleName\": \"Hussein\"," + " \"lastName\": \"Obama\","
+ + " \"birthDate\": \"04/08/1961\"," + "\"gender\": \"MALE\""
+ + "}";
+
+ private static final String PERSON_LIST_AS_JSON = "[" + "{"
+ + "\"@type\": \"com.gemstone.gemfire.rest.internal.web.controllers.Person\","
+ + "\"id\": 3," + " \"firstName\": \"Nishka3\","
+ + " \"middleName\": \"Nilkanth3\"," + " \"lastName\": \"Patel3\","
+ + " \"birthDate\": \"07/31/2009\"," + "\"gender\": \"FEMALE\"" + "},"
+ + "{" + "\"@type\": \"com.gemstone.gemfire.rest.internal.web.controllers.Person\","
+ + "\"id\": 4," + " \"firstName\": \"Tanay4\","
+ + " \"middleName\": \"kiran4\"," + " \"lastName\": \"Patel4\","
+ + " \"birthDate\": \"23/08/2012\"," + "\"gender\": \"MALE\"" + "}," + "{"
+ + "\"@type\": \"com.gemstone.gemfire.rest.internal.web.controllers.Person\","
+ + "\"id\": 5," + " \"firstName\": \"Nishka5\","
+ + " \"middleName\": \"Nilkanth5\"," + " \"lastName\": \"Patel5\","
+ + " \"birthDate\": \"31/09/2009\"," + "\"gender\": \"FEMALE\"" + "},"
+ + "{" + "\"@type\": \"com.gemstone.gemfire.rest.internal.web.controllers.Person\","
+ + "\"id\": 6," + " \"firstName\": \"Tanay6\","
+ + " \"middleName\": \"Kiran6\"," + " \"lastName\": \"Patel\","
+ + " \"birthDate\": \"23/08/2012\"," + "\"gender\": \"MALE\"" + "}," + "{"
+ + "\"@type\": \"com.gemstone.gemfire.rest.internal.web.controllers.Person\","
+ + "\"id\": 7," + " \"firstName\": \"Nishka7\","
+ + " \"middleName\": \"Nilkanth7\"," + " \"lastName\": \"Patel\","
+ + " \"birthDate\": \"31/09/2009\"," + "\"gender\": \"FEMALE\"" + "},"
+ + "{" + "\"@type\": \"com.gemstone.gemfire.rest.internal.web.controllers.Person\","
+ + "\"id\": 8," + " \"firstName\": \"Tanay8\","
+ + " \"middleName\": \"kiran8\"," + " \"lastName\": \"Patel\","
+ + " \"birthDate\": \"23/08/2012\"," + "\"gender\": \"MALE\"" + "}," + "{"
+ + "\"@type\": \"com.gemstone.gemfire.rest.internal.web.controllers.Person\","
+ + "\"id\": 9," + " \"firstName\": \"Nishka9\","
+ + " \"middleName\": \"Nilkanth9\"," + " \"lastName\": \"Patel\","
+ + " \"birthDate\": \"31/09/2009\"," + "\"gender\": \"FEMALE\"" + "},"
+ + "{" + "\"@type\": \"com.gemstone.gemfire.rest.internal.web.controllers.Person\","
+ + "\"id\": 10," + " \"firstName\": \"Tanay10\","
+ + " \"middleName\": \"kiran10\"," + " \"lastName\": \"Patel\","
+ + " \"birthDate\": \"23/08/2012\"," + "\"gender\": \"MALE\"" + "}," + "{"
+ + "\"@type\": \"com.gemstone.gemfire.rest.internal.web.controllers.Person\","
+ + "\"id\": 11," + " \"firstName\": \"Nishka11\","
+ + " \"middleName\": \"Nilkanth11\"," + " \"lastName\": \"Patel\","
+ + " \"birthDate\": \"31/09/2009\"," + "\"gender\": \"FEMALE\"" + "},"
+ + "{" + "\"@type\": \"com.gemstone.gemfire.rest.internal.web.controllers.Person\","
+ + "\"id\": 12," + " \"firstName\": \"Tanay12\","
+ + " \"middleName\": \"kiran12\"," + " \"lastName\": \"Patel\","
+ + " \"birthDate\": \"23/08/2012\"," + "\"gender\": \"MALE\"" + "}" + "]";
+
+ public RestAPIsAndInterOpsDUnitTest(String name) {
+ super(name);
+ this.helper = new ManagementTestBase(name);
+
+ }
+
+ public void setUp() throws Exception {
+ disconnectAllFromDS();
+ super.setUp();
+ }
+
+ @Override
+ protected final void postTearDownLocatorTestBase() throws Exception {
+ disconnectAllFromDS();
+ }
+
+ public static String startBridgeServerWithRestServiceOnInVM(VM vm, final String[] groups, final String locators, final String[] regions, final ServerLoadProbe probe) {
+
+ final String hostName = vm.getHost().getHostName();
+ final int serverPort = AvailablePortHelper.getRandomAvailableTCPPort();
+
+ //create Cache of given VM and start HTTP service with REST APIs service
+ new RestAPIsAndInterOpsDUnitTest("temp").startBridgeServer(hostName, serverPort, groups, locators, regions, probe);
+
+ String restEndPoint = "http://" + hostName + ":" + serverPort + "/gemfire-api/v1";
+ return restEndPoint;
+ }
+
+ @SuppressWarnings("deprecation")
+ protected int startBridgeServer(String hostName, int restServicerPort, final String[] groups, final String locators, final String[] regions, final ServerLoadProbe probe) {
+
+ Properties props = new Properties();
+ props.setProperty(DistributionConfig.MCAST_PORT_NAME, String.valueOf(0));
+ props.setProperty(DistributionConfig.LOCATORS_NAME, locators);
+ props.setProperty(DistributionConfig.START_DEV_REST_API_NAME, "true");
+ props.setProperty(DistributionConfig.HTTP_SERVICE_BIND_ADDRESS_NAME, hostName);
+ props.setProperty(DistributionConfig.HTTP_SERVICE_PORT_NAME, String.valueOf(restServicerPort));
+
+ DistributedSystem ds = getSystem(props);
+ Cache cache = CacheFactory.create(ds);
+ ((GemFireCacheImpl)cache).setReadSerialized(true);
+ AttributesFactory factory = new AttributesFactory();
+
+ factory.setEnableBridgeConflation(true);
+ factory.setDataPolicy(DataPolicy.REPLICATE);
+ RegionAttributes attrs = factory.create();
+ for(int i = 0; i < regions.length; i++) {
+ cache.createRegion(regions[i], attrs);
+ }
+
+ CacheServer server = cache.addCacheServer();
+ final int serverPort = AvailablePortHelper.getRandomAvailableTCPPort();
+ server.setPort(serverPort);
+ server.setGroups(groups);
+ server.setLoadProbe(probe);
+ try {
+ server.start();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ remoteObjects.put(CACHE_KEY, cache);
+ return new Integer(serverPort);
+ }
+
+ public static void doPutsInClientCache() {
+ ClientCache cache = GemFireCacheImpl.getInstance();
+ assertNotNull(cache);
+ Region<String, Object> region = cache.getRegion(PEOPLE_REGION_NAME);
+
+ //put person object
+ final Person person1 = new Person(101L, "Mithali", "Dorai", "Raj", DateTimeUtils.createDate(1982, Calendar.DECEMBER, 4), Gender.FEMALE);
+ final Person person2 = new Person(102L, "Sachin", "Ramesh", "Tendulkar", DateTimeUtils.createDate(1975, Calendar.DECEMBER, 14), Gender.MALE);
+ final Person person3 = new Person(103L, "Saurabh", "Baburav", "Ganguly", DateTimeUtils.createDate(1972, Calendar.AUGUST, 29), Gender.MALE);
+ final Person person4 = new Person(104L, "Rahul", "subrymanyam", "Dravid", DateTimeUtils.createDate(1979, Calendar.MARCH, 17), Gender.MALE);
+ final Person person5 = new Person(105L, "Jhulan", "Chidambaram", "Goswami", DateTimeUtils.createDate(1983, Calendar.NOVEMBER, 25), Gender.FEMALE);
+
+ region.put("1", person1);
+ region.put("2", person2);
+ region.put("3", person3);
+ region.put("4", person4);
+ region.put("5", person5);
+
+ final Person person6 = new Person(101L, "Rahul", "Rajiv", "Gndhi", DateTimeUtils.createDate(1970, Calendar.MAY, 14), Gender.MALE);
+ final Person person7 = new Person(102L, "Narendra", "Damodar", "Modi", DateTimeUtils.createDate(1945, Calendar.DECEMBER, 24), Gender.MALE);
+ final Person person8 = new Person(103L, "Atal", "Bihari", "Vajpayee", DateTimeUtils.createDate(1920, Calendar.AUGUST, 9), Gender.MALE);
+ final Person person9 = new Person(104L, "Soniya", "Rajiv", "Gandhi", DateTimeUtils.createDate(1929, Calendar.MARCH, 27), Gender.FEMALE);
+ final Person person10 = new Person(104L, "Priyanka", "Robert", "Gandhi", DateTimeUtils.createDate(1973, Calendar.APRIL, 15), Gender.FEMALE);
+
+ final Person person11 = new Person(104L, "Murali", "Manohar", "Joshi", DateTimeUtils.createDate(1923, Calendar.APRIL, 25), Gender.MALE);
+ final Person person12 = new Person(104L, "Lalkrishna", "Parmhansh", "Advani", DateTimeUtils.createDate(1910, Calendar.JANUARY, 01), Gender.MALE);
+ final Person person13 = new Person(104L, "Shushma", "kumari", "Swaraj", DateTimeUtils.createDate(1943, Calendar.AUGUST, 10), Gender.FEMALE);
+ final Person person14 = new Person(104L, "Arun", "raman", "jetly", DateTimeUtils.createDate(1942, Calendar.OCTOBER, 27), Gender.MALE);
+ final Person person15 = new Person(104L, "Amit", "kumar", "shah", DateTimeUtils.createDate(1958, Calendar.DECEMBER, 21), Gender.MALE);
+ final Person person16 = new Person(104L, "Shila", "kumari", "Dixit", DateTimeUtils.createDate(1927, Calendar.FEBRUARY, 15), Gender.FEMALE);
+
+ Map<String, Object> userMap = new HashMap<String, Object>();
+ userMap.put("6", person6);
+ userMap.put("7", person7);
+ userMap.put("8", person8);
+ userMap.put("9", person9);
+ userMap.put("10", person10);
+ userMap.put("11", person11);
+ userMap.put("12", person12);
+ userMap.put("13", person13);
+ userMap.put("14", person14);
+ userMap.put("15", person15);
+ userMap.put("16", person16);
+
+ region.putAll(userMap);
+
+ if (cache != null)
+ cache.getLogger().info("Gemfire Cache Client: Puts successfully done");
+
+ }
+
+ public static void doQueryOpsUsingRestApis(String restEndpoint) {
+ String currentQueryOp = null;
+ try {
+ // Query TestCase-1 :: Prepare parameterized Queries
+ {
+ currentQueryOp = "findAllPeopleQuery";
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ HttpPost post = new HttpPost(restEndpoint + findAllPeopleQuery);
+ post.addHeader("Content-Type", "application/json");
+ post.addHeader("Accept", "application/json");
+ CloseableHttpResponse createNamedQueryResponse = httpclient.execute(post);
+ assertEquals(createNamedQueryResponse.getStatusLine().getStatusCode(), 201);
+ assertNotNull(createNamedQueryResponse.getEntity());
+ createNamedQueryResponse.close();
+
+
+ post = new HttpPost(restEndpoint + findPeopleByGenderQuery);
+ post.addHeader("Content-Type", "application/json");
+ post.addHeader("Accept", "application/json");
+ createNamedQueryResponse = httpclient.execute(post);
+ assertEquals(createNamedQueryResponse.getStatusLine().getStatusCode(), 201);
+ assertNotNull(createNamedQueryResponse.getEntity());
+ createNamedQueryResponse.close();
+
+
+ post = new HttpPost(restEndpoint + findPeopleByLastNameQuery);
+ post.addHeader("Content-Type", "application/json");
+ post.addHeader("Accept", "application/json");
+ createNamedQueryResponse = httpclient.execute(post);
+ assertEquals(createNamedQueryResponse.getStatusLine().getStatusCode(), 201);
+ assertNotNull(createNamedQueryResponse.getEntity());
+ createNamedQueryResponse.close();
+ }
+
+ // Query TestCase-2 :: List all parameterized queries
+ {
+ currentQueryOp = "listAllQueries";
+ HttpGet get = new HttpGet(restEndpoint + "/queries");
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ CloseableHttpResponse listAllQueriesResponse = httpclient.execute(get);
+ assertEquals(listAllQueriesResponse.getStatusLine().getStatusCode(), 200);
+ assertNotNull(listAllQueriesResponse.getEntity());
+
+ HttpEntity entity = listAllQueriesResponse.getEntity();
+ InputStream content = entity.getContent();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ content));
+ String line;
+ StringBuffer sb = new StringBuffer();
+ while ((line = reader.readLine()) != null) {
+ sb.append(line);
+ }
+ listAllQueriesResponse.close();
+
+ // Check whether received response contains expected query IDs.
+
+ JSONObject jsonObject = new JSONObject(sb.toString());
+ JSONArray jsonArray = jsonObject.getJSONArray("queries");
+ for (int i = 0; i < jsonArray.length(); i++) {
+ assertTrue(
+ "PREPARE_PARAMETERIZED_QUERY: function IDs are not matched",
+ Arrays.asList(PARAM_QUERY_IDS_ARRAY).contains(
+ jsonArray.getJSONObject(i).getString("id")));
+ }
+ }
+
+ // Query TestCase-3 :: Run the specified named query passing in scalar values for query parameters.
+ {
+ currentQueryOp = "filterByLastName";
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ HttpPost post = new HttpPost(restEndpoint + "/queries/filterByLastName");
+ post.addHeader("Content-Type", "application/json");
+ post.addHeader("Accept", "application/json");
+ StringEntity entity = new StringEntity(QUERY_ARGS);
+ post.setEntity(entity);
+ CloseableHttpResponse runNamedQueryResponse = httpclient.execute(post);
+
+ assertEquals(200, runNamedQueryResponse.getStatusLine().getStatusCode());
+ assertNotNull(runNamedQueryResponse.getEntity());
+ }
+ } catch ( Exception e ) {
+ throw new RuntimeException("unexpected exception", e);
+ }
+ }
+
+ public static void verifyUpdatesInClientCache() {
+ ClientCache cache = GemFireCacheImpl.getInstance();
+ assertNotNull(cache);
+ Region<String, Object> region = cache.getRegion(PEOPLE_REGION_NAME);
+
+ {
+ Person expectedPerson = new Person(3L, "Nishka3", "Nilkanth3", "Patel3", DateTimeUtils.createDate(2009, Calendar.JULY, 31), Gender.FEMALE );
+ Object value = region.get("3");
+ if (value instanceof PdxInstance) {
+ PdxInstance pi3 = (PdxInstance) value;
+ Person actualPerson = (Person) pi3.getObject();
+ assertEquals(actualPerson.getId(), expectedPerson.getId());
+ assertEquals(actualPerson.getFirstName(), expectedPerson.getFirstName());
+ assertEquals(actualPerson.getMiddleName(), expectedPerson.getMiddleName());
+ assertEquals(actualPerson.getLastName(), expectedPerson.getLastName());
+ assertEquals(actualPerson.getBirthDate(), expectedPerson.getBirthDate());
+ assertEquals(actualPerson.getGender(), expectedPerson.getGender());
+ } else if (value instanceof Person) {
+ fail("VerifyUpdatesInClientCache, Get on key 3, Expected to get value of type PdxInstance ");
+ }
+ }
+
+
+ //TODO: uncomment it once following issue encountered in put?op=CAS is fixed or document the issue
+ // CAS functionality is not working in following test case
+ // step-1: Java client, Region.put("K", A);
+ //Step-2: Rest CAS request for key "K" with data "@old" = A. CAS is failing as existing PdxInstance in cache and
+ // PdxInstance generated from JSON (CAS request) does not match as their value's type are getting changed
+ /*
+ //verify update on key "1"
+ {
+ Object obj = region.get("1");
+ if (obj instanceof PdxInstance) {
+ PdxInstance pi = (PdxInstance)obj;
+ Person p1 = (Person)pi.getObject();
+ System.out.println("Nilkanth1 : verifyUpdatesInClientCache() : GET ON KEY=1" + p1.toString());
+ }else {
+ System.out.println("Nilkanth1 : verifyUpdatesInClientCache() GET ON KEY=1 returned OBJECT: " + obj.toString());
+ }
+ }
+ */
+
+ //verify update on key "2"
+ {
+ Person expectedPerson = new Person(501L, "Barack", "Hussein", "Obama", DateTimeUtils.createDate(1961, Calendar.APRIL, 8), Gender.MALE );
+ Object value = region.get("2");
+ if (value instanceof PdxInstance) {
+ PdxInstance pi3 = (PdxInstance) value;
+ Person actualPerson = (Person) pi3.getObject();
+ assertEquals(actualPerson.getId(), expectedPerson.getId());
+ assertEquals(actualPerson.getFirstName(), expectedPerson.getFirstName());
+ assertEquals(actualPerson.getMiddleName(), expectedPerson.getMiddleName());
+ assertEquals(actualPerson.getLastName(), expectedPerson.getLastName());
+ assertEquals(actualPerson.getBirthDate(), expectedPerson.getBirthDate());
+ assertEquals(actualPerson.getGender(), expectedPerson.getGender());
+ }else {
+ fail("VerifyUpdatesInClientCache, Get on key 2, Expected to get value of type PdxInstance ");
+ }
+ }
+
+ //verify Deleted key "13"
+ {
+ Object obj = region.get("13");
+ assertEquals(obj, null);
+
+ obj = region.get("14");
+ assertEquals(obj, null);
+
+ obj = region.get("15");
+ assertEquals(obj, null);
+
+ obj = region.get("16");
+ assertEquals(obj, null);
+ }
+
+ }
+
+ public static void doUpdatesUsingRestApis(String restEndpoint) {
+ //UPdate keys using REST calls
+ {
+
+ try {
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ HttpPut put = new HttpPut(restEndpoint
+ + "/People/3,4,5,6,7,8,9,10,11,12");
+ put.addHeader("Content-Type", "application/json");
+ put.addHeader("Accept", "application/json");
+ StringEntity entity = new StringEntity(PERSON_LIST_AS_JSON);
+ put.setEntity(entity);
+ CloseableHttpResponse result = httpclient.execute(put);
+ } catch (Exception e) {
+ throw new RuntimeException("unexpected exception", e);
+ }
+ }
+
+ //Delete Single keys
+ {
+ try {
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ HttpDelete delete = new HttpDelete(restEndpoint + "/People/13");
+ delete.addHeader("Content-Type", "application/json");
+ delete.addHeader("Accept", "application/json");
+ CloseableHttpResponse result = httpclient.execute(delete);
+ } catch (Exception e) {
+ throw new RuntimeException("unexpected exception", e);
+ }
+ }
+
+ //Delete set of keys
+ {
+ try {
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ HttpDelete delete = new HttpDelete(restEndpoint + "/People/14,15,16");
+ delete.addHeader("Content-Type", "application/json");
+ delete.addHeader("Accept", "application/json");
+ CloseableHttpResponse result = httpclient.execute(delete);
+ } catch (Exception e) {
+ throw new RuntimeException("unexpected exception", e);
+ }
+ }
+
+ //REST put?op=CAS for key 1
+ /*
+ try {
+ {
+ HttpEntity<Object> entity = new HttpEntity<Object>(PERSON_AS_JSON_CAS, headers);
+ ResponseEntity<String> result = RestTestUtils.getRestTemplate().exchange(
+ restEndpoint + "/People/1?op=cas",
+ HttpMethod.PUT, entity, String.class);
+ }
+ } catch (HttpClientErrorException e) {
+
+ fail("Caught HttpClientErrorException while doing put with op=cas");
+ }catch (HttpServerErrorException se) {
+ fail("Caught HttpServerErrorException while doing put with op=cas");
+ }
+ */
+
+ //REST put?op=REPLACE for key 2
+ {
+ /*HttpEntity<Object> entity = new HttpEntity<Object>(PERSON_AS_JSON_REPLACE, headers);
+ ResponseEntity<String> result = RestTestUtils.getRestTemplate().exchange(
+ restEndpoint + "/People/2?op=replace",
+ HttpMethod.PUT, entity, String.class);*/
+
+ try {
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ HttpPut put = new HttpPut(restEndpoint
+ + "/People/2?op=replace");
+ put.addHeader("Content-Type", "application/json");
+ put.addHeader("Accept", "application/json");
+ StringEntity entity = new StringEntity(PERSON_AS_JSON_REPLACE);
+ put.setEntity(entity);
+ CloseableHttpResponse result = httpclient.execute(put);
+ } catch (Exception e) {
+ throw new RuntimeException("unexpected exception", e);
+ }
+ }
+ }
+
+ public static void fetchRestServerEndpoints(String restEndpoint) {
+ HttpGet get = new HttpGet(restEndpoint + "/servers");
+ get.addHeader("Content-Type", "application/json");
+ get.addHeader("Accept", "application/json");
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ CloseableHttpResponse response;
+
+ try {
+ response = httpclient.execute(get);
+ HttpEntity entity = response.getEntity();
+ InputStream content = entity.getContent();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ content));
+ String line;
+ StringBuffer str = new StringBuffer();
+ while ((line = reader.readLine()) != null) {
+ str.append(line);
+ }
+
+ //validate the satus code
+ assertEquals(response.getStatusLine().getStatusCode(), 200);
+
+ if(response.getStatusLine().getStatusCode() == 200) {
+ JSONArray jsonArray = new JSONArray(str.toString());
+
+ //verify total number of REST service endpoints in DS
+ assertEquals(jsonArray.length(), 2);
+ }
+
+ } catch (ClientProtocolException e) {
+ e.printStackTrace();
+ fail(" Rest Request should not have thrown ClientProtocolException!");
+ } catch (IOException e) {
+ e.printStackTrace();
+ fail(" Rest Request should not have thrown IOException!");
+ } catch (JSONException e) {
+ e.printStackTrace();
+ fail(" Rest Request should not have thrown JSONException!");
+ }
+
+ }
+
+ public static void doGetsUsingRestApis(String restEndpoint) {
+
+ //HttpHeaders headers = setAcceptAndContentTypeHeaders();
+ String currentOperation = null;
+ JSONObject jObject;
+ JSONArray jArray;
+ try {
+ //1. Get on key="1" and validate result.
+ {
+ currentOperation = "GET on key 1";
+
+ HttpGet get = new HttpGet(restEndpoint + "/People/1");
+ get.addHeader("Content-Type", "application/json");
+ get.addHeader("Accept", "application/json");
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ CloseableHttpResponse response = httpclient.execute(get);
+
+ HttpEntity entity = response.getEntity();
+ InputStream content = entity.getContent();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ content));
+ String line;
+ StringBuffer str = new StringBuffer();
+ while ((line = reader.readLine()) != null) {
+ str.append(line);
+ }
+
+ jObject = new JSONObject(str.toString());
+
+ assertEquals(jObject.get("id"), 101);
+ assertEquals(jObject.get("firstName"), "Mithali");
+ assertEquals(jObject.get("middleName"), "Dorai");
+ assertEquals(jObject.get("lastName"), "Raj");
+ assertEquals(jObject.get("gender"), Gender.FEMALE.name());
+ }
+
+ //2. Get on key="16" and validate result.
+ {
+ currentOperation = "GET on key 16";
+
+
+ HttpGet get = new HttpGet(restEndpoint + "/People/16");
+ get.addHeader("Content-Type", "application/json");
+ get.addHeader("Accept", "application/json");
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ CloseableHttpResponse response = httpclient.execute(get);
+
+ HttpEntity entity = response.getEntity();
+ InputStream content = entity.getContent();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ content));
+ String line;
+ StringBuffer str = new StringBuffer();
+ while ((line = reader.readLine()) != null) {
+ str.append(line);
+ }
+
+ jObject = new JSONObject(str.toString());
+
+
+ assertEquals(jObject.get("id"), 104);
+ assertEquals(jObject.get("firstName"), "Shila");
+ assertEquals(jObject.get("middleName"), "kumari");
+ assertEquals(jObject.get("lastName"), "Dixit");
+ assertEquals(jObject.get("gender"), Gender.FEMALE.name());
+ }
+
+ //3. Get all (getAll) entries in Region
+ {
+
+ HttpGet get = new HttpGet(restEndpoint + "/People");
+ get.addHeader("Content-Type", "application/json");
+ get.addHeader("Accept", "application/json");
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ CloseableHttpResponse result = httpclient.execute(get);
+ assertEquals(result.getStatusLine().getStatusCode(), 200);
+ assertNotNull(result.getEntity());
+
+ HttpEntity entity = result.getEntity();
+ InputStream content = entity.getContent();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ content));
+ String line;
+ StringBuffer sb = new StringBuffer();
+ while ((line = reader.readLine()) != null) {
+ sb.append(line);
+ }
+ result.close();
+
+ try {
+ jObject = new JSONObject(sb.toString());
+ jArray = jObject.getJSONArray("People");
+ assertEquals(jArray.length(), 16);
+ } catch (JSONException e) {
+ fail(" Rest Request ::" + currentOperation + " :: should not have thrown JSONException ");
+ }
+ }
+
+ //4. GetAll?limit=10 (10 entries) and verify results
+ {
+ HttpGet get = new HttpGet(restEndpoint + "/People?limit=10");
+ get.addHeader("Content-Type", "application/json");
+ get.addHeader("Accept", "application/json");
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ CloseableHttpResponse response = httpclient.execute(get);
+ assertEquals(response.getStatusLine().getStatusCode(), 200);
+ assertNotNull(response.getEntity());
+
+ HttpEntity entity = response.getEntity();
+ InputStream content = entity.getContent();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ content));
+ String line;
+ StringBuffer str = new StringBuffer();
+ while ((line = reader.readLine()) != null) {
+ str.append(line);
+ }
+
+ try {
+ jObject = new JSONObject(str.toString());
+ jArray = jObject.getJSONArray("People");
+ assertEquals(jArray.length(), 10);
+ } catch (JSONException e) {
+ fail(" Rest Request ::" + currentOperation + " :: should not have thrown JSONException ");
+ }
+ }
+
+ //5. Get keys - List all keys in region
+ {
+
+ HttpGet get = new HttpGet(restEndpoint + "/People/keys");
+ get.addHeader("Content-Type", "application/json");
+ get.addHeader("Accept", "application/json");
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ CloseableHttpResponse response = httpclient.execute(get);
+ assertEquals(response.getStatusLine().getStatusCode(), 200);
+ assertNotNull(response.getEntity());
+
+ HttpEntity entity = response.getEntity();
+ InputStream content = entity.getContent();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ content));
+ String line;
+ StringBuffer str = new StringBuffer();
+ while ((line = reader.readLine()) != null) {
+ str.append(line);
+ }
+
+ try {
+ jObject = new JSONObject(str.toString());
+ jArray = jObject.getJSONArray("keys");
+ assertEquals(jArray.length(), 16);
+ } catch (JSONException e) {
+ fail(" Rest Request ::" + currentOperation + " :: should not have thrown JSONException ");
+ }
+ }
+
+ //6. Get data for specific keys
+ {
+
+ HttpGet get = new HttpGet(restEndpoint + "/People/1,3,5,7,9,11");
+ get.addHeader("Content-Type", "application/json");
+ get.addHeader("Accept", "application/json");
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ CloseableHttpResponse response = httpclient.execute(get);
+ assertEquals(response.getStatusLine().getStatusCode(), 200);
+ assertNotNull(response.getEntity());
+
+ HttpEntity entity = response.getEntity();
+ InputStream content = entity.getContent();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ content));
+ String line;
+ StringBuffer str = new StringBuffer();
+ while ((line = reader.readLine()) != null) {
+ str.append(line);
+ }
+
+ try {
+ jObject = new JSONObject(str.toString());
+ jArray = jObject.getJSONArray("People");
+ assertEquals(jArray.length(), 6);
+
+ } catch (JSONException e) {
+ fail(" Rest Request ::" + currentOperation + " :: should not have thrown JSONException ");
+ }
+ }
+ }catch ( Exception e ) {
+ throw new RuntimeException("unexpected exception", e);
+ }
+ }
+
+ public static void createRegionInClientCache() {
+ ClientCache cache = GemFireCacheImpl.getInstance();
+ assertNotNull(cache);
+ ClientRegionFactory<String, Object> crf = cache
+ .createClientRegionFactory(ClientRegionShortcut.PROXY);
+ Region<String, Object> region = crf.create(PEOPLE_REGION_NAME);
+
+ }
+
+ public static void createRegionInManager() {
+ Cache cache = GemFireCacheImpl.getInstance();
+ assertNotNull(cache);
+
+ RegionFactory<String, Object> rf = cache
+ .createRegionFactory(RegionShortcut.REPLICATE);
+ Region<String, Object> region = rf.create(PEOPLE_REGION_NAME);
+ }
+
+ public static void createRegionInPeerServer() {
+ Cache cache = GemFireCacheImpl.getInstance();
+ assertNotNull(cache);
+
+ RegionFactory<String, Object> rf = cache
+ .createRegionFactory(RegionShortcut.REPLICATE);
+ Region<String, Object> region = rf.create(PEOPLE_REGION_NAME);
+ }
+
+ /**
+ * InterOps Test between REST-client, Peer Cache Client and Client Cache
+ * @throws Exception
+ */
+
+ public void testInterOpsWithReplicatedRegion() throws Exception {
+
+ final Host host = Host.getHost(0);
+ VM locator = host.getVM(0);
+ VM manager = host.getVM(1);
+ VM server = host.getVM(2);
+ VM client = host.getVM(3);
+
+ // start locator
+ int locatorPort = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET);
+
+ startLocatorInVM(locator, locatorPort, "");
+
+ // find locators
+ String locators = NetworkUtils.getServerHostName(locator.getHost()) + "[" + locatorPort
+ + "]";
+
+ // start manager (peer cache)
+ int managerPort = startManagerInVM(manager,/* groups */null, locators,
+ new String[] {REGION_NAME}, CacheServer.DEFAULT_LOAD_PROBE);
+
+ //start startCacheServer With RestService enabled
+ String restEndpoint = (String)server.invoke(RestAPIsAndInterOpsDUnitTest.class,
+ "startBridgeServerWithRestServiceOnInVM", new Object[] { server , null, locators, new String[] {REGION_NAME}, CacheServer.DEFAULT_LOAD_PROBE });
+
+ // create a client cache
+ createClientCacheInVM(client, NetworkUtils.getServerHostName(locator.getHost()),
+ locatorPort);
+
+ // create region in Manager, peer cache and Client cache nodes
+ manager.invoke(() -> RestAPIsAndInterOpsDUnitTest.createRegionInManager());
+ server.invoke(() -> RestAPIsAndInterOpsDUnitTest.createRegionInPeerServer());
+ client.invoke(() -> RestAPIsAndInterOpsDUnitTest.createRegionInClientCache());
+
+ // do some person puts from clientcache
+ client.invoke(() -> RestAPIsAndInterOpsDUnitTest.doPutsInClientCache());
+
+ //TEST: fetch all available REST endpoints
+ RestAPIsAndInterOpsDUnitTest.fetchRestServerEndpoints(restEndpoint);
+
+ // Controller VM - config REST Client and make HTTP calls
+ RestAPIsAndInterOpsDUnitTest.doGetsUsingRestApis(restEndpoint);
+
+ //update Data using REST APIs
+ RestAPIsAndInterOpsDUnitTest.doUpdatesUsingRestApis(restEndpoint);
+
+ client.invoke(() -> RestAPIsAndInterOpsDUnitTest.verifyUpdatesInClientCache());
+
+ //Querying
+ RestAPIsAndInterOpsDUnitTest.doQueryOpsUsingRestApis(restEndpoint);
+
+ // stop the client and make sure the bridge server notifies
+ // stopBridgeMemberVM(client);
+ helper.closeCache(locator);
+ helper.closeCache(manager);
+ helper.closeCache(server);
+ helper.closeCache(client);
+
+ }
+
+ private void createClientCacheInVM(VM vm, final String host, final int port) throws Exception {
+ SerializableRunnable connect = new SerializableRunnable(
+ "Start Cache client") {
+ public void run() {
+ // Connect using the GemFire locator and create a Caching_Proxy cache
+ ClientCache c = new ClientCacheFactory().setPdxReadSerialized(true).addPoolLocator(host, port)
+ .create();
+
+ Region r = c.createClientRegionFactory(
+ ClientRegionShortcut.PROXY).create(REGION_NAME);
+ }
+ };
+
+ if (vm == null) {
+ connect.run();
+ } else {
+ vm.invoke(connect);
+ }
+ }
+
+ private int startManagerInVM(VM vm, final String[] groups,
+ final String locators, final String[] regions, final ServerLoadProbe probe) {
+ SerializableCallable connect = new SerializableCallable("Start Manager ") {
+ public Object call() throws IOException {
+ Properties props = new Properties();
+ props
+ .setProperty(DistributionConfig.MCAST_PORT_NAME, String.valueOf(0));
+ props.setProperty(DistributionConfig.LOCATORS_NAME, locators);
+
+ props.setProperty("jmx-manager", "true");
+ props.setProperty("jmx-manager-start", "true");
+ props.setProperty(DistributionConfig.JMX_MANAGER_PORT_NAME, "0");
+
+ final int httpPort = AvailablePortHelper.getRandomAvailableTCPPort();
+ //Set REST service related configuration
+ props.setProperty(DistributionConfig.START_DEV_REST_API_NAME, "true");
+ props.setProperty(DistributionConfig.HTTP_SERVICE_BIND_ADDRESS_NAME, "localhost");
+ props.setProperty(DistributionConfig.HTTP_SERVICE_PORT_NAME, String.valueOf(httpPort));
+
+ DistributedSystem ds = getSystem(props);
+ Cache cache = CacheFactory.create(ds);
+ AttributesFactory factory = new AttributesFactory();
+
+ factory.setEnableBridgeConflation(true);
+ factory.setDataPolicy(DataPolicy.REPLICATE);
+ RegionAttributes attrs = factory.create();
+ for (int i = 0; i < regions.length; i++) {
+ cache.createRegion(regions[i], attrs);
+ }
+ CacheServer server = cache.addCacheServer();
+ final int serverPort = AvailablePortHelper.getRandomAvailableTCPPort();
+ server.setPort(serverPort);
+ server.setGroups(groups);
+ server.setLoadProbe(probe);
+ server.start();
+
+ return new Integer(serverPort);
+ }
+ };
+ Integer port = (Integer) vm.invoke(connect);
+ return port.intValue();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9b55879e/geode-assembly/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestAPIsOnGroupsFunctionExecutionDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-assembly/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestAPIsOnGroupsFunctionExecutionDUnitTest.java b/geode-assembly/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestAPIsOnGroupsFunctionExecutionDUnitTest.java
new file mode 100644
index 0000000..1ae3810
--- /dev/null
+++ b/geode-assembly/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestAPIsOnGroupsFunctionExecutionDUnitTest.java
@@ -0,0 +1,306 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.gemstone.gemfire.rest.internal.web.controllers;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.json.JSONArray;
+
+import com.gemstone.gemfire.cache.execute.Function;
+import com.gemstone.gemfire.cache.execute.FunctionContext;
+import com.gemstone.gemfire.cache.execute.FunctionService;
+import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
+import com.gemstone.gemfire.test.dunit.Host;
+import com.gemstone.gemfire.test.dunit.IgnoredException;
+import com.gemstone.gemfire.test.dunit.LogWriterUtils;
+import com.gemstone.gemfire.test.dunit.SerializableCallable;
+import com.gemstone.gemfire.test.dunit.VM;
+
+public class RestAPIsOnGroupsFunctionExecutionDUnitTest extends RestAPITestBase {
+
+ public RestAPIsOnGroupsFunctionExecutionDUnitTest(String name) {
+ super(name);
+ }
+
+ public void setUp() throws Exception {
+ super.setUp();
+ final Host host = Host.getHost(0);
+ }
+
+ private void registerFunction(VM vm) {
+ vm.invoke(new SerializableCallable() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Object call() throws Exception {
+ FunctionService.registerFunction(new OnGroupsFunction());
+ return null;
+ }
+ });
+ }
+
+ static class OnGroupsFunction implements Function {
+ private static final long serialVersionUID = -1032915440862585532L;
+ public static final String Id = "OnGroupsFunction";
+ public static int invocationCount;
+
+ @Override
+ public void execute(FunctionContext context) {
+ LogWriterUtils.getLogWriter().fine("SWAP:1:executing OnGroupsFunction:"+invocationCount);
+ InternalDistributedSystem ds = InternalDistributedSystem.getConnectedInstance();
+ invocationCount++;
+ ArrayList<String> l = (ArrayList<String>) context.getArguments();
+ if (l != null) {
+ assertFalse(Collections.disjoint(l, ds.getDistributedMember().getGroups()));
+ }
+ context.getResultSender().lastResult(Boolean.TRUE);
+ }
+
+ @Override
+ public String getId() {
+ return Id;
+ }
+
+ @Override
+ public boolean hasResult() {
+ return true;
+ }
+
+ @Override
+ public boolean optimizeForWrite() {
+ return false;
+ }
+
+ @Override
+ public boolean isHA() {
+ return false;
+ }
+ }
+
+
+ public static void executeFunctionThroughRestCall(List<String> restURLs) {
+ Random randomGenerator = new Random();
+ int index = randomGenerator.nextInt(restURLs.size());
+
+ try {
+
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ CloseableHttpResponse response = null;
+ HttpPost post = new HttpPost(restURLs.get(index) + "/functions/OnGroupsFunction?onGroups=g0,g1");
+ post.addHeader("Content-Type", "application/json");
+ post.addHeader("Accept", "application/json");
+ LogWriterUtils.getLogWriter().info("Request POST : " + post.toString());
+ response = httpclient.execute(post);
+
+ HttpEntity entity = response.getEntity();
+ InputStream content = entity.getContent();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ content));
+ String line;
+ StringBuffer sb = new StringBuffer();
+ while ((line = reader.readLine()) != null) {
+ sb.append(line);
+ }
+ LogWriterUtils.getLogWriter().info("Response : " + sb.toString());
+
+ //verify response status code. expected status code is 200 OK.
+ assertEquals(response.getStatusLine().getStatusCode(), 200);
+
+
+ //verify response hasbody flag, expected is true.
+ assertNotNull(response.getEntity());
+
+
+ response.close();
+
+ //verify function execution result
+ JSONArray resultArray = new JSONArray(sb.toString());
+ assertEquals(resultArray.length(), 3);
+
+ } catch (Exception e) {
+ throw new RuntimeException("unexpected exception", e);
+ }
+
+ }
+
+ public static void executeFunctionOnMemberThroughRestCall(List<String> restURLs) {
+ Random randomGenerator = new Random();
+ int index = randomGenerator.nextInt(restURLs.size());
+
+ //Testcase-1: Executing function on non-existing group.
+ final IgnoredException ex = IgnoredException.addIgnoredException("com.gemstone.gemfire.cache.execute.FunctionException");
+ try {
+
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ CloseableHttpResponse response = null;
+ HttpPost post = new HttpPost(restURLs.get(index) + "/functions/OnGroupsFunction?onGroups=no%20such%20group");
+ post.addHeader("Content-Type", "application/json");
+ post.addHeader("Accept", "application/json");
+ response = httpclient.execute(post);
+
+ if ( response.getStatusLine().getStatusCode() == 200 ) {
+ fail("FunctionException expected : no member(s) are found belonging to the provided group(s)");
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("unexpected exception", e);
+
+ } finally {
+ ex.remove();
+ }
+
+ //Testcase-2: Executing function on group with args.
+
+ final String FUNCTION_ARGS1 = "{"
+ + "\"@type\": \"string\","
+ + "\"@value\": \"gm\""
+ + "}";
+
+ try {
+
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ CloseableHttpResponse response = null;
+ HttpPost post = new HttpPost(restURLs.get(index) + "/functions/OnGroupsFunction?onGroups=gm");
+ post.addHeader("Content-Type", "application/json");
+ post.addHeader("Accept", "application/json");
+ response = httpclient.execute(post);
+
+ //verify response status code
+ assertEquals(response.getStatusLine().getStatusCode(), 200);
+
+ //verify response hasbody flag
+ assertNotNull(response.getEntity());
+
+ HttpEntity entity = response.getEntity();
+ InputStream content = entity.getContent();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ content));
+ String line;
+ StringBuffer sb = new StringBuffer();
+ while ((line = reader.readLine()) != null) {
+ sb.append(line);
+ }
+ response.close();
+
+ //verify function execution result
+ JSONArray resultArray = new JSONArray(sb.toString());
+ assertEquals(resultArray.length(), 1);
+
+ } catch (Exception e) {
+ throw new RuntimeException("unexpected exception", e);
+ }
+ }
+
+ private void verifyAndResetInvocationCount(VM vm, final int count) {
+ vm.invoke(new SerializableCallable() {
+ @Override
+ public Object call() throws Exception {
+ OnGroupsFunction f = (OnGroupsFunction) FunctionService.getFunction(OnGroupsFunction.Id);
+ assertEquals(count, f.invocationCount);
+ // assert succeeded, reset count
+ f.invocationCount = 0;
+ return null;
+ }
+ });
+ }
+
+ private void resetInvocationCount(VM vm) {
+ vm.invoke(new SerializableCallable() {
+ @Override
+ public Object call() throws Exception {
+ OnGroupsFunction f = (OnGroupsFunction) FunctionService.getFunction(OnGroupsFunction.Id);
+ f.invocationCount = 0;
+ return null;
+ }
+ });
+ }
+
+ public void testonGroupsExecutionOnAllMembers() {
+
+ List<String> restURLs = new ArrayList<String>();
+ //Step-1 : create cache on each VM, this will start HTTP service in embedded mode and deploy REST APIs web app on it.
+ // Create and configure Region on all VMs. Add Rest end-point into the restURLs list.
+
+ String url1 = (String)vm0.invoke(() -> RestAPITestBase.createCacheWithGroups(vm0, "g0,gm", "TEST_REGION"));
+ restURLs.add(url1);
+
+ String url2 = (String)vm1.invoke(() -> RestAPITestBase.createCacheWithGroups(vm1, "g1", "TEST_REGION" ));
+ restURLs.add(url2);
+
+ String url3 = (String)vm2.invoke(() -> RestAPITestBase.createCacheWithGroups(vm2, "g0,g1", "TEST_REGION"));
+ restURLs.add(url3);
+
+ //Step-2: Register function in all VMs
+ registerFunction(vm0);
+ registerFunction(vm1);
+ registerFunction(vm2);
+
+ //Step-3 : Execute function randomly (in iteration) on all available (per VM) REST end-points and verify its result
+ for (int i=0; i< 10; i++)
+ executeFunctionThroughRestCall(restURLs);
+
+ //Verify that each node belonging to specified group has run the function
+ verifyAndResetInvocationCount(vm0, 10);
+ verifyAndResetInvocationCount(vm1, 10);
+ verifyAndResetInvocationCount(vm2, 10);
+
+ restURLs.clear();
+ }
+
+
+ public void testBasicP2PFunctionSelectedGroup() {
+
+ List<String> restURLs = new ArrayList<String>();
+
+ //Step-1 : create cache on each VM, this will start HTTP service in embedded mode and deploy REST APIs web app on it.
+ // Create and configure Region on all VMs. Add Rest end-point into the restURLs list.
+ String url1 = (String)vm0.invoke(() -> RestAPITestBase.createCacheWithGroups(vm0, "g0,gm", "null" ));
+ restURLs.add(url1);
+
+ String url2 = (String)vm1.invoke(() -> RestAPITestBase.createCacheWithGroups(vm1, "g1", "null" ));
+ restURLs.add(url2);
+
+ String url3 = (String)vm2.invoke(() -> RestAPITestBase.createCacheWithGroups(vm2, "g0,g1", "null" ));
+ restURLs.add(url3);
+
+ //Step-2: Register function in all VMs
+ registerFunction(vm0);
+ registerFunction(vm1);
+ registerFunction(vm2);
+
+ //Step-3 : Execute function randomly (in iteration) on all available (per VM) REST end-points and verify its result
+ for (int i=0; i< 5; i++)
+ executeFunctionOnMemberThroughRestCall(restURLs);
+
+ resetInvocationCount(vm0);
+ resetInvocationCount(vm1);
+ resetInvocationCount(vm2);
+
+ restURLs.clear();
+ }
+}
+