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/08/04 23:25:33 UTC

[05/27] geode git commit: GEODE-3284: New flow: getAvailableServers. This now closed #673

GEODE-3284: New flow: getAvailableServers. This now closed #673

Signed-off-by: Bruce Schuchardt <bs...@pivotal.io>


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

Branch: refs/heads/feature/GEODE-3299
Commit: bf2e0f6e03d1c50580a45efdd3588d1a19bdb5d9
Parents: 636e970
Author: Udo Kohlmeyer <uk...@pivotal.io>
Authored: Mon Jul 31 09:23:53 2017 -0700
Committer: Udo Kohlmeyer <uk...@pivotal.io>
Committed: Wed Aug 2 09:48:43 2017 -0700

----------------------------------------------------------------------
 .../GetAvailableServersOperationHandler.java    |  98 ++++++++++++++
 .../registry/OperationContextRegistry.java      |   6 +
 .../utilities/ProtobufRequestUtilities.java     |  11 +-
 .../protobuf/utilities/ProtobufUtilities.java   |  24 ++--
 geode-protobuf/src/main/proto/basicTypes.proto  |   3 +-
 .../src/main/proto/clientProtocol.proto         |  10 +-
 geode-protobuf/src/main/proto/region_API.proto  |   8 --
 geode-protobuf/src/main/proto/server_API.proto  |   4 +-
 .../protocol/GetAvailableServersDUnitTest.java  | 108 +++++++++++++++
 ...ailableServersOperationHandlerJUnitTest.java | 131 +++++++++++++++++++
 10 files changed, 374 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/bf2e0f6e/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/operations/GetAvailableServersOperationHandler.java
