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 2017/04/07 19:34:14 UTC

[15/19] geode git commit: Create ClientCachePutBench

Create ClientCachePutBench


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/0c168582
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/0c168582
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/0c168582

Branch: refs/heads/feature/GEODE-2632
Commit: 0c1685828e9717c52bf96b881fd006d8a92f4cbc
Parents: 39c72b2
Author: Kirk Lund <kl...@apache.org>
Authored: Mon Apr 3 14:52:28 2017 -0700
Committer: Kirk Lund <kl...@apache.org>
Committed: Wed Apr 5 12:49:37 2017 -0700

----------------------------------------------------------------------
 geode-core/build.gradle                         |   5 +
 .../sockets/command/ClientCachePutBench.java    | 174 +++++++++++++++++++
 .../cache/tier/sockets/command/Put65Bench.java  | 120 +++++++++++++
 .../command/ClientCachePutBench-server.xml      |  29 ++++
 .../internal/ClusterConfigurationService.java   |  20 ++-
 .../cache/tier/sockets/BaseCommand.java         |  35 ++--
 .../tier/sockets/ClientProxyMembershipID.java   |   5 +-
 .../geode/distributed/ServerLauncherUtils.java  |  30 ++++
 .../cache/tier/sockets/CacheServerUtils.java    |  55 ++++++
 .../command/ExperimentIntegrationTest.java      |  80 +++++++++
 .../tier/sockets/command/ExperimentTest.java    | 121 +++++++++++++
 11 files changed, 646 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/0c168582/geode-core/build.gradle
----------------------------------------------------------------------
diff --git a/geode-core/build.gradle b/geode-core/build.gradle
index 757599a..fd56fe1 100755
--- a/geode-core/build.gradle
+++ b/geode-core/build.gradle
@@ -17,6 +17,7 @@
 
 
 apply plugin: 'antlr'
