From 68cfb23e8e5fd21b79908bf46d6b17630e3fcc9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Herrera=20de=20la=20Garza?= Date: Tue, 21 Jan 2020 22:25:36 -0600 Subject: [PATCH 1/7] Add GRP State Integration Test --- .../io/dapr/client/DaprClientGrpcAdapter.java | 7 +- .../io/dapr/client/DaprClientTestBuilder.java | 15 + sdk/src/test/java/io/dapr/it/BaseIT.java | 1 + .../dapr/it/DaprIntegrationTestingRunner.java | 4 + .../io/dapr/it/state/GRPCStateClientIT.java | 546 ++++++++++++++++++ 5 files changed, 571 insertions(+), 2 deletions(-) create mode 100644 sdk/src/test/java/io/dapr/it/state/GRPCStateClientIT.java diff --git a/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java b/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java index 3a2694f2ff..32d09feb2d 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java @@ -352,8 +352,11 @@ public Mono deleteState(String key, String etag, StateOptions options) { } } DaprProtos.DeleteStateEnvelope.Builder builder = DaprProtos.DeleteStateEnvelope.newBuilder() - .setEtag(etag) - .setKey(key); + .setKey(key); + if(etag != null) { + builder.setEtag(etag); + } + if (optionBuilder != null) { builder.setOptions(optionBuilder.build()); } diff --git a/sdk/src/test/java/io/dapr/client/DaprClientTestBuilder.java b/sdk/src/test/java/io/dapr/client/DaprClientTestBuilder.java index 65333e2e1b..88570a554c 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientTestBuilder.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientTestBuilder.java @@ -5,6 +5,11 @@ package io.dapr.client; +import io.dapr.DaprGrpc; +import io.dapr.utils.Constants; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; + /** * Builder for DaprClient used in tests only. */ @@ -18,4 +23,14 @@ public class DaprClientTestBuilder { public static DaprClient buildHttpClient(DaprHttp client) { return new DaprClientHttpAdapter(client); } + + /** + * Builds a DaprGrpcClient. + * @return New instance of DaprClient. + */ + public static DaprClient buildGrpcClient(){ + int gprcPort = Integer.parseInt(System.getenv(Constants.ENV_DAPR_GRPC_PORT)); + ManagedChannel channel = ManagedChannelBuilder.forAddress(Constants.DEFAULT_HOSTNAME, gprcPort).usePlaintext().build(); + return new DaprClientGrpcAdapter(DaprGrpc.newFutureStub(channel), new DefaultObjectSerializer()); + } } diff --git a/sdk/src/test/java/io/dapr/it/BaseIT.java b/sdk/src/test/java/io/dapr/it/BaseIT.java index 2f5f462280..2eb7092ce4 100644 --- a/sdk/src/test/java/io/dapr/it/BaseIT.java +++ b/sdk/src/test/java/io/dapr/it/BaseIT.java @@ -27,6 +27,7 @@ public class BaseIT { @BeforeClass public static void setEnvironmentVariables(){ environmentVariables.set("DAPR_HTTP_PORT", String.valueOf(DAPR_FREEPORTS.getHttpPort())); + environmentVariables.set("DAPR_GRPC_PORT", String.valueOf(DAPR_FREEPORTS.getGrpcPort())); } public static DaprIntegrationTestingRunner createDaprIntegrationTestingRunner(String successMessage, Class serviceClass, Boolean useAppPort, int sleepTime) { diff --git a/sdk/src/test/java/io/dapr/it/DaprIntegrationTestingRunner.java b/sdk/src/test/java/io/dapr/it/DaprIntegrationTestingRunner.java index 0065fe0f2a..59a4fd0ff8 100644 --- a/sdk/src/test/java/io/dapr/it/DaprIntegrationTestingRunner.java +++ b/sdk/src/test/java/io/dapr/it/DaprIntegrationTestingRunner.java @@ -85,6 +85,10 @@ public DaprFreePorts initializeDapr() throws Exception { private String buildDaprCommand(){ StringBuilder stringBuilder= new StringBuilder(String.format(DAPR_RUN, this.appName)) .append(this.useAppPort ? "--app-port " + this.DAPR_FREEPORTS.appPort : "") + .append(" --grpc-port ") + .append(this.DAPR_FREEPORTS.grpcPort) + .append(" --port ") + .append(this.DAPR_FREEPORTS.httpPort) .append(String.format(DAPR_COMMAND, this.serviceClass.getCanonicalName(),this.DAPR_FREEPORTS.appPort)); return stringBuilder.toString(); } diff --git a/sdk/src/test/java/io/dapr/it/state/GRPCStateClientIT.java b/sdk/src/test/java/io/dapr/it/state/GRPCStateClientIT.java new file mode 100644 index 0000000000..687c9b21a3 --- /dev/null +++ b/sdk/src/test/java/io/dapr/it/state/GRPCStateClientIT.java @@ -0,0 +1,546 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.it.state; + +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientTestBuilder; +import io.dapr.client.domain.State; +import io.dapr.client.domain.StateOptions; +import io.dapr.it.BaseIT; +import io.dapr.it.services.EmptyService; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +import static org.junit.Assert.*; + +/** + * Test State GRPC DAPR capabilities using a DAPR instance with an empty service running + */ +public class GRPCStateClientIT extends BaseIT { + + private static DaprClient daprClient; + + @BeforeClass + public static void init() throws Exception { + daprIntegrationTestingRunner = + createDaprIntegrationTestingRunner( + "BUILD SUCCESS", + EmptyService.class, + false, + 0 + ); + daprIntegrationTestingRunner.initializeDapr(); + daprClient = DaprClientTestBuilder.buildGrpcClient(); + } + + + @Test + public void saveAndGetState() { + + //The key use to store the state + final String stateKey = "myKey"; + + //create the http client + + + //creation of a dummy data + MyData data = new MyData(); + data.setPropertyA("data in property A"); + data.setPropertyB("data in property B"); + + //create of the deferred call to DAPR to store the state + Mono saveResponse = daprClient.saveState(stateKey, null, data, null); + //execute the save action + saveResponse.block(); + + //create of the deferred call to DAPR to get the state + Mono> response = daprClient.getState(new State(stateKey, null, null), MyData.class); + + //retrieve the state + State myDataResponse = response.block(); + + //Assert that the response is the correct one + assertNotNull(myDataResponse.getEtag()); + assertNotNull(myDataResponse.getKey()); + assertNotNull(myDataResponse.getValue()); + assertEquals("data in property A", myDataResponse.getValue().getPropertyA()); + assertEquals("data in property B", myDataResponse.getValue().getPropertyB()); + } + + @Test + public void saveUpdateAndGetState() { + + //The key use to store the state and be updated + final String stateKey = "keyToBeUpdated"; + + //create http DAPR client + + //Create dummy data to be store + MyData data = new MyData(); + data.setPropertyA("data in property A"); + data.setPropertyB("data in property B"); + + //Create deferred action to save the sate + Mono saveResponse = daprClient.saveState(stateKey, null, data, null); + //execute save action to DAPR + saveResponse.block(); + + //change data properties + data.setPropertyA("data in property A"); + data.setPropertyB("data in property B2"); + //create deferred action to update the sate without any etag or options + saveResponse = daprClient.saveState(stateKey, null, data, null); + //execute the update action to DAPR + saveResponse.block(); + + //Create deferred action to retrieve the action + Mono> response = daprClient.getState(new State(stateKey, null, null), MyData.class); + //execute the retrieve of the state + State myDataResponse = response.block(); + + //review that the update was success action + assertEquals("data in property A", myDataResponse.getValue().getPropertyA()); + assertEquals("data in property B2", myDataResponse.getValue().getPropertyB()); + } + + @Test + public void saveAndDeleteState() { + //The key use to store the state and be deleted + final String stateKey = "myeKeyToBeDeleted"; + + //Create dummy data to be store + MyData data = new MyData(); + data.setPropertyA("data in property A"); + data.setPropertyB("data in property B"); + //Create deferred action to save the sate + Mono saveResponse = daprClient.saveState(stateKey, null, data, null); + //execute the save state action + saveResponse.block(); + + //Create deferred action to retrieve the state + Mono> response = daprClient.getState(new State(stateKey, null, null), MyData.class); + //execute the retrieve of the state + State myDataResponse = response.block(); + + //review that the state was saved correctly + assertEquals("data in property A", myDataResponse.getValue().getPropertyA()); + assertEquals("data in property B", myDataResponse.getValue().getPropertyB()); + + //create deferred action to delete the state + Mono deleteResponse = daprClient.deleteState(stateKey, null, null); + //execute the delete action + deleteResponse.block(); + + //Create deferred action to retrieve the state + response = daprClient.getState(new State(stateKey, null, null), MyData.class); + //execute the retrieve of the state + myDataResponse = response.block(); + + //review that the action does not return any value, because the state was deleted + assertNull(myDataResponse.getValue()); + } + + + @Test + public void saveUpdateAndGetStateWithEtag() { + //The key use to store the state and be updated using etags + final String stateKey = "keyToBeUpdatedWithEtag"; + + + //Create dummy data to be store + MyData data = new MyData(); + data.setPropertyA("data in property A"); + data.setPropertyB("data in property B"); + + //Create deferred action to save the sate + Mono saveResponse = daprClient.saveState(stateKey, null, data, null); + //execute the save state action + saveResponse.block(); + + //Create deferred action to retrieve the state + Mono> response = daprClient.getState(new State(stateKey, null, null), MyData.class); + //execute the action for retrieve the state and the etag + State myDataResponse = response.block(); + + //review that the etag is not empty + assertNotNull(myDataResponse.getEtag()); + assertNotNull(myDataResponse.getKey()); + assertNotNull(myDataResponse.getValue()); + assertEquals("data in property A", myDataResponse.getValue().getPropertyA()); + assertEquals("data in property B", myDataResponse.getValue().getPropertyB()); + + String firstETag = myDataResponse.getEtag(); + + //change the data in order to update the state + data.setPropertyA("data in property A2"); + data.setPropertyB("data in property B2"); + //Create deferred action to update the data using the correct etag + saveResponse = daprClient.saveState(stateKey, myDataResponse.getEtag(), data, null); + saveResponse.block(); + + + response = daprClient.getState(new State(stateKey, null, null), MyData.class); + //retrive the data wihout any etag + myDataResponse = response.block(); + + //review that state value changes + assertNotNull(myDataResponse.getEtag()); + //review that the etag changes after an update + assertNotEquals(firstETag,myDataResponse.getEtag()); + assertNotNull(myDataResponse.getKey()); + assertNotNull(myDataResponse.getValue()); + assertEquals("data in property A2", myDataResponse.getValue().getPropertyA()); + assertEquals("data in property B2", myDataResponse.getValue().getPropertyB()); + } + + @Ignore + @Test(expected = RuntimeException.class) + public void saveUpdateAndGetStateWithWrongEtag() { + final String stateKey = "keyToBeUpdatedWithWrongEtag"; + + //Create dummy data to be store + MyData data = new MyData(); + data.setPropertyA("data in property A"); + data.setPropertyB("data in property B"); + + //Create deferred action to save the sate + Mono saveResponse = daprClient.saveState(stateKey, null, data, null); + //execute the save state action + saveResponse.block(); + + //Create deferred action to retrieve the state + Mono> response = daprClient.getState(new State(stateKey, null, null), MyData.class); + //execute the action for retrieve the state and the etag + State myDataResponse = response.block(); + + //review that the etag is not empty + assertNotNull(myDataResponse.getEtag()); + assertNotNull(myDataResponse.getKey()); + assertNotNull(myDataResponse.getValue()); + assertEquals("data in property A", myDataResponse.getValue().getPropertyA()); + assertEquals("data in property B", myDataResponse.getValue().getPropertyB()); + + String firstETag = myDataResponse.getEtag(); + + //change the data in order to update the state + data.setPropertyA("data in property A2"); + data.setPropertyB("data in property B2"); + //Create deferred action to update the data using the incorrect etag + saveResponse = daprClient.saveState(stateKey, "99999999999999", data, null); + saveResponse.block(); + + + + response = daprClient.getState(new State(stateKey, null, null), MyData.class); + //retrive the data wihout any etag + myDataResponse = response.block(); + + //review that state value changes + assertNotNull(myDataResponse.getEtag()); + //review that the etag changes after an update + assertNotEquals(firstETag,myDataResponse.getEtag()); + assertNotNull(myDataResponse.getKey()); + assertNotNull(myDataResponse.getValue()); + assertEquals("data in property A2", myDataResponse.getValue().getPropertyA()); + assertEquals("data in property B2", myDataResponse.getValue().getPropertyB()); + } + + @Test + public void saveAndDeleteStateWithEtag() { + final String stateKey = "myeKeyToBeDeletedWithEtag"; + + + //Create dummy data to be store + MyData data = new MyData(); + data.setPropertyA("data in property A"); + data.setPropertyB("data in property B"); + //Create deferred action to save the sate + Mono saveResponse = daprClient.saveState(stateKey, null, data, null); + //execute the save state action + saveResponse.block(); + + //Create deferred action to get the state with the etag + Mono> response = daprClient.getState(new State(stateKey, null, null), MyData.class); + //execute the get state + State myDataResponse = response.block(); + + assertNotNull(myDataResponse.getEtag()); + assertNotNull(myDataResponse.getKey()); + assertNotNull(myDataResponse.getValue()); + assertEquals("data in property A", myDataResponse.getValue().getPropertyA()); + assertEquals("data in property B", myDataResponse.getValue().getPropertyB()); + + //Create deferred action to delete an state sending the etag + Mono deleteResponse = daprClient.deleteState(stateKey, myDataResponse.getEtag(), null); + //execute the delete of the state + deleteResponse.block(); + + //Create deferred action to get the sate without an etag + response = daprClient.getState(new State(stateKey, null, null), MyData.class); + myDataResponse = response.block(); + + //Review that the response is null, because the state was deleted + assertNull(myDataResponse.getValue()); + } + + @Ignore + @Test(expected = RuntimeException.class) + public void saveAndDeleteStateWithWrongEtag() { + final String stateKey = "myeKeyToBeDeletedWithWrongEtag"; + + + + //Create dummy data to be store + MyData data = new MyData(); + data.setPropertyA("data in property A"); + data.setPropertyB("data in property B"); + //Create deferred action to save the sate + Mono saveResponse = daprClient.saveState(stateKey, null, data, null); + //execute the save state action + saveResponse.block(); + + //Create deferred action to get the state with the etag + Mono> response = daprClient.getState(new State(stateKey, null, null), MyData.class); + //execute the get state + State myDataResponse = response.block(); + + assertNotNull(myDataResponse.getEtag()); + assertNotNull(myDataResponse.getKey()); + assertNotNull(myDataResponse.getValue()); + assertEquals("data in property A", myDataResponse.getValue().getPropertyA()); + assertEquals("data in property B", myDataResponse.getValue().getPropertyB()); + + //Create deferred action to delete an state sending the incorrect etag + Mono deleteResponse = daprClient.deleteState(stateKey, "99999999999", null); + //execute the delete of the state, this should trhow an exception + deleteResponse.block(); + + //Create deferred action to get the sate without an etag + response = daprClient.getState(new State(stateKey, null, null), MyData.class); + myDataResponse = response.block(); + + //Review that the response is null, because the state was deleted + assertNull(myDataResponse.getValue()); + } + + @Ignore + @Test(expected = RuntimeException.class) + public void saveUpdateAndGetStateWithEtagAndStateOptionsFirstWrite() { + final String stateKey = "keyToBeUpdatedWithEtagAndOptions"; + + //create option with concurrency with first writte and consistency of strong + StateOptions stateOptions = new StateOptions(StateOptions.Consistency.STRONG, StateOptions.Concurrency.FIRST_WRITE, null); + + + + //create Dummy data + MyData data = new MyData(); + data.setPropertyA("data in property A"); + data.setPropertyB("data in property B"); + + //create state using stateOptions + Mono saveResponse = daprClient.saveState(stateKey, null, data, stateOptions); + //execute the save state + saveResponse.block(); + + + //crate deferred action to retrieve the state + Mono> response = daprClient.getState(new State(stateKey, null, stateOptions), MyData.class); + //execute the retrieve of the state using options + State myDataResponse = response.block(); + + assertNotNull(myDataResponse.getEtag()); + assertNotNull(myDataResponse.getKey()); + assertNotNull(myDataResponse.getValue()); + assertEquals("data in property A", myDataResponse.getValue().getPropertyA()); + assertEquals("data in property B", myDataResponse.getValue().getPropertyB()); + + //change data to be udpated + data.setPropertyA("data in property A2"); + data.setPropertyB("data in property B2"); + //create deferred action to update the action with options + saveResponse = daprClient.saveState(stateKey, myDataResponse.getEtag(), data, stateOptions); + //update the state + saveResponse.block(); + + + data.setPropertyA("last write"); + data.setPropertyB("data in property B2"); + //create deferred action to update the action with the same etag + saveResponse = daprClient.saveState(stateKey, myDataResponse.getEtag(), data, stateOptions); + //throws an exception, the state was already udpated + saveResponse.block(); + + response = daprClient.getState(new State(stateKey, null, stateOptions), MyData.class); + State myLastDataResponse = response.block(); + + assertNotNull(myLastDataResponse.getEtag()); + assertNotNull(myLastDataResponse.getKey()); + assertNotNull(myLastDataResponse.getValue()); + assertNotNull(myDataResponse.getEtag(), myLastDataResponse.getEtag()); + assertEquals("data in property A2", myLastDataResponse.getValue().getPropertyA()); + assertEquals("data in property B2", myLastDataResponse.getValue().getPropertyB()); + } + + @Test() + public void saveUpdateAndGetStateWithEtagAndStateOptionsLastWrite() { + final String stateKey = "keyToBeUpdatedWithEtagAndOptions"; + + //create option with concurrency with first writte and consistency of strong + StateOptions stateOptions = new StateOptions(StateOptions.Consistency.STRONG, StateOptions.Concurrency.LAST_WRITE, null); + + + + //create Dummy data + MyData data = new MyData(); + data.setPropertyA("data in property A"); + data.setPropertyB("data in property B"); + + //create state using stateOptions + Mono saveResponse = daprClient.saveState(stateKey, null, data, stateOptions); + //execute the save state + saveResponse.block(); + + + //crate deferred action to retrieve the state + Mono> response = daprClient.getState(new State(stateKey, null, stateOptions), MyData.class); + //execute the retrieve of the state using options + State myDataResponse = response.block(); + + assertNotNull(myDataResponse.getEtag()); + assertNotNull(myDataResponse.getKey()); + assertNotNull(myDataResponse.getValue()); + assertEquals("data in property A", myDataResponse.getValue().getPropertyA()); + assertEquals("data in property B", myDataResponse.getValue().getPropertyB()); + + //change data to be udpated + data.setPropertyA("data in property A2"); + data.setPropertyB("data in property B2"); + //create deferred action to update the action with options + saveResponse = daprClient.saveState(stateKey, myDataResponse.getEtag(), data, stateOptions); + //update the state + saveResponse.block(); + + + data.setPropertyA("last write"); + data.setPropertyB("data in property B2"); + //create deferred action to update the action with the same etag + saveResponse = daprClient.saveState(stateKey, myDataResponse.getEtag(), data, stateOptions); + //update the state without an error + saveResponse.block(); + + response = daprClient.getState(new State(stateKey, null, stateOptions), MyData.class); + State myLastDataResponse = response.block(); + + assertNotNull(myLastDataResponse.getEtag()); + assertNotNull(myLastDataResponse.getKey()); + assertNotNull(myLastDataResponse.getValue()); + assertNotNull(myDataResponse.getEtag(), myLastDataResponse.getEtag()); + assertEquals("last write", myLastDataResponse.getValue().getPropertyA()); + assertEquals("data in property B2", myLastDataResponse.getValue().getPropertyB()); + } + + @Test(timeout=13000) + public void saveDeleteWithRetry() { + final String stateKey = "keyToBeDeleteWithWrongEtagAndRetry"; + StateOptions.RetryPolicy retryPolicy= new StateOptions.RetryPolicy(Duration.ofSeconds(3),3, StateOptions.RetryPolicy.Pattern.LINEAR); + StateOptions stateOptions = new StateOptions(null, null, retryPolicy); + + + + //Create dummy data to be store + MyData data = new MyData(); + data.setPropertyA("data in property A"); + data.setPropertyB("data in property B"); + + //Create deferred action to save the sate + Mono saveResponse = daprClient.saveState(stateKey, null, data, null); + //execute the save state action + saveResponse.block(); + + //Create deferred action to retrieve the state + Mono> response = daprClient.getState(new State(stateKey, null, null), MyData.class); + //execute the action for retrieve the state and the etag + State myDataResponse = response.block(); + + //review that the etag is not empty + assertNotNull(myDataResponse.getEtag()); + assertNotNull(myDataResponse.getKey()); + assertNotNull(myDataResponse.getValue()); + assertEquals("data in property A", myDataResponse.getValue().getPropertyA()); + assertEquals("data in property B", myDataResponse.getValue().getPropertyB()); + + + Mono deleteResponse = daprClient.deleteState(stateKey, "99999999", stateOptions); + + long start = System.currentTimeMillis(); + try { + //delete action + deleteResponse.block(); + }catch(RuntimeException ex){ + assertTrue(ex.getMessage().contains("failed to set value after 3 retries")); + } + long end = System.currentTimeMillis(); + System.out.println("DEBUG: Logic A took " + (end - start) + " MilliSeconds"); + long elapsedTime = end -start; + assertTrue(elapsedTime>9000 && elapsedTime<9200); + + } + + @Ignore("Ignored as an issue on DAPR") + @Test(timeout=13000) + public void saveUpdateWithRetry() { + final String stateKey = "keyToBeDeleteWithWrongEtagAndRetry"; + StateOptions.RetryPolicy retryPolicy= new StateOptions.RetryPolicy(Duration.ofSeconds(4),3, StateOptions.RetryPolicy.Pattern.LINEAR); + StateOptions stateOptions = new StateOptions(null, null, retryPolicy); + + + + //Create dummy data to be store + MyData data = new MyData(); + data.setPropertyA("data in property A"); + data.setPropertyB("data in property B"); + + //Create deferred action to save the sate + Mono saveResponse = daprClient.saveState(stateKey, null, data, null); + //execute the save state action + saveResponse.block(); + + //Create deferred action to retrieve the state + Mono> response = daprClient.getState(new State(stateKey, null, null), MyData.class); + //execute the action for retrieve the state and the etag + State myDataResponse = response.block(); + + //review that the etag is not empty + assertNotNull(myDataResponse.getEtag()); + assertNotNull(myDataResponse.getKey()); + assertNotNull(myDataResponse.getValue()); + assertEquals("data in property A", myDataResponse.getValue().getPropertyA()); + assertEquals("data in property B", myDataResponse.getValue().getPropertyB()); + + //Create deferred action to save the sate + saveResponse = daprClient.saveState(stateKey, "9999999", data, stateOptions); + //execute the save state action + long start = System.currentTimeMillis(); + + + try { + saveResponse.block(); + }catch(RuntimeException ex){ + assertTrue(ex.getMessage().contains("failed to set value after 3 retries")); + } + long end = System.currentTimeMillis(); + System.out.println("DEBUG: Logic A took " + (end - start) + " MilliSeconds"); + long elapsedTime = end -start; + assertTrue(elapsedTime>9000 && elapsedTime<9200); + + } + +} From 0d5ef02841bb729c52faa03edf455e4072f5a527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Herrera=20de=20la=20Garza?= Date: Wed, 22 Jan 2020 19:44:56 -0600 Subject: [PATCH 2/7] Explain ignored test cases for GRPC --- sdk/src/test/java/io/dapr/it/state/GRPCStateClientIT.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/src/test/java/io/dapr/it/state/GRPCStateClientIT.java b/sdk/src/test/java/io/dapr/it/state/GRPCStateClientIT.java index 687c9b21a3..b31e81af34 100644 --- a/sdk/src/test/java/io/dapr/it/state/GRPCStateClientIT.java +++ b/sdk/src/test/java/io/dapr/it/state/GRPCStateClientIT.java @@ -200,7 +200,7 @@ public void saveUpdateAndGetStateWithEtag() { assertEquals("data in property B2", myDataResponse.getValue().getPropertyB()); } - @Ignore + @Ignore("This test case is ignored because DAPR ignore the ETag is wrong when is sent from GRPC protocol, the execution continues and the state is updated.") @Test(expected = RuntimeException.class) public void saveUpdateAndGetStateWithWrongEtag() { final String stateKey = "keyToBeUpdatedWithWrongEtag"; @@ -290,7 +290,7 @@ public void saveAndDeleteStateWithEtag() { assertNull(myDataResponse.getValue()); } - @Ignore + @Ignore("This test case is ignored because DAPR ignore if the ETag is wrong when is sent from GRPC protocol, the execution continues and the state is deleted.") @Test(expected = RuntimeException.class) public void saveAndDeleteStateWithWrongEtag() { final String stateKey = "myeKeyToBeDeletedWithWrongEtag"; From 5bff72f6e6239f0486aafcb4a30bed3ff7cb5344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Herrera=20de=20la=20Garza?= Date: Thu, 23 Jan 2020 13:41:05 -0600 Subject: [PATCH 3/7] Explain ignored test cases for GRPC --- sdk/src/test/java/io/dapr/it/state/GRPCStateClientIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/test/java/io/dapr/it/state/GRPCStateClientIT.java b/sdk/src/test/java/io/dapr/it/state/GRPCStateClientIT.java index b31e81af34..2ca6cf612d 100644 --- a/sdk/src/test/java/io/dapr/it/state/GRPCStateClientIT.java +++ b/sdk/src/test/java/io/dapr/it/state/GRPCStateClientIT.java @@ -330,7 +330,7 @@ public void saveAndDeleteStateWithWrongEtag() { assertNull(myDataResponse.getValue()); } - @Ignore + @Ignore("This test case is ignored because it seems that DAPR using GRPC is ignoring the state options for consistency and concurrency.") @Test(expected = RuntimeException.class) public void saveUpdateAndGetStateWithEtagAndStateOptionsFirstWrite() { final String stateKey = "keyToBeUpdatedWithEtagAndOptions"; From 19f77d8b8b4917cf81891046236459eea8d7234b Mon Sep 17 00:00:00 2001 From: Artur Souza Date: Thu, 23 Jan 2020 13:06:10 -0800 Subject: [PATCH 4/7] Update DaprClientTestBuilder.java --- sdk/src/test/java/io/dapr/client/DaprClientTestBuilder.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sdk/src/test/java/io/dapr/client/DaprClientTestBuilder.java b/sdk/src/test/java/io/dapr/client/DaprClientTestBuilder.java index 88570a554c..802cf1c589 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientTestBuilder.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientTestBuilder.java @@ -6,6 +6,7 @@ package io.dapr.client; import io.dapr.DaprGrpc; +import io.dapr.serializer.DefaultObjectSerializer; import io.dapr.utils.Constants; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; @@ -31,6 +32,8 @@ public static DaprClient buildHttpClient(DaprHttp client) { public static DaprClient buildGrpcClient(){ int gprcPort = Integer.parseInt(System.getenv(Constants.ENV_DAPR_GRPC_PORT)); ManagedChannel channel = ManagedChannelBuilder.forAddress(Constants.DEFAULT_HOSTNAME, gprcPort).usePlaintext().build(); - return new DaprClientGrpcAdapter(DaprGrpc.newFutureStub(channel), new DefaultObjectSerializer()); + return new DaprClientGrpcAdapter(DaprGrpc.newFutureStub(channel), + new DefaultObjectSerializer(), + new DefaultObjectSerializer()); } } From 76a13c2b99d27328e6c01086687313e2111bf98e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Herrera=20de=20la=20Garza?= Date: Fri, 24 Jan 2020 11:11:21 -0600 Subject: [PATCH 5/7] Add binding E2E testing. --- pom.xml | 8 +- sdk/pom.xml | 12 +++ .../dapr/it/DaprIntegrationTestingRunner.java | 16 ++- .../it/binding/http/OutputBindingExample.java | 102 ++++++++++++++++++ .../it/services/InputBindingController.java | 39 +++++++ .../dapr/it/services/InputBindingExample.java | 30 ++++++ 6 files changed, 200 insertions(+), 7 deletions(-) create mode 100644 sdk/src/test/java/io/dapr/it/binding/http/OutputBindingExample.java create mode 100644 sdk/src/test/java/io/dapr/it/services/InputBindingController.java create mode 100644 sdk/src/test/java/io/dapr/it/services/InputBindingExample.java diff --git a/pom.xml b/pom.xml index 81dc4e5b21..79ad69d0c2 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 8 true true - true + @@ -112,15 +112,15 @@ org.codehaus.mojo failsafe-maven-plugin 2.4.3-alpha-1 - - ${skipITs} - integration-test verify + + ${skipITs} + diff --git a/sdk/pom.xml b/sdk/pom.xml index ac83d76628..6793749a87 100644 --- a/sdk/pom.xml +++ b/sdk/pom.xml @@ -92,6 +92,18 @@ 5.5.2 test + + org.springframework.boot + spring-boot-starter-web + 2.2.2.RELEASE + test + + + org.springframework.boot + spring-boot-autoconfigure + 2.2.2.RELEASE + test + diff --git a/sdk/src/test/java/io/dapr/it/DaprIntegrationTestingRunner.java b/sdk/src/test/java/io/dapr/it/DaprIntegrationTestingRunner.java index 59a4fd0ff8..5abb5dbcb1 100644 --- a/sdk/src/test/java/io/dapr/it/DaprIntegrationTestingRunner.java +++ b/sdk/src/test/java/io/dapr/it/DaprIntegrationTestingRunner.java @@ -83,7 +83,7 @@ public DaprFreePorts initializeDapr() throws Exception { private static final String DAPR_COMMAND = " -- mvn exec:java -Dexec.mainClass=%s -Dexec.classpathScope=test -Dexec.args=\"%d\""; private String buildDaprCommand(){ - StringBuilder stringBuilder= new StringBuilder(String.format(DAPR_RUN, this.appName)) + StringBuilder stringBuilder= new StringBuilder(String.format(DAPR_RUN, this.getAppName())) .append(this.useAppPort ? "--app-port " + this.DAPR_FREEPORTS.appPort : "") .append(" --grpc-port ") .append(this.DAPR_FREEPORTS.grpcPort) @@ -110,12 +110,22 @@ private static Integer findRandomOpenPortOnAllLocalInterfaces() throws Exception public void destroyDapr() { Optional.ofNullable(rt).ifPresent( runtime -> { try { - runtime.exec("dapr stop --app-id " + this.appName); + System.out.println("Start dapr Stop"); + runtime.exec("dapr stop --app-id " + this.getAppName()); + System.out.println("End Dapr Stop"); } catch (IOException e) { throw new RuntimeException(e); } }); - Optional.ofNullable(proc).ifPresent(process -> process.destroy()); + Optional.ofNullable(proc).ifPresent(process -> { + System.out.println("Start process Stop"); + process.destroyForcibly(); + System.out.println("End process Stop"); + }); + } + + public String getAppName() { + return appName; } public static class DaprFreePorts diff --git a/sdk/src/test/java/io/dapr/it/binding/http/OutputBindingExample.java b/sdk/src/test/java/io/dapr/it/binding/http/OutputBindingExample.java new file mode 100644 index 0000000000..4ea8734cb3 --- /dev/null +++ b/sdk/src/test/java/io/dapr/it/binding/http/OutputBindingExample.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.it.binding.http; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; +import io.dapr.client.DefaultObjectSerializer; +import io.dapr.client.domain.Verb; +import io.dapr.it.BaseIT; +import io.dapr.it.DaprIntegrationTestingRunner; +import io.dapr.it.services.InputBindingExample; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.Base64; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * Service for output binding example. + * 1. From your repo root, build and install jars: + * mvn clean install + * 2. cd to [repo-root]/examples + * 3. Run the program: + * dapr run --app-id outputbinding --port 3006 -- mvn exec:java -Dexec.mainClass=io.dapr.examples.bindings.http.OutputBindingExample + */ +public class OutputBindingExample extends BaseIT { + + private static DaprClient client; + + @BeforeClass + public static void init() throws Exception { + daprIntegrationTestingRunner = + createDaprIntegrationTestingRunner( + "dapr initialized. Status: Running. Init Elapsed", + InputBindingExample.class, + true, + 19000 + ); + daprIntegrationTestingRunner.initializeDapr(); + client = new DaprClientBuilder(new DefaultObjectSerializer()).build(); + } + + public static class MyClass { + public MyClass(){} + public String message; + } + + @Test + public void BindingTest() { + + + final String BINDING_NAME = "sample123"; + + // This is an example of sending data in a user-defined object. The input binding will receive: + // {"message":"hello"} + MyClass myClass = new MyClass(); + myClass.message = "hello"; + + System.out.println("sending first message"); + client.invokeBinding(BINDING_NAME, myClass).block(); + + // This is an example of sending a plain string. The input binding will receive + // cat + final String m = "cat"; + System.out.println("sending " + m); + client.invokeBinding(BINDING_NAME, m).block(); + + try { + Thread.sleep(8000); + } catch (InterruptedException e) { + e.printStackTrace(); + Thread.currentThread().interrupt(); + return; + } + + final List messages = client.invokeService(Verb.GET, daprIntegrationTestingRunner.getAppName(), "messages", null, List.class).block(); + assertEquals(2,messages.size()); + MyClass resultClass = null; + try { + resultClass = new ObjectMapper().readValue(new String(Base64.getDecoder().decode(messages.get(0))), MyClass.class); + }catch (Exception ex) + { + ex.printStackTrace(); + fail("Error on decode message 1"); + } + + try { + assertEquals("cat", new ObjectMapper().readValue(new String(Base64.getDecoder().decode(messages.get(1))), String.class)); + }catch (Exception ex){ + ex.printStackTrace(); + fail("Error on decode message 2"); + } + assertEquals("hello",resultClass.message); + } +} diff --git a/sdk/src/test/java/io/dapr/it/services/InputBindingController.java b/sdk/src/test/java/io/dapr/it/services/InputBindingController.java new file mode 100644 index 0000000000..273f1fe37e --- /dev/null +++ b/sdk/src/test/java/io/dapr/it/services/InputBindingController.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.it.services; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; +import java.util.List; + +/** + * SpringBoot Controller to handle input binding. + */ +@RestController +public class InputBindingController { + + private static final List messagesReceived = new ArrayList(); + + @PostMapping(path = "/sample123") + public Mono handleInputBinding(@RequestBody(required = false) byte[] body) { + messagesReceived.add(body); + return Mono.fromRunnable(() -> + System.out.println("Received message through binding: " + (body == null ? "" : new String(body)))); + } + + @GetMapping(path = "/messages") + public Mono> getMessages(){ + return Mono.just( messagesReceived); + } + + + +} diff --git a/sdk/src/test/java/io/dapr/it/services/InputBindingExample.java b/sdk/src/test/java/io/dapr/it/services/InputBindingExample.java new file mode 100644 index 0000000000..8a84e34fc3 --- /dev/null +++ b/sdk/src/test/java/io/dapr/it/services/InputBindingExample.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.it.services; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication(scanBasePackages = {"io.dapr.it.services"}) +public class InputBindingExample { + + public static void main(String[] args) throws Exception { + // If port string is not valid, it will throw an exception. + int port = Integer.parseInt(args[0]); + // Start Dapr's callback endpoint. + InputBindingExample.start(port); + } + + /** + * Starts Dapr's callback in a given port. + * @param port Port to listen to. + */ + public static void start(int port) { + SpringApplication app = new SpringApplication(InputBindingExample.class); + app.run(String.format("--server.port=%d", port)); + } + +} From 0ff2c32847f3c4701c2ca37a9949daf639bc5917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Herrera=20de=20la=20Garza?= Date: Fri, 24 Jan 2020 11:17:59 -0600 Subject: [PATCH 6/7] Add fix binding E2E testing after merge with new changes --- .../java/io/dapr/it/binding/http/OutputBindingExample.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sdk/src/test/java/io/dapr/it/binding/http/OutputBindingExample.java b/sdk/src/test/java/io/dapr/it/binding/http/OutputBindingExample.java index 4ea8734cb3..b193518256 100644 --- a/sdk/src/test/java/io/dapr/it/binding/http/OutputBindingExample.java +++ b/sdk/src/test/java/io/dapr/it/binding/http/OutputBindingExample.java @@ -8,11 +8,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; -import io.dapr.client.DefaultObjectSerializer; import io.dapr.client.domain.Verb; import io.dapr.it.BaseIT; -import io.dapr.it.DaprIntegrationTestingRunner; import io.dapr.it.services.InputBindingExample; +import io.dapr.serializer.DefaultObjectSerializer; import org.junit.BeforeClass; import org.junit.Test; @@ -44,7 +43,7 @@ public static void init() throws Exception { 19000 ); daprIntegrationTestingRunner.initializeDapr(); - client = new DaprClientBuilder(new DefaultObjectSerializer()).build(); + client = new DaprClientBuilder(new DefaultObjectSerializer(), new DefaultObjectSerializer()).build(); } public static class MyClass { From ce3ee5af7d74c23be2d015f84a412b49b22db083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Herrera=20de=20la=20Garza?= Date: Fri, 24 Jan 2020 13:22:32 -0600 Subject: [PATCH 7/7] Remove example comments --- .../io/dapr/it/binding/http/OutputBindingExample.java | 5 ----- .../java/io/dapr/it/services/InputBindingController.java | 8 +++++--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/sdk/src/test/java/io/dapr/it/binding/http/OutputBindingExample.java b/sdk/src/test/java/io/dapr/it/binding/http/OutputBindingExample.java index b193518256..19d53d376c 100644 --- a/sdk/src/test/java/io/dapr/it/binding/http/OutputBindingExample.java +++ b/sdk/src/test/java/io/dapr/it/binding/http/OutputBindingExample.java @@ -23,11 +23,6 @@ /** * Service for output binding example. - * 1. From your repo root, build and install jars: - * mvn clean install - * 2. cd to [repo-root]/examples - * 3. Run the program: - * dapr run --app-id outputbinding --port 3006 -- mvn exec:java -Dexec.mainClass=io.dapr.examples.bindings.http.OutputBindingExample */ public class OutputBindingExample extends BaseIT { diff --git a/sdk/src/test/java/io/dapr/it/services/InputBindingController.java b/sdk/src/test/java/io/dapr/it/services/InputBindingController.java index 273f1fe37e..8036674854 100644 --- a/sdk/src/test/java/io/dapr/it/services/InputBindingController.java +++ b/sdk/src/test/java/io/dapr/it/services/InputBindingController.java @@ -24,9 +24,11 @@ public class InputBindingController { @PostMapping(path = "/sample123") public Mono handleInputBinding(@RequestBody(required = false) byte[] body) { - messagesReceived.add(body); - return Mono.fromRunnable(() -> - System.out.println("Received message through binding: " + (body == null ? "" : new String(body)))); + + return Mono.fromRunnable(() -> { + messagesReceived.add(body); + System.out.println("Received message through binding: " + (body == null ? "" : new String(body))); + }); } @GetMapping(path = "/messages")