----------------------------------------------------------------------
diff --git a/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/operations/GetAvailableServersOperationHandler.java b/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/operations/GetAvailableServersOperationHandler.java
new file mode 100644
index 0000000..cf3f828
--- /dev/null
+++ b/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/operations/GetAvailableServersOperationHandler.java
@@ -0,0 +1,98 @@
+/*
+ * 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.protocol.protobuf.operations;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.client.internal.locator.GetAllServersRequest;
+import org.apache.geode.cache.client.internal.locator.GetAllServersResponse;
+import org.apache.geode.distributed.ConfigurationProperties;
+import org.apache.geode.distributed.internal.InternalDistributedSystem;
+import org.apache.geode.distributed.internal.ServerLocation;
+import org.apache.geode.distributed.internal.tcpserver.TcpClient;
+import org.apache.geode.internal.admin.remote.DistributionLocatorId;
+import org.apache.geode.protocol.operations.OperationHandler;
+import org.apache.geode.protocol.protobuf.BasicTypes;
+import org.apache.geode.protocol.protobuf.Failure;
+import org.apache.geode.protocol.protobuf.Result;
+import org.apache.geode.protocol.protobuf.ServerAPI;
+import org.apache.geode.protocol.protobuf.Success;
+import org.apache.geode.serialization.SerializationService;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.stream.Collectors;
+
+public class GetAvailableServersOperationHandler implements
+    OperationHandler<ServerAPI.GetAvailableServersRequest, ServerAPI.GetAvailableServersResponse> {
+
+  @Override
+  public Result<ServerAPI.GetAvailableServersResponse> process(
+      SerializationService serializationService, ServerAPI.GetAvailableServersRequest request,
+      Cache cache) {
+
+    InternalDistributedSystem distributedSystem =
+        (InternalDistributedSystem) cache.getDistributedSystem();
+    Properties properties = distributedSystem.getProperties();
+    String locatorsString = properties.getProperty(ConfigurationProperties.LOCATORS);
+
+    HashSet<DistributionLocatorId> locators = new HashSet();
+    StringTokenizer stringTokenizer = new StringTokenizer(locatorsString, ",");
+    while (stringTokenizer.hasMoreTokens()) {
+      String locator = stringTokenizer.nextToken();
+      if (StringUtils.isNotEmpty(locator)) {
+        locators.add(new DistributionLocatorId(locator));
+      }
+    }
+
+    TcpClient tcpClient = getTcpClient();
+    for (DistributionLocatorId locator : locators) {
+      try {
+        return getGetAvailableServersFromLocator(tcpClient, locator.getHost());
+      } catch (IOException | ClassNotFoundException e) {
+        // try the next locator
+      }
+    }
+    return Failure
+        .of(BasicTypes.ErrorResponse.newBuilder().setMessage("Unable to find a locator").build());
+  }
+
+  private Result<ServerAPI.GetAvailableServersResponse> getGetAvailableServersFromLocator(
+      TcpClient tcpClient, InetSocketAddress address) throws IOException, ClassNotFoundException {
+    GetAllServersResponse getAllServersResponse = (GetAllServersResponse) tcpClient
+        .requestToServer(address, new GetAllServersRequest(), 1000, true);
+    Collection<BasicTypes.Server> servers =
+        (Collection<BasicTypes.Server>) getAllServersResponse.getServers().stream()
+            .map(serverLocation -> getServerProtobufMessage((ServerLocation) serverLocation))
+            .collect(Collectors.toList());
+    ServerAPI.GetAvailableServersResponse.Builder builder =
+        ServerAPI.GetAvailableServersResponse.newBuilder().addAllServers(servers);
+    return Success.of(builder.build());
+  }
+
+  protected TcpClient getTcpClient() {
+    return new TcpClient();
+  }
+
+  private BasicTypes.Server getServerProtobufMessage(ServerLocation serverLocation) {
+    BasicTypes.Server.Builder serverBuilder = BasicTypes.Server.newBuilder();
+    serverBuilder.setHostname(serverLocation.getHostName()).setPort(serverLocation.getPort());
+    return serverBuilder.build();
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/bf2e0f6e/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/registry/OperationContextRegistry.java
----------------------------------------------------------------------
diff --git a/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/registry/OperationContextRegistry.java b/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/registry/OperationContextRegistry.java
index 37bb322..b160adc 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/registry/OperationContextRegistry.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/registry/OperationContextRegistry.java
@@ -22,6 +22,7 @@ import org.apache.geode.protocol.protobuf.ClientProtocol;
 import org.apache.geode.protocol.protobuf.ClientProtocol.Request.RequestAPICase;
 import org.apache.geode.protocol.protobuf.OperationContext;
 import org.apache.geode.protocol.protobuf.operations.GetAllRequestOperationHandler;
+import org.apache.geode.protocol.protobuf.operations.GetAvailableServersOperationHandler;
 import org.apache.geode.protocol.protobuf.operations.GetRegionNamesRequestOperationHandler;
 import org.apache.geode.protocol.protobuf.operations.GetRegionRequestOperationHandler;
 import org.apache.geode.protocol.protobuf.operations.GetRequestOperationHandler;
@@ -75,5 +76,10 @@ public class OperationContextRegistry {
         new OperationContext<>(ClientProtocol.Request::getGetRegionRequest,
             new GetRegionRequestOperationHandler(),
             opsResp -> ClientProtocol.Response.newBuilder().setGetRegionResponse(opsResp)));
+
+    operationContexts.put(RequestAPICase.GETAVAILABLESERVERSREQUEST, new OperationContext<>(
+        ClientProtocol.Request::getGetAvailableServersRequest,
+        new GetAvailableServersOperationHandler(),
+        opsResp -> ClientProtocol.Response.newBuilder().setGetAvailableServersResponse(opsResp)));
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/bf2e0f6e/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/utilities/ProtobufRequestUtilities.java
----------------------------------------------------------------------
diff --git a/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/utilities/ProtobufRequestUtilities.java b/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/utilities/ProtobufRequestUtilities.java
index 01be750..e184592 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/utilities/ProtobufRequestUtilities.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/utilities/ProtobufRequestUtilities.java
@@ -14,11 +14,12 @@
  */
 package org.apache.geode.protocol.protobuf.utilities;
 