+apply plugin: 'me.champeau.gradle.jmh'
 
 sourceSets {
   jca {
@@ -220,5 +221,9 @@ dependencies {
   classesOutput sourceSets.main.output
 }
 
+jmh {
+  duplicateClassesStrategy = 'warn'
+}
+
 tasks.eclipse.dependsOn(generateGrammarSource)
 

http://git-wip-us.apache.org/repos/asf/geode/blob/0c168582/geode-core/src/jmh/java/org/apache/geode/internal/cache/tier/sockets/command/ClientCachePutBench.java
----------------------------------------------------------------------
diff --git a/geode-core/src/jmh/java/org/apache/geode/internal/cache/tier/sockets/command/ClientCachePutBench.java b/geode-core/src/jmh/java/org/apache/geode/internal/cache/tier/sockets/command/ClientCachePutBench.java
new file mode 100644
index 0000000..a1cbd81
--- /dev/null
+++ b/geode-core/src/jmh/java/org/apache/geode/internal/cache/tier/sockets/command/ClientCachePutBench.java
@@ -0,0 +1,174 @@
+/*
+ * 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 org.apache.geode.internal.cache.tier.sockets.command;
+
+import static org.apache.commons.io.FileUtils.*;
+import static org.apache.geode.test.dunit.NetworkUtils.getIPLiteral;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.client.ClientCache;
+import org.apache.geode.cache.client.ClientCacheFactory;
+import org.apache.geode.cache.client.ClientRegionShortcut;
+import org.apache.geode.distributed.ConfigurationProperties;
+import org.apache.geode.distributed.ServerLauncher;
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.internal.AvailablePort;
+import org.apache.geode.internal.net.SocketCreator;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.infra.Blackhole;
+
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+@Measurement(iterations = 5)
+@Warmup(iterations = 5)
+@Fork(1)
+@BenchmarkMode(Mode.Throughput)
+@OutputTimeUnit(TimeUnit.SECONDS)
+@State(Scope.Thread)
+@SuppressWarnings("unused")
+public class ClientCachePutBench {
+
+  @Test
+  public void tempTest() throws Exception {
+    String SERVER_XML_FILE_NAME =
+        "/" + StringUtils.replace(ClientCachePutBench.class.getPackage().getName(), ".", "/")
+            + "/ClientCachePutBench-server.xml";
+    assertThat(new File(getClass().getResource(SERVER_XML_FILE_NAME).getFile())).exists();
+  }
+
+  @State(Scope.Benchmark)
+  public static class ClientState {
+    // public static final String SERVER_XML_FILE_NAME =
+    // "/" + StringUtils.replace(ClientCachePutBench.class.getPackage().getName(), ".", "/")
+    // + "/ClientCachePutBench-server.xml";
+    public static final String REGION_NAME = "clientCachePutBench-region";
+
+    public Random random;
+
+    public int serverPort;
+    public Process process;
+    public ServerLauncher launcher;
+    public File serverDirectory;
+
+    public ClientCache clientCache;
+    public Region<String, String> region;
+
+    public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+    @Setup(Level.Trial)
+    public void startServer() throws Exception {
+      this.random = new Random(System.nanoTime());
+
+      this.temporaryFolder.create();
+      this.serverDirectory = this.temporaryFolder.getRoot();
+
+      String SERVER_XML_FILE_NAME =
+          "/" + StringUtils.replace(ClientCachePutBench.class.getPackage().getName(), ".", "/")
+              + "/ClientCachePutBench-server.xml";
+
+      URL srcServerXml = getClass().getResource(SERVER_XML_FILE_NAME);
+      assertThat(srcServerXml).isNotNull();
+      File destServerXml = new File(this.serverDirectory, SERVER_XML_FILE_NAME);
+      copyURLToFile(srcServerXml, destServerXml);
+
+      this.serverPort = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET);
+
+      List<String> jvmArguments = getJvmArguments();
+
+      List<String> command = new ArrayList<>();
+      command.add(
+          new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
+      for (String jvmArgument : jvmArguments) {
+        command.add(jvmArgument);
+      }
+      command.add("-Dgemfire.cache-xml-file=" + destServerXml.getAbsolutePath());
+      command.add("-cp");
+      command.add(System.getProperty("java.class.path"));
+      command.add(ServerLauncher.class.getName());
+      command.add(ServerLauncher.Command.START.getName());
+      command.add("server1");
+      command.add("--server-port=" + this.serverPort);
+      // command.add("--redirect-output");
+
+      this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
+
+      boolean forever = true;
+      while (forever) {
+        assertThat(this.process.isAlive()).isTrue();
+        Thread.sleep(10000);
+      }
+
+      this.clientCache =
+          new ClientCacheFactory().addPoolServer(getIPLiteral(), this.serverPort).create();
+      this.region =
+          this.clientCache.<String, String>createClientRegionFactory(ClientRegionShortcut.PROXY)
+              .create(REGION_NAME);
+    }
+
+    @TearDown(Level.Trial)
+    public void stopServer() throws Exception {
+      try {
+        this.clientCache.close(false);
+        new ServerLauncher.Builder().setWorkingDirectory(this.serverDirectory.getAbsolutePath())
+            .build().stop();
+      } finally {
+        if (this.process != null) {
+          this.process.destroyForcibly();
+        }
+        this.temporaryFolder.delete();
+      }
+    }
+
+    private List<String> getJvmArguments() {
+      List<String> jvmArguments = new ArrayList<>();
+      jvmArguments.add(
+          "-D" + DistributionConfig.GEMFIRE_PREFIX + ConfigurationProperties.MCAST_PORT + "=0");
+      jvmArguments.add(
+          "-D" + DistributionConfig.GEMFIRE_PREFIX + ConfigurationProperties.LOCATORS + "\"\"");
+      return jvmArguments;
+    }
+  }
+
+  @Benchmark
+  public void test(ClientState state, Blackhole blackhole) throws Exception {
+    String key = "key-" + state.random.nextInt();
+    String value = "value-" + state.random.nextInt();
+    String oldValue = state.region.put(key, value);
+    blackhole.consume(new Object[] {key, value, oldValue});
+    blackhole.consume(oldValue);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0c168582/geode-core/src/jmh/java/org/apache/geode/internal/cache/tier/sockets/command/Put65Bench.java
----------------------------------------------------------------------
diff --git a/geode-core/src/jmh/java/org/apache/geode/internal/cache/tier/sockets/command/Put65Bench.java b/geode-core/src/jmh/java/org/apache/geode/internal/cache/tier/sockets/command/Put65Bench.java
new file mode 100644
index 0000000..6ccd8c3
--- /dev/null
+++ b/geode-core/src/jmh/java/org/apache/geode/internal/cache/tier/sockets/command/Put65Bench.java
@@ -0,0 +1,120 @@
+/*
+ * 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 org.apache.geode.internal.cache.tier.sockets.command;
+
+import static org.apache.geode.SystemFailure.loadEmergencyClasses;
+import static org.apache.geode.internal.cache.TXManagerImpl.NOTX;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.geode.SystemFailure;
+import org.apache.geode.cache.Operation;
+import org.apache.geode.internal.Version;
+import org.apache.geode.internal.cache.GemFireCacheImpl;
+import org.apache.geode.internal.cache.TXManagerImpl;
+import org.apache.geode.internal.cache.tier.Command;
+import org.apache.geode.internal.cache.tier.sockets.CacheServerStats;
+import org.apache.geode.internal.cache.tier.sockets.ClientProxyMembershipID;
+import org.apache.geode.internal.cache.tier.sockets.Message;
+import org.apache.geode.internal.cache.tier.sockets.Part;
+import org.apache.geode.internal.cache.tier.sockets.ServerConnection;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.infra.Blackhole;
+
+public class Put65Bench {
+
+  @State(Scope.Benchmark)
+  public static class ServerConnectionState {
+    public Command command;
+    public ServerConnection mockServerConnection;
+    public Message message;
+
+    @Setup(Level.Trial)
+    public void setup() throws Exception {
+      loadEmergencyClasses();
+
+      this.command = Put65.getCommand();
+
+      this.mockServerConnection = mock(ServerConnection.class);
+      when(this.mockServerConnection.getClientVersion()).thenReturn(Version.CURRENT);
+
+      TXManagerImpl txManager = mock(TXManagerImpl.class);
+      GemFireCacheImpl cache = mock(GemFireCacheImpl.class);
+      when(cache.getTxManager()).thenReturn(txManager);
+
+      when(this.mockServerConnection.getCache()).thenReturn(cache);
+
+      CacheServerStats cacheServerStats = mock(CacheServerStats.class);
+      when(this.mockServerConnection.getCacheServerStats()).thenReturn(cacheServerStats);
+
+      // .getDistributedMember()
+      ClientProxyMembershipID mockProxyId = mock(ClientProxyMembershipID.class);
+      when(this.mockServerConnection.getProxyID()).thenReturn(mockProxyId);
+
+      Message errorResponseMessage = mock(Message.class);
+      when(this.mockServerConnection.getErrorResponseMessage()).thenReturn(errorResponseMessage);
+
+      Part regionNamePart = mock(Part.class);
+      when(regionNamePart.getString()).thenReturn("regionNamePart");
+
+      Part operationPart = mock(Part.class);
+      when(operationPart.getObject()).thenReturn(Operation.UPDATE);
+
+      Part flagsPart = mock(Part.class);
+      when(flagsPart.getInt()).thenReturn(0);
+
+      Part keyPart = mock(Part.class);
+      when(keyPart.getObject()).thenReturn("keyPart");
+      when(keyPart.getStringOrObject()).thenReturn("keyPart");
+
+      Part isDeltaPart = mock(Part.class);
+      when(isDeltaPart.getObject()).thenReturn(Boolean.FALSE);
+
+      Part valuePart = mock(Part.class);
+      when(valuePart.getObject()).thenReturn("valuePart");
+
+      Part eventPart = mock(Part.class);
+      when(eventPart.getObject()).thenReturn("eventPart");
+
+      Part callbackArgPart = mock(Part.class);
+      when(callbackArgPart.getObject()).thenReturn("callbackArgPart");
+
+      message = mock(Message.class);
+
+      when(message.getTransactionId()).thenReturn(NOTX);
+
+      when(message.getPart(0)).thenReturn(regionNamePart);
+      when(message.getPart(1)).thenReturn(operationPart);
+      when(message.getPart(2)).thenReturn(flagsPart);
+      when(message.getPart(3)).thenReturn(keyPart);
+      when(message.getPart(4)).thenReturn(isDeltaPart);
+      when(message.getPart(5)).thenReturn(valuePart);
+      when(message.getPart(6)).thenReturn(eventPart);
+      when(message.getPart(7)).thenReturn(callbackArgPart);
+    }
+  }
+
+  // @Benchmark
+  public void benchmark(ServerConnectionState state, Blackhole blackhole) {
+    state.command.execute(state.message, state.mockServerConnection);
+    // Message replyMessage = state.mockServerConnection.getReplyMessage();
+    // blackhole.consume(replyMessage);
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0c168582/geode-core/src/jmh/resources/org/apache/geode/internal/cache/tier/sockets/command/ClientCachePutBench-server.xml
----------------------------------------------------------------------
diff --git a/geode-core/src/jmh/resources/org/apache/geode/internal/cache/tier/sockets/command/ClientCachePutBench-server.xml b/geode-core/src/jmh/resources/org/apache/geode/internal/cache/tier/sockets/command/ClientCachePutBench-server.xml
new file mode 100644
index 0000000..2013b37
--- /dev/null
+++ b/geode-core/src/jmh/resources/org/apache/geode/internal/cache/tier/sockets/command/ClientCachePutBench-server.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+	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.
+-->
+<cache
+        xmlns="http://geode.apache.org/schema/cache"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd"
+        version="1.0">
+    <region name="clientCachePutBench-region" refid="REPLICATE">
+        <region-attributes>
+            <key-constraint>java.lang.String</key-constraint>
+            <value-constraint>java.lang.String</value-constraint>
+        </region-attributes>
+    </region>
+</cache>

http://git-wip-us.apache.org/repos/asf/geode/blob/0c168582/geode-core/src/main/java/org/apache/geode/distributed/internal/ClusterConfigurationService.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/ClusterConfigurationService.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/ClusterConfigurationService.java
index 95d1a5b..74df19c 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/ClusterConfigurationService.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/ClusterConfigurationService.java
@@ -386,10 +386,22 @@ public class ClusterConfigurationService {
 
     createConfigDirIfNecessary(groupName);
 
-    byte[] jarBytes = locators.stream()
-        .map((DistributedMember locator) -> downloadJarFromLocator(locator, groupName, jarName))
-        .filter(Objects::nonNull).findFirst().orElseThrow(() -> new IllegalStateException(
-            "No locators have a deployed jar named " + jarName + " in " + groupName));
+    byte[] jarBytes = null;
+    for (DistributedMember locator : locators) {
+      jarBytes = downloadJarFromLocator(locator, groupName, jarName);
+      if (jarBytes != null) {
+        break;
+      }
+    }
+    if (jarBytes == null) {
+      throw new IllegalStateException(
+          "No locators have a deployed jar named " + jarName + " in " + groupName);
+    }
+
+    // byte[] jarBytes = locators.stream()
+    // .map((DistributedMember locator) -> downloadJarFromLocator(locator, groupName, jarName))
+    // .filter(Objects::nonNull).findFirst().orElseThrow(() -> new IllegalStateException(
+    // "No locators have a deployed jar named " + jarName + " in " + groupName));
 
     File jarToWrite = getPathToJarOnThisLocator(groupName, jarName).toFile();
     FileUtils.writeByteArrayToFile(jarToWrite, jarBytes);

http://git-wip-us.apache.org/repos/asf/geode/blob/0c168582/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/BaseCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/BaseCommand.java b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/BaseCommand.java
index d217672..ff9daca 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/BaseCommand.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/BaseCommand.java
@@ -91,31 +91,26 @@ public abstract class BaseCommand implements Command {
   private static final int MAX_INCOMING_MSGS =
       Integer.getInteger("BridgeServer.MAX_INCOMING_MSGS", -1).intValue();
 
-  private static final Semaphore incomingDataLimiter;
-
-  private static final Semaphore incomingMsgLimiter;
-  static {
-    Semaphore tmp;
-    if (MAX_INCOMING_DATA > 0) {
-      // backport requires that this is fair since we inc by values > 1
-      tmp = new Semaphore(MAX_INCOMING_DATA, true);
-    } else {
-      tmp = null;
-    }
-    incomingDataLimiter = tmp;
-    if (MAX_INCOMING_MSGS > 0) {
-      tmp = new Semaphore(MAX_INCOMING_MSGS, false); // unfair for best
-      // performance
-    } else {
-      tmp = null;
-    }
-    incomingMsgLimiter = tmp;
+  // backport requires that this is fair since we inc by values > 1
+  private static final Semaphore incomingDataLimiter =
+      createIncomingLimiterSemaphore(MAX_INCOMING_DATA, true);
+
+  // unfair for best performance
+  private static final Semaphore incomingMsgLimiter =
+      createIncomingLimiterSemaphore(MAX_INCOMING_MSGS, false);
 
+  private static Semaphore createIncomingLimiterSemaphore(final int maximum, final boolean fair) {
+    Semaphore semaphore = null;
+    if (maximum > 0) {
+      semaphore = new Semaphore(maximum, fair);
+    }
+    return semaphore;
   }
 
   protected SecurityService securityService = IntegratedSecurityService.getSecurityService();
 
-  final public void execute(Message msg, ServerConnection servConn) {
+  @Override
+  public void execute(final Message msg, final ServerConnection servConn) {
     // Read the request and update the statistics
     long start = DistributionStats.getStatTime();
     // servConn.resetTransientData();

http://git-wip-us.apache.org/repos/asf/geode/blob/0c168582/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/ClientProxyMembershipID.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/ClientProxyMembershipID.java b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/ClientProxyMembershipID.java
index 2cbf63b..46e43c5 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/ClientProxyMembershipID.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/ClientProxyMembershipID.java
@@ -34,11 +34,8 @@ import static org.apache.geode.distributed.ConfigurationProperties.*;
 
 /**
  * This class represents a ConnectionProxy of the CacheClient
- * 
- * 
- * 
  */
-public final class ClientProxyMembershipID
+public class ClientProxyMembershipID
     implements DataSerializableFixedID, Serializable, Externalizable {
 
   private static final Logger logger = LogService.getLogger();

http://git-wip-us.apache.org/repos/asf/geode/blob/0c168582/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherUtils.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherUtils.java b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherUtils.java
new file mode 100644
index 0000000..017e0f5
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherUtils.java
@@ -0,0 +1,30 @@
+/*
+ * 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 org.apache.geode.distributed;
+
+import org.apache.geode.cache.Cache;
+
+/**
+ * Provides tests a way to access non-public state in ServerLauncher
+ */
+public class ServerLauncherUtils {
+
+  /**
+   * Returns the Cache from an online in-process ServerLauncher instance
+   */
+  public static Cache getCache(final ServerLauncher serverLauncher) {
+    return serverLauncher.getCache();
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0c168582/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/CacheServerUtils.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/CacheServerUtils.java b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/CacheServerUtils.java
new file mode 100644
index 0000000..8cd7622
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/CacheServerUtils.java
@@ -0,0 +1,55 @@
+/*
+ * 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 org.apache.geode.internal.cache.tier.sockets;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.server.CacheServer;
+import org.apache.geode.internal.cache.CacheServerImpl;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Provides tests a way to access CacheServer, AcceptorImpl and ServerConnection
+ */
+public class CacheServerUtils {
+
+  /**
+   * Returns single CacheServer for the specified Cache instance
+   */
+  public static CacheServer getCacheServer(final Cache cache) {
+    List<CacheServer> cacheServers = cache.getCacheServers();
+    CacheServer cacheServer = cacheServers.get(0);
+    return cacheServer;
+  }
+
+  /**
+   * Returns AcceptorImpl for the specified CacheServer instance
+   */
+  public static AcceptorImpl getAcceptorImpl(final CacheServer cacheServer) {
+    AcceptorImpl acceptor = ((CacheServerImpl) cacheServer).getAcceptor();
+    return acceptor;
+  }
+
+  /**
+   * Returns single ServerConnection for the specified CacheServer instance
+   */
+  public static ServerConnection getServerConnection(final CacheServer cacheServer) {
+    AcceptorImpl acceptor = ((CacheServerImpl) cacheServer).getAcceptor();
+    Set<ServerConnection> serverConnections = acceptor.getAllServerConnections();
+    ServerConnection serverConnection = serverConnections.iterator().next(); // null
+    return serverConnection;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0c168582/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExperimentIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExperimentIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExperimentIntegrationTest.java
new file mode 100644
index 0000000..2d900dc
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExperimentIntegrationTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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 org.apache.geode.internal.cache.tier.sockets.command;
+
+import static org.apache.geode.distributed.AbstractLauncher.Status.ONLINE;
+import static org.apache.geode.distributed.ServerLauncherUtils.*;
+import static org.apache.geode.internal.cache.tier.sockets.AcceptorImpl.DEFAULT_HANDSHAKE_TIMEOUT_MS;
+import static org.apache.geode.internal.cache.tier.sockets.CacheServerUtils.*;
+import static org.apache.geode.internal.AvailablePort.*;
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.server.CacheServer;
+import org.apache.geode.distributed.ServerLauncher;
+import org.apache.geode.internal.cache.tier.Acceptor;
+import org.apache.geode.internal.cache.tier.Command;
+import org.apache.geode.internal.cache.tier.sockets.AcceptorImpl;
+import org.apache.geode.internal.cache.tier.sockets.Message;
+import org.apache.geode.internal.cache.tier.sockets.ServerConnection;
+import org.apache.geode.internal.net.SocketCreator;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.net.Socket;
+
+@Category(IntegrationTest.class)
+public class ExperimentIntegrationTest {
+
+  private ServerLauncher serverLauncher;
+  private ServerConnection serverConnection;
+
+  @Before
+  public void before() throws Exception {
+    int serverPort = getRandomAvailablePort(SOCKET);
+
+    this.serverLauncher =
+        new ServerLauncher.Builder().setMemberName("server").setServerPort(serverPort).build();
+    this.serverLauncher.start();
+
+    Cache cache = getCache(this.serverLauncher);
+    CacheServer cacheServer = getCacheServer(cache);
+    AcceptorImpl acceptor = getAcceptorImpl(cacheServer);
+
+    Socket mockSocket = mock(Socket.class);
+    when(mockSocket.getInetAddress()).thenReturn(SocketCreator.getLocalHost());
+
+    this.serverConnection =
+        new ServerConnection(mockSocket, cache, null, null, DEFAULT_HANDSHAKE_TIMEOUT_MS,
+            CacheServer.DEFAULT_SOCKET_BUFFER_SIZE, "client", Acceptor.CLIENT_TO_SERVER, acceptor);
+
+    preConditions();
+  }
+
+  public void preConditions() throws Exception {
+    assertThat(this.serverLauncher.status().getStatus()).isEqualTo(ONLINE);
+  }
+
+  @Test
+  public void handlePutFromFakeClient() throws Exception {
+    Message message = mock(Message.class);
+    Command command = mock(Command.class);
+    command.execute(message, this.serverConnection);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0c168582/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExperimentTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExperimentTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExperimentTest.java
new file mode 100644
index 0000000..b52e81d
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExperimentTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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 org.apache.geode.internal.cache.tier.sockets.command;
+
+import static org.apache.geode.internal.cache.TXManagerImpl.NOTX;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.Operation;
+import org.apache.geode.internal.Version;
+import org.apache.geode.internal.cache.GemFireCacheImpl;
+import org.apache.geode.internal.cache.TXManagerImpl;
+import org.apache.geode.internal.cache.tier.Command;
+import org.apache.geode.internal.cache.tier.sockets.CacheServerStats;
+import org.apache.geode.internal.cache.tier.sockets.ClientProxyMembershipID;
+import org.apache.geode.internal.cache.tier.sockets.Message;
+import org.apache.geode.internal.cache.tier.sockets.Part;
+import org.apache.geode.internal.cache.tier.sockets.ServerConnection;
+import org.apache.geode.test.junit.categories.UnitTest;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+
+@Category(UnitTest.class)
+public class ExperimentTest {
+
+  private ServerConnection mockServerConnection;
+
+  @Rule
+  public TestName testName = new TestName();
+
+  @Before
+  public void before() throws Exception {
+    this.mockServerConnection = mock(ServerConnection.class);
+    when(this.mockServerConnection.getClientVersion()).thenReturn(Version.CURRENT);
+
+    TXManagerImpl txManager = mock(TXManagerImpl.class);
+    GemFireCacheImpl cache = mock(GemFireCacheImpl.class);
+    when(cache.getTxManager()).thenReturn(txManager);
+
+    when(this.mockServerConnection.getCache()).thenReturn(cache);
+
+    CacheServerStats cacheServerStats = mock(CacheServerStats.class);
+    when(this.mockServerConnection.getCacheServerStats()).thenReturn(cacheServerStats);
+
+    // .getDistributedMember()
+    ClientProxyMembershipID mockProxyId = mock(ClientProxyMembershipID.class);
+    when(this.mockServerConnection.getProxyID()).thenReturn(mockProxyId);
+
+    Message errorResponseMessage = mock(Message.class);
+    when(this.mockServerConnection.getErrorResponseMessage()).thenReturn(errorResponseMessage);
+  }
+
+  @Test
+  public void handlePutFromFakeClient() throws Exception {
+    Part regionNamePart = mock(Part.class);
+    when(regionNamePart.getString()).thenReturn("regionNamePart");
+
+    Part operationPart = mock(Part.class);
+    when(operationPart.getObject()).thenReturn(Operation.UPDATE);
+
+    Part flagsPart = mock(Part.class);
+    when(flagsPart.getInt()).thenReturn(0);
+
+    Part keyPart = mock(Part.class);
+    when(keyPart.getObject()).thenReturn("keyPart");
+    when(keyPart.getStringOrObject()).thenReturn("keyPart");
+
+    Part isDeltaPart = mock(Part.class);
+    when(isDeltaPart.getObject()).thenReturn(Boolean.FALSE);
+
+    Part valuePart = mock(Part.class);
+    when(valuePart.getObject()).thenReturn("valuePart");
+
+    Part eventPart = mock(Part.class);
+    when(eventPart.getObject()).thenReturn("eventPart");
+
+    Part callbackArgPart = mock(Part.class);
+    when(callbackArgPart.getObject()).thenReturn("callbackArgPart");
+
+    Message message = mock(Message.class);
+
+    when(message.getTransactionId()).thenReturn(NOTX);
+
+    when(message.getPart(0)).thenReturn(regionNamePart);
+    when(message.getPart(1)).thenReturn(operationPart);
+    when(message.getPart(2)).thenReturn(flagsPart);
+    when(message.getPart(3)).thenReturn(keyPart);
+    when(message.getPart(4)).thenReturn(isDeltaPart);
+    when(message.getPart(5)).thenReturn(valuePart);
+    when(message.getPart(6)).thenReturn(eventPart);
+    when(message.getPart(7)).thenReturn(callbackArgPart);
+
+    assertThat(message.getPart(0)).isSameAs(regionNamePart);
+    assertThat(message.getPart(1)).isSameAs(operationPart);
+    assertThat(message.getPart(2)).isSameAs(flagsPart);
+    assertThat(message.getPart(3)).isSameAs(keyPart);
+    assertThat(message.getPart(4)).isSameAs(isDeltaPart);
+    assertThat(message.getPart(5)).isSameAs(valuePart);
+    assertThat(message.getPart(6)).isSameAs(eventPart);
+    assertThat(message.getPart(7)).isSameAs(callbackArgPart);
+
+    Command command = Put65.getCommand();
+    command.execute(message, this.mockServerConnection);
+  }
+}