Repository: geode Updated Branches: refs/heads/develop 636e970d9 -> bf2e0f6e0
GEODE-3284: New flow: getAvailableServers. This now closed #673 Signed-off-by: Bruce Schuchardt <[email protected]> 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/develop Commit: bf2e0f6e03d1c50580a45efdd3588d1a19bdb5d9 Parents: 636e970 Author: Udo Kohlmeyer <[email protected]> Authored: Mon Jul 31 09:23:53 2017 -0700 Committer: Udo Kohlmeyer <[email protected]> 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); + } +}