-import java.util.Set;
-
 import org.apache.geode.protocol.protobuf.BasicTypes;
 import org.apache.geode.protocol.protobuf.ClientProtocol;
 import org.apache.geode.protocol.protobuf.RegionAPI;
+import org.apache.geode.protocol.protobuf.ServerAPI;
+
+import java.util.Set;
 
 /**
  * This class contains helper functions for generating ClientProtocol.Request objects
@@ -106,4 +107,10 @@ public abstract class ProtobufRequestUtilities {
     putAllRequestBuilder.addAllEntry(entries);
     return ClientProtocol.Request.newBuilder().setPutAllRequest(putAllRequestBuilder).build();
   }
+
+  public static ServerAPI.GetAvailableServersRequest createGetAvailableServersRequest() {
+    ServerAPI.GetAvailableServersRequest.Builder builder =
+        ServerAPI.GetAvailableServersRequest.newBuilder();
+    return builder.build();
+  }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/bf2e0f6e/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/utilities/ProtobufUtilities.java
----------------------------------------------------------------------
diff --git a/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/utilities/ProtobufUtilities.java b/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/utilities/ProtobufUtilities.java
index c7bf6aa..27c141d 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/utilities/ProtobufUtilities.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/utilities/ProtobufUtilities.java
@@ -15,6 +15,7 @@
 package org.apache.geode.protocol.protobuf.utilities;
 
 import com.google.protobuf.ByteString;
+
 import org.apache.geode.cache.Region;
 import org.apache.geode.cache.RegionAttributes;
 import org.apache.geode.protocol.protobuf.BasicTypes;
@@ -38,7 +39,7 @@ import org.apache.geode.serialization.registry.exception.CodecNotRegisteredForTy
 public abstract class ProtobufUtilities {
   /**
    * Creates a object containing the type and value encoding of a piece of data
-   *
+   * 
    * @param serializationService - object which knows how to encode objects for the protobuf
    *        protocol {@link ProtobufSerializationService}
    * @param unencodedValue - the value object which is to be encoded
@@ -60,7 +61,7 @@ public abstract class ProtobufUtilities {
 
   /**
    * Creates a protobuf key,value pair from an encoded key and value
-   *
+   * 
    * @param key - an EncodedValue containing the key of the entry
    * @param value - an EncodedValue containing the value of the entry
    * @return a protobuf Entry object containing the passed key and value
@@ -72,7 +73,7 @@ public abstract class ProtobufUtilities {
 
   /**
    * Creates a protobuf key,value pair from unencoded data
-   *
+   * 
    * @param serializationService - object which knows how to encode objects for the protobuf
    *        protocol {@link ProtobufSerializationService}
    * @param unencodedKey - the unencoded key for the entry
@@ -92,7 +93,7 @@ public abstract class ProtobufUtilities {
 
   /**
    * This creates a protobuf message containing a ClientProtocol.Response
-   *
+   * 
    * @param messageHeader - The header for the message
    * @param response - The response for the message
    * @return a protobuf Message containing the above parameters
@@ -105,7 +106,7 @@ public abstract class ProtobufUtilities {
 
   /**
    * This creates a protobuf message containing a ClientProtocol.Request
-   *
+   * 
    * @param messageHeader - The header for the message
    * @param request - The request for the message
    * @return a protobuf Message containing the above parameters
@@ -118,7 +119,7 @@ public abstract class ProtobufUtilities {
 
   /**
    * This creates a protobuf message containing a ClientProtocol.Request
-   *
+   * 
    * @param getAllRequest - The request for the message
    * @return a protobuf Message containing the above parameters
    */
@@ -129,7 +130,7 @@ public abstract class ProtobufUtilities {
 
   /**
    * This builds the MessageHeader for a response which matches an incoming request
-   *
+   * 
    * @param request - The request message that we're responding to.
    * @return the MessageHeader the response to the passed request
    */
@@ -140,7 +141,7 @@ public abstract class ProtobufUtilities {
 
   /**
    * This creates a MessageHeader
-   *
+   * 
    * @param correlationId - An identifier used to correlate requests and responses
    * @return a MessageHeader containing the above parameters
    */
@@ -150,7 +151,7 @@ public abstract class ProtobufUtilities {
 
   /**
    * This will return the object encoded in a protobuf EncodedValue
-   *
+   * 
    * @param serializationService - object which knows how to encode objects for the protobuf
    *        protocol {@link ProtobufSerializationService}
    * @param encodedValue - The value to be decoded
@@ -169,7 +170,6 @@ public abstract class ProtobufUtilities {
   }
 
   /**
-   * @param region
    * @return a Protobuf BasicTypes.Region message that represents the {@link Region}
    */
   public static BasicTypes.Region createRegionMessageFromRegion(Region region) {
@@ -197,4 +197,8 @@ public abstract class ProtobufUtilities {
     return ClientProtocol.Request.newBuilder().setGetRegionNamesRequest(getRegionNamesRequest)
         .build();
   }
+
+  public static ClientProtocol.Request.Builder createProtobufRequestBuilder() {
+    return ClientProtocol.Request.newBuilder();
+  }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/bf2e0f6e/geode-protobuf/src/main/proto/basicTypes.proto
----------------------------------------------------------------------
diff --git a/geode-protobuf/src/main/proto/basicTypes.proto b/geode-protobuf/src/main/proto/basicTypes.proto
index ad254cd..a9d07d8 100644
--- a/geode-protobuf/src/main/proto/basicTypes.proto
+++ b/geode-protobuf/src/main/proto/basicTypes.proto
@@ -61,7 +61,8 @@ message Region {
 }
 
 message Server {
-    string url = 1;
+    string hostname = 1;
+    int32 port = 2;
 }
 
 message ErrorResponse {

http://git-wip-us.apache.org/repos/asf/geode/blob/bf2e0f6e/geode-protobuf/src/main/proto/clientProtocol.proto
----------------------------------------------------------------------
diff --git a/geode-protobuf/src/main/proto/clientProtocol.proto b/geode-protobuf/src/main/proto/clientProtocol.proto
index 6b037ca..c64d4de 100644
--- a/geode-protobuf/src/main/proto/clientProtocol.proto
+++ b/geode-protobuf/src/main/proto/clientProtocol.proto
@@ -43,13 +43,12 @@ message Request {
         GetAllRequest getAllRequest = 5;
         RemoveRequest removeRequest = 6;
         RemoveAllRequest removeAllRequest = 7;
-        ListKeysRequest listKeysRequest = 8;
 
         CreateRegionRequest createRegionRequest = 21;
         DestroyRegionRequest destroyRegionRequest = 22;
 
-        PingRequest pingRequest = 41;
-        GetServersRequest getServersRequest = 42;
+//        PingRequest pingRequest = 41;
+        GetAvailableServersRequest getAvailableServersRequest = 42;
         GetRegionNamesRequest getRegionNamesRequest = 43;
         GetRegionRequest getRegionRequest = 44;
 
@@ -64,15 +63,14 @@ message Response {
         GetAllResponse getAllResponse = 5;
         RemoveResponse removeResponse = 6;
         RemoveAllResponse removeAllResponse = 7;
-        ListKeysResponse listKeysResponse = 8;
 
         ErrorResponse errorResponse = 13;
 
         CreateRegionResponse createRegionResponse = 20;
         DestroyRegionResponse destroyRegionResponse = 21;
 
-        PingResponse pingResponse = 41;
-        GetServersResponse getServersResponse = 42;
+//        PingResponse pingResponse = 41;
+        GetAvailableServersResponse getAvailableServersResponse = 42;
         GetRegionNamesResponse getRegionNamesResponse = 43;
         GetRegionResponse getRegionResponse = 44;
     }

http://git-wip-us.apache.org/repos/asf/geode/blob/bf2e0f6e/geode-protobuf/src/main/proto/region_API.proto
----------------------------------------------------------------------
diff --git a/geode-protobuf/src/main/proto/region_API.proto b/geode-protobuf/src/main/proto/region_API.proto
index bf2c15e..2a93a7d 100644
--- a/geode-protobuf/src/main/proto/region_API.proto
+++ b/geode-protobuf/src/main/proto/region_API.proto
@@ -55,14 +55,6 @@ message GetAllResponse {
     repeated Entry entries = 1;
 }
 
-message ListKeysRequest {
-    string regionName = 1;
-}
-
-message ListKeysResponse {
-    repeated EncodedValue key = 1;
-}
-
 message RemoveRequest {
     string regionName = 1;
     EncodedValue key = 2;

http://git-wip-us.apache.org/repos/asf/geode/blob/bf2e0f6e/geode-protobuf/src/main/proto/server_API.proto
----------------------------------------------------------------------
diff --git a/geode-protobuf/src/main/proto/server_API.proto b/geode-protobuf/src/main/proto/server_API.proto
index 8c4e345..81622cc 100644
--- a/geode-protobuf/src/main/proto/server_API.proto
+++ b/geode-protobuf/src/main/proto/server_API.proto
@@ -27,10 +27,10 @@ message PingResponse {
     int32 sequenceNumber = 1;
 }
 
-message GetServersRequest {
+message GetAvailableServersRequest {
 
 }
 
-message GetServersResponse {
+message GetAvailableServersResponse {
     repeated Server servers = 1;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/geode/blob/bf2e0f6e/geode-protobuf/src/test/java/org/apache/geode/protocol/GetAvailableServersDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-protobuf/src/test/java/org/apache/geode/protocol/GetAvailableServersDUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/protocol/GetAvailableServersDUnitTest.java
new file mode 100644
index 0000000..4d6390b
--- /dev/null
+++ b/geode-protobuf/src/test/java/org/apache/geode/protocol/GetAvailableServersDUnitTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.protocol;
+
+import org.apache.geode.cache.server.CacheServer;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.protocol.exception.InvalidProtocolMessageException;
+import org.apache.geode.protocol.protobuf.ClientProtocol;
+import org.apache.geode.protocol.protobuf.ServerAPI;
+import org.apache.geode.protocol.protobuf.serializer.ProtobufProtocolSerializer;
+import org.apache.geode.protocol.protobuf.utilities.ProtobufRequestUtilities;
+import org.apache.geode.protocol.protobuf.utilities.ProtobufUtilities;
+import org.apache.geode.test.dunit.DistributedTestUtils;
+import org.apache.geode.test.dunit.Host;
+import org.apache.geode.test.dunit.VM;
+import org.apache.geode.test.dunit.cache.internal.JUnit4CacheTestCase;
+import org.apache.geode.test.dunit.rules.DistributedRestoreSystemProperties;
+import org.apache.geode.test.junit.categories.DistributedTest;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.io.IOException;
+import java.net.Socket;
+
+import static org.junit.Assert.assertEquals;
+
+@Category(DistributedTest.class)
+public class GetAvailableServersDUnitTest extends JUnit4CacheTestCase {
+
+  @Rule
+  public DistributedRestoreSystemProperties distributedRestoreSystemProperties =
+      new DistributedRestoreSystemProperties();
+
+  @Before
+  public void setup() {
+
+  }
+
+  @Test
+  public void testGetAllAvailableServersRequest()
+      throws IOException, InvalidProtocolMessageException {
+    Host host = Host.getHost(0);
+    VM vm0 = host.getVM(0);
+    VM vm1 = host.getVM(1);
+    VM vm2 = host.getVM(2);
+
+    int locatorPort = DistributedTestUtils.getDUnitLocatorPort();
+
+    // int cacheServer1Port = vm0.invoke("Start Cache1", () -> startCacheWithCacheServer());
+    int cacheServer1Port = startCacheWithCacheServer();
+    int cacheServer2Port = vm1.invoke("Start Cache2", () -> startCacheWithCacheServer());
+    int cacheServer3Port = vm2.invoke("Start Cache3", () -> startCacheWithCacheServer());
+
+    vm0.invoke(() -> {
+      Socket socket = new Socket(host.getHostName(), cacheServer1Port);
+      socket.getOutputStream().write(110);
+
+      ClientProtocol.Request.Builder protobufRequestBuilder =
+          ProtobufUtilities.createProtobufRequestBuilder();
+      ClientProtocol.Message getAvailableServersRequestMessage =
+          ProtobufUtilities.createProtobufMessage(ProtobufUtilities.createMessageHeader(1233445),
+              protobufRequestBuilder.setGetAvailableServersRequest(
+                  ProtobufRequestUtilities.createGetAvailableServersRequest()).build());
+
+      ProtobufProtocolSerializer protobufProtocolSerializer = new ProtobufProtocolSerializer();
+      protobufProtocolSerializer.serialize(getAvailableServersRequestMessage,
+          socket.getOutputStream());
+
+      ClientProtocol.Message getAvailableServersResponseMessage =
+          protobufProtocolSerializer.deserialize(socket.getInputStream());
+      assertEquals(1233445,
+          getAvailableServersResponseMessage.getMessageHeader().getCorrelationId());
+      assertEquals(ClientProtocol.Message.MessageTypeCase.RESPONSE,
+          getAvailableServersResponseMessage.getMessageTypeCase());
+      ClientProtocol.Response messageResponse = getAvailableServersResponseMessage.getResponse();
+      assertEquals(ClientProtocol.Response.ResponseAPICase.GETAVAILABLESERVERSRESPONSE,
+          messageResponse.getResponseAPICase());
+      ServerAPI.GetAvailableServersResponse getAvailableServersResponse =
+          messageResponse.getGetAvailableServersResponse();
+      assertEquals(3, getAvailableServersResponse.getServersCount());
+    });
+  }
+
+  private Integer startCacheWithCacheServer() throws IOException {
+    System.setProperty("geode.feature-protobuf-protocol", "true");
+
+    InternalCache cache = getCache();
+    CacheServer cacheServer = cache.addCacheServer();
+    cacheServer.setPort(0);
+    cacheServer.start();
+    return cacheServer.getPort();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/bf2e0f6e/geode-protobuf/src/test/java/org/apache/geode/protocol/protobuf/operations/GetAvailableServersOperationHandlerJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-protobuf/src/test/java/org/apache/geode/protocol/protobuf/operations/GetAvailableServersOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/protocol/protobuf/operations/GetAvailableServersOperationHandlerJUnitTest.java
new file mode 100644
index 0000000..77b088d
--- /dev/null
+++ b/geode-protobuf/src/test/java/org/apache/geode/protocol/protobuf/operations/GetAvailableServersOperationHandlerJUnitTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.protocol.protobuf.operations;
+
+import org.apache.geode.cache.client.internal.locator.GetAllServersResponse;
+import org.apache.geode.distributed.ConfigurationProperties;
+import org.apache.geode.distributed.internal.InternalDistributedSystem;
+import org.apache.geode.distributed.internal.ServerLocation;
+import org.apache.geode.distributed.internal.tcpserver.TcpClient;
+import org.apache.geode.internal.cache.GemFireCacheImpl;
+import org.apache.geode.protocol.protobuf.BasicTypes;
+import org.apache.geode.protocol.protobuf.Failure;
+import org.apache.geode.protocol.protobuf.Result;
+import org.apache.geode.protocol.protobuf.ServerAPI;
+import org.apache.geode.protocol.protobuf.ServerAPI.GetAvailableServersResponse;
+import org.apache.geode.protocol.protobuf.Success;
+import org.apache.geode.protocol.protobuf.utilities.ProtobufRequestUtilities;
+import org.apache.geode.test.junit.categories.UnitTest;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@Category(UnitTest.class)
+public class GetAvailableServersOperationHandlerJUnitTest extends OperationHandlerJUnitTest {
+
+  private TcpClient mockTCPClient;
+
+  @Before
+  public void setUp() throws Exception {
+    super.setUp();
+
+    operationHandler = mock(GetAvailableServersOperationHandler.class);
+    cacheStub = mock(GemFireCacheImpl.class);
+    when(operationHandler.process(any(), any(), any())).thenCallRealMethod();
+    InternalDistributedSystem mockDistributedSystem = mock(InternalDistributedSystem.class);
+    when(cacheStub.getDistributedSystem()).thenReturn(mockDistributedSystem);
+    Properties mockProperties = mock(Properties.class);
+    when(mockDistributedSystem.getProperties()).thenReturn(mockProperties);
+    String locatorString = "testLocator1Host[12345],testLocator2Host[23456]";
+    when(mockProperties.getProperty(ConfigurationProperties.LOCATORS)).thenReturn(locatorString);
+    mockTCPClient = mock(TcpClient.class);
+    when(((GetAvailableServersOperationHandler) operationHandler).getTcpClient())
+        .thenReturn(mockTCPClient);
+  }
+
+  @Test
+  public void testServerReturnedFromHandler() throws Exception {
+    when(mockTCPClient.requestToServer(any(), any(), anyInt(), anyBoolean()))
+        .thenReturn(new GetAllServersResponse(new ArrayList<ServerLocation>() {
+          {
+            add(new ServerLocation("hostname1", 12345));
+            add(new ServerLocation("hostname2", 23456));
+          }
+        }));
+
+    ServerAPI.GetAvailableServersRequest getAvailableServersRequest =
+        ProtobufRequestUtilities.createGetAvailableServersRequest();
+    Result operationHandlerResult =
+        operationHandler.process(serializationServiceStub, getAvailableServersRequest, cacheStub);
+    assertTrue(operationHandlerResult instanceof Success);
+    ValidateGetAvailableServersResponse(
+        (GetAvailableServersResponse) operationHandlerResult.getMessage());
+  }
+
+  @Test
+  public void testServerReturnedFromSecondLocatorIfFirstDown() throws Exception {
+    when(mockTCPClient.requestToServer(any(), any(), anyInt(), anyBoolean()))
+        .thenThrow(new IOException("BOOM!!!"))
+        .thenReturn(new GetAllServersResponse(new ArrayList<ServerLocation>() {
+          {
+            add(new ServerLocation("hostname1", 12345));
+            add(new ServerLocation("hostname2", 23456));
+          }
+        }));
+
+    ServerAPI.GetAvailableServersRequest getAvailableServersRequest =
+        ProtobufRequestUtilities.createGetAvailableServersRequest();
+    Result operationHandlerResult =
+        operationHandler.process(serializationServiceStub, getAvailableServersRequest, cacheStub);
+    assertTrue(operationHandlerResult instanceof Success);
+    ValidateGetAvailableServersResponse(
+        (GetAvailableServersResponse) operationHandlerResult.getMessage());
+  }
+
+  private void ValidateGetAvailableServersResponse(
+      GetAvailableServersResponse getAvailableServersResponse) {
+    assertEquals(2, getAvailableServersResponse.getServersCount());
+    BasicTypes.Server server = getAvailableServersResponse.getServers(0);
+    assertEquals("hostname1", server.getHostname());
+    assertEquals(12345, server.getPort());
+    server = getAvailableServersResponse.getServers(1);
+    assertEquals("hostname2", server.getHostname());
+    assertEquals(23456, server.getPort());
+  }
+
+  @Test
+  public void testProcessFailsIfNoLocatorsAvailable() throws Exception {
+    when(mockTCPClient.requestToServer(any(), any(), anyInt(), anyBoolean()))
+        .thenThrow(new IOException("BOOM!!!"));
+
+    ServerAPI.GetAvailableServersRequest getAvailableServersRequest =
+        ProtobufRequestUtilities.createGetAvailableServersRequest();
+    Result operationHandlerResult =
+        operationHandler.process(serializationServiceStub, getAvailableServersRequest, cacheStub);
+    assertTrue(operationHandlerResult instanceof Failure);
+  }
+}