From 1a0debd4a4244bfeee451d9fce636f6bd312bd1d Mon Sep 17 00:00:00 2001 From: "andres.robles" Date: Wed, 15 Jan 2020 14:24:52 -0600 Subject: [PATCH 1/6] Fixing bug, where call should be deferred instead of async --- .../io/dapr/client/DaprClientGrpcAdapter.java | 69 +++++++------------ .../main/java/io/dapr/client/DaprHttp.java | 4 +- 2 files changed, 28 insertions(+), 45 deletions(-) diff --git a/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java b/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java index 8e2d27a99e..a4eef4c2ad 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java @@ -71,14 +71,11 @@ public Mono publishEvent(String topic, T event, Map me DaprProtos.PublishEventEnvelope envelope = DaprProtos.PublishEventEnvelope.newBuilder() .setTopic(topic).setData(data).build(); - ListenableFuture futureEmpty = client.publishEvent(envelope); - return Mono.just(futureEmpty).flatMap(f -> { - try { - f.get(); - } catch (Exception ex) { - return Mono.error(ex); - } - return Mono.empty(); + + return Mono.fromCallable(() -> { + ListenableFuture futureEmpty = client.publishEvent(envelope); + futureEmpty.get(); + return null; }); } catch (Exception ex) { return Mono.error(ex); @@ -92,16 +89,11 @@ public Mono publishEvent(String topic, T event, Map me public Mono invokeService(Verb verb, String appId, String method, R request, Map metadata, Class clazz) { try { DaprProtos.InvokeServiceEnvelope envelope = buildInvokeServiceEnvelope(verb.toString(), appId, method, request); - ListenableFuture futureResponse = - client.invokeService(envelope); - return Mono.just(futureResponse).flatMap(f -> { - try { - return Mono.just(objectSerializer.deserialize(f.get().getData().getValue().toByteArray(), clazz)); - } catch (Exception ex) { - return Mono.error(ex); - } + return Mono.fromCallable(() -> { + ListenableFuture futureResponse = + client.invokeService(envelope); + return objectSerializer.deserialize(futureResponse.get().getData().getValue().toByteArray(), clazz); }); - } catch (Exception ex) { return Mono.error(ex); } @@ -151,14 +143,10 @@ public Mono invokeBinding(String name, T request) { .setName(name) .setData(data); DaprProtos.InvokeBindingEnvelope envelope = builder.build(); - ListenableFuture futureEmpty = client.invokeBinding(envelope); - return Mono.just(futureEmpty).flatMap(f -> { - try { - f.get(); - } catch (Exception ex) { - return Mono.error(ex); - } - return Mono.empty(); + return Mono.fromCallable(() -> { + ListenableFuture futureEmpty = client.invokeBinding(envelope); + futureEmpty.get(); + return null; }); } catch (Exception ex) { return Mono.error(ex); @@ -167,7 +155,7 @@ public Mono invokeBinding(String name, T request) { /** * @return Returns an io.dapr.client.domain.StateKeyValue - * + *

* {@inheritDoc} */ @Override @@ -180,14 +168,9 @@ public Mono> getState(StateKeyValue state, StateOptions } DaprProtos.GetStateEnvelope envelope = builder.build(); - ListenableFuture futureResponse = client.getState(envelope); - return Mono.just(futureResponse).flatMap(f -> { - try { - return Mono.just(buildStateKeyValue(f.get(), state.getKey(), stateOptions, clazz)); - } catch (Exception ex) { - return Mono.error(ex); - } - }); + return Mono.fromCallable(() -> { + ListenableFuture futureResponse = client.getState(envelope); + return buildStateKeyValue(futureResponse.get(), state.getKey(), clazz); }); } catch (Exception ex) { return Mono.error(ex); } @@ -208,8 +191,7 @@ public Mono saveStates(List> states) { try { DaprProtos.SaveStateEnvelope.Builder builder = DaprProtos.SaveStateEnvelope.newBuilder(); for (StateKeyValue state : states) { - builder.addRequests(buildStateRequest(state).build()); - } + builder.addRequests(buildStateRequest(state).build()); } DaprProtos.SaveStateEnvelope envelope = builder.build(); ListenableFuture futureEmpty = client.saveState(envelope); @@ -282,7 +264,7 @@ public Mono saveState(String key, String etag, T value, StateOptions o @Override public Mono deleteState(StateKeyValue state, StateOptions options) { try { - DaprProtos.StateOptions.Builder optionBuilder = null; + DaprProtos.StateOptions.Builder optionBuilder = null; if (options != null) { optionBuilder = DaprProtos.StateOptions.newBuilder(); @@ -407,12 +389,13 @@ public Mono unregisterActorTimer(String actorType, String actorId, String /** * Builds the object io.dapr.{@link DaprProtos.InvokeServiceEnvelope} to be send based on the parameters. - * @param verb String that must match HTTP Methods - * @param appId The application id to be invoked - * @param method The application method to be invoked - * @param request The body of the request to be send as part of the invokation - * @param The Type of the Body - * @return The object to be sent as part of the invokation. + * + * @param verb String that must match HTTP Methods + * @param appId The application id to be invoked + * @param method The application method to be invoked + * @param request The body of the request to be send as part of the invokation + * @param The Type of the Body + * @return The object to be sent as part of the invokation. * @throws IOException If there's an issue serializing the request. */ private DaprProtos.InvokeServiceEnvelope buildInvokeServiceEnvelope( diff --git a/sdk/src/main/java/io/dapr/client/DaprHttp.java b/sdk/src/main/java/io/dapr/client/DaprHttp.java index 82736f64f0..64a48a5712 100644 --- a/sdk/src/main/java/io/dapr/client/DaprHttp.java +++ b/sdk/src/main/java/io/dapr/client/DaprHttp.java @@ -132,7 +132,7 @@ public Mono invokeAPI(String method, String urlString, Map invokeAPI(String method, String urlString, Map urlParameters, byte[] content, Map headers) { - return Mono.fromFuture(CompletableFuture.supplyAsync( + return Mono.fromCallable( () -> { try { String requestId = UUID.randomUUID().toString(); @@ -190,7 +190,7 @@ public Mono invokeAPI(String method, String urlString, Map Date: Wed, 15 Jan 2020 15:44:38 -0600 Subject: [PATCH 2/6] Removing unused pool property Returning null as response body if empty response is found. Adding Test case for validating callback is executed when expected. --- .../main/java/io/dapr/client/DaprHttp.java | 8 +--- .../java/io/dapr/client/DaprHttpTest.java | 42 +++++++++++++++++-- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/sdk/src/main/java/io/dapr/client/DaprHttp.java b/sdk/src/main/java/io/dapr/client/DaprHttp.java index 64a48a5712..aa49a743cf 100644 --- a/sdk/src/main/java/io/dapr/client/DaprHttp.java +++ b/sdk/src/main/java/io/dapr/client/DaprHttp.java @@ -83,11 +83,6 @@ public int getStatusCode() { */ private final OkHttpClient httpClient; - /** - * Thread-pool for HTTP calls. - */ - private final ExecutorService pool; - /** * Creates a new instance of {@link DaprHttp}. * @@ -97,7 +92,6 @@ public int getStatusCode() { DaprHttp(int port, OkHttpClient httpClient) { this.port = port; this.httpClient = httpClient; - this.pool = Executors.newWorkStealingPool(); } /** @@ -185,7 +179,7 @@ public Mono invokeAPI(String method, String urlString, Map { mapHeaders.put(pair.getFirst(), pair.getSecond()); }); - return new Response(result, mapHeaders, response.code()); + return new Response(result.length > 0 ? result : null, mapHeaders, response.code()); } } catch (Exception e) { throw new RuntimeException(e); diff --git a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java index 041c08a11e..dc94103e09 100644 --- a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java @@ -4,6 +4,8 @@ */ package io.dapr.client; +import io.dapr.exceptions.DaprException; +import io.dapr.utils.Constants; import io.dapr.utils.ObjectSerializer; import okhttp3.*; import okhttp3.mock.Behavior; @@ -16,7 +18,7 @@ import java.util.HashMap; import java.util.Map; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; public class DaprHttpTest { @@ -177,16 +179,48 @@ public void invokePostMethodUnknownError() throws IOException { @Test public void getHeadersAndStatus(){ - mockInterceptor.addRule() .post("http://localhost:3500/v1.0/state") .respond(500, ResponseBody.create(MediaType.parse("application/json"), "{\"errorCode\":\"null\",\"message\":\"null\"}")); - DaprHttp daprHttp = new DaprHttp(3500, okHttpClient); - System.out.println(daprHttp); + } + @Test () + public void testCallbackCalledAtTheExpectedTimeTest() throws IOException { + String deletedStateKey = "deletedKey"; + String existingState = "existingState"; + String urlDeleteState = Constants.STATE_PATH + "/" + deletedStateKey; + String urlExistingState = Constants.STATE_PATH + "/" + existingState; + mockInterceptor.addRule() + .get("http://localhost:3500/" + urlDeleteState) + .respond(200, ResponseBody.create(MediaType.parse("application/json"), + deletedStateKey)); + mockInterceptor.addRule() + .delete("http://localhost:3500/" + urlDeleteState) + .respond(204); + mockInterceptor.addRule() + .get("http://localhost:3500/" +urlExistingState) + .respond(200, ResponseBody.create(MediaType.parse("application/json"), + existingState)); + DaprHttp daprHttp = new DaprHttp(3500, okHttpClient); + Mono response = daprHttp.invokeAPI("GET", urlExistingState, null, null); + assertEquals(existingState, serializer.deserialize(response.block().getBody(), String.class)); + Mono responseDeleted = daprHttp.invokeAPI("GET", urlDeleteState, null, null); + Mono responseDeleteKey = daprHttp.invokeAPI("DELETE", urlDeleteState, null, null); + assertEquals("", serializer.deserialize(responseDeleteKey.block().getBody(), String.class)); + mockInterceptor.reset(); + mockInterceptor.addRule() + .get("http://localhost:3500/" +urlDeleteState) + .respond(404, ResponseBody.create(MediaType.parse("application/json"), + "{\"errorCode\":\"404\",\"message\":\"State Not Fuund\"}")); + try { + responseDeleted.block(); + fail("Expected DaprException"); + } catch (Exception ex) { + assertEquals(DaprException.class, ex.getCause().getCause().getClass()); + } } } From 4da1c9430a484771817a4fbdf9cfdd09c31ccbb1 Mon Sep 17 00:00:00 2001 From: "andres.robles" Date: Wed, 15 Jan 2020 15:54:14 -0600 Subject: [PATCH 3/6] Fixing assertion based on previous changes --- sdk/src/test/java/io/dapr/client/DaprHttpTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java index dc94103e09..6b9452be18 100644 --- a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java @@ -209,7 +209,7 @@ public void testCallbackCalledAtTheExpectedTimeTest() throws IOException { assertEquals(existingState, serializer.deserialize(response.block().getBody(), String.class)); Mono responseDeleted = daprHttp.invokeAPI("GET", urlDeleteState, null, null); Mono responseDeleteKey = daprHttp.invokeAPI("DELETE", urlDeleteState, null, null); - assertEquals("", serializer.deserialize(responseDeleteKey.block().getBody(), String.class)); + assertNull(serializer.deserialize(responseDeleteKey.block().getBody(), String.class)); mockInterceptor.reset(); mockInterceptor.addRule() .get("http://localhost:3500/" +urlDeleteState) From 329fb3d3023d66a83a32f18e146a4af3498e6f21 Mon Sep 17 00:00:00 2001 From: "andres.robles" Date: Wed, 15 Jan 2020 19:06:05 -0600 Subject: [PATCH 4/6] Adding test case to verify that the call to grpc only happens when the requestor block the thread, instead of in parallel immediately after calling the methods in the adapter. Documenting complex test case --- .../io/dapr/client/DaprClientGrpcAdapter.java | 16 ++- .../client/DaprClientGrpcAdapterTest.java | 103 ++++++++++++++++-- .../java/io/dapr/client/DaprHttpTest.java | 13 +++ 3 files changed, 115 insertions(+), 17 deletions(-) diff --git a/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java b/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java index a4eef4c2ad..5f1adde32f 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java @@ -170,15 +170,21 @@ public Mono> getState(StateKeyValue state, StateOptions DaprProtos.GetStateEnvelope envelope = builder.build(); return Mono.fromCallable(() -> { ListenableFuture futureResponse = client.getState(envelope); - return buildStateKeyValue(futureResponse.get(), state.getKey(), clazz); }); - } catch (Exception ex) { + DaprProtos.GetStateResponseEnvelope response = null; + try { + response = futureResponse.get(); + } catch (NullPointerException npe) { + return null; + } + return buildStateKeyValue(response, state.getKey(), clazz); + }); } catch (Exception ex) { return Mono.error(ex); } } - private StateKeyValue buildStateKeyValue(DaprProtos.GetStateResponseEnvelope resonse, String requestedKey, StateOptions stateOptions, Class clazz) throws IOException { - T value = objectSerializer.deserialize(resonse.getData().getValue().toByteArray(), clazz); - String etag = resonse.getEtag(); + private StateKeyValue buildStateKeyValue(DaprProtos.GetStateResponseEnvelope response, String requestedKey, StateOptions stateOptions, Class clazz) throws IOException { + T value = objectSerializer.deserialize(Optional.ofNullable(response.getData().getValue().toByteArray()).orElse(null), clazz); + String etag = response.getEtag(); String key = requestedKey; return new StateKeyValue<>(value, key, etag, stateOptions); } diff --git a/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java b/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java index dd83cb318b..e0728844d5 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java @@ -14,12 +14,15 @@ import org.checkerframework.checker.nullness.compatqual.NullableDecl; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentMatcher; import reactor.core.publisher.Mono; import javax.annotation.Nullable; import java.io.IOException; import java.time.Duration; +import java.util.HashMap; +import java.util.Map; import static com.google.common.util.concurrent.Futures.addCallback; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; @@ -42,13 +45,13 @@ public void setup() { @Test(expected = UnsupportedOperationException.class) public void unregisterActorTimerTest() { - Mono result = adater.unregisterActorTimer("actorType", "actorId", "timerName"); + Mono result = adater.unregisterActorTimer("actorType", "actorId", "timerName"); result.block(); } @Test(expected = UnsupportedOperationException.class) public void registerActorTimerTest() { - Mono result = adater.registerActorTimer("actorType", "actorId", "timerName" , "DATA"); + Mono result = adater.registerActorTimer("actorType", "actorId", "timerName", "DATA"); result.block(); } @@ -273,7 +276,7 @@ public void invokeServiceTest() throws Exception { } @Test - public void invokeServiceObjectTest() throws Exception { + public void invokeServiceObjectTest() throws Exception { MyObject resultObj = new MyObject(1, "Value"); SettableFuture settableFuture = SettableFuture.create(); MockCallback callback = @@ -322,13 +325,13 @@ public void invokeServiceNoRequestBodyTest() throws Exception { settableFuture.set(DaprProtos.InvokeServiceResponseEnvelope.newBuilder().setData(getAny(expected)).build()); when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) .thenReturn(settableFuture); - Mono result = adater.invokeService(Verb.GET, "appId", "method",null, String.class); + Mono result = adater.invokeService(Verb.GET, "appId", "method", null, String.class); String strOutput = result.block(); assertEquals(expected, strOutput); } @Test - public void invokeServiceNoRequestBodyObjectTest() throws Exception { + public void invokeServiceNoRequestBodyObjectTest() throws Exception { MyObject resultObj = new MyObject(1, "Value"); SettableFuture settableFuture = SettableFuture.create(); @@ -339,7 +342,7 @@ public void invokeServiceNoRequestBodyObjectTest() throws Exception { settableFuture.set(DaprProtos.InvokeServiceResponseEnvelope.newBuilder().setData(getAny(resultObj)).build()); when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) .thenReturn(settableFuture); - Mono result = adater.invokeService(Verb.GET, "appId", "method",null, String.class); + Mono result = adater.invokeService(Verb.GET, "appId", "method", null, String.class); String strOutput = result.block(); assertEquals(serializer.serializeString(resultObj), strOutput); } @@ -390,7 +393,7 @@ public void invokeByteRequestServiceTest() throws Exception { } @Test - public void invokeServiceByteRequestObjectTest() throws Exception { + public void invokeServiceByteRequestObjectTest() throws Exception { MyObject resultObj = new MyObject(1, "Value"); SettableFuture settableFuture = SettableFuture.create(); MockCallback callback = @@ -446,7 +449,7 @@ public void invokeServiceNoRequestNoClassBodyTest() throws Exception { } @Test - public void invokeServiceNoRequestNoClassBodyObjectTest() throws Exception { + public void invokeServiceNoRequestNoClassBodyObjectTest() throws Exception { MyObject resultObj = new MyObject(1, "Value"); SettableFuture settableFuture = SettableFuture.create(); @@ -491,10 +494,7 @@ public void getStateStringValueNoOptionsTest() throws IOException { String key = "key1"; String expectedValue = "Expected state"; StateKeyValue expectedState = buildStateKey(expectedValue, key, etag, null); - DaprProtos.GetStateResponseEnvelope responseEnvelope = DaprProtos.GetStateResponseEnvelope.newBuilder() - .setData(getAny(expectedValue)) - .setEtag(etag) - .build(); + DaprProtos.GetStateResponseEnvelope responseEnvelope = buildGetStateResponseEnvelope(expectedValue, etag); SettableFuture settableFuture = SettableFuture.create(); MockCallback callback = new MockCallback<>(responseEnvelope); addCallback(settableFuture, callback, directExecutor()); @@ -879,6 +879,57 @@ public void saveStateRetryPolicyNoPatternTest() { private StateKeyValue buildStateKey(T value, String key, String etag, StateOptions options) { return new StateKeyValue(value, key, etag, options); } + /** *

This test will execute the following flow:

+ *
    + *
  1. Exeucte client getState for Key=key1
  2. + *
  3. Block result to the the state
  4. + *
  5. Assert the Returned State is the expected to key1
  6. + *
  7. Execute client getState for Key=key2
  8. + *
  9. Execute client deleteState for Key=key2
  10. + *
  11. Block deleteState call.
  12. + *
  13. Block getState for Key=key2 and Assert they 2 was not found.
  14. + *
+ * @throws Exception + */ + @Test + public void getStateDeleteStateThenBlockDeleteThenBlockGet() throws Exception { + String etag = "ETag1"; + String key1 = "key1"; + String expectedValue1 = "Expected state 1"; + String key2 = "key2"; + String expectedValue2 = "Expected state 2"; + StateKeyValue expectedState1 = buildStateKey(expectedValue1, key1, etag); + Map> futuresMap = new HashMap<>(); + futuresMap.put(key1, buildFutureGetStateEnvelop(expectedValue1, etag)); + futuresMap.put(key2, buildFutureGetStateEnvelop(expectedValue2, etag)); + when(client.getState(argThat(new GetStateEnvelopeKeyMatcher(key1)))).thenReturn(futuresMap.get(key1)); + StateKeyValue keyRequest1 = buildStateKey(null, key1, etag); + Mono> resultGet1 = adater.getState(keyRequest1, null, String.class); + assertEquals(expectedState1, resultGet1.block()); + StateKeyValue keyRequest2 = buildStateKey(null, key2, etag); + Mono> resultGet2 = adater.getState(keyRequest2, null, String.class); + + SettableFuture settableFutureDelete = SettableFuture.create(); + MockCallback callbackDelete = new MockCallback<>(Empty.newBuilder().build()); + addCallback(settableFutureDelete, callbackDelete, directExecutor()); + when(client.deleteState(any(io.dapr.DaprProtos.DeleteStateEnvelope.class))) + .thenReturn(settableFutureDelete); + Mono resultDelete = adater.deleteState(keyRequest2, null); + settableFutureDelete.set(Empty.newBuilder().build()); + resultDelete.block(); + assertTrue(callbackDelete.wasCalled); + futuresMap.replace(key2, null); + when(client.getState(argThat(new GetStateEnvelopeKeyMatcher(key2)))).thenReturn(futuresMap.get(key2)); + + StateKeyValue state2 = resultGet2.block(); + assertNull(state2); + } + private DaprProtos.GetStateResponseEnvelope buildGetStateResponseEnvelope(T value, String etag) throws IOException { + return DaprProtos.GetStateResponseEnvelope.newBuilder() + .setData(getAny(value)) + .setEtag(etag) + .build(); + } private StateOptions buildStateOptions(StateOptions.Consistency consistency, StateOptions.Concurrency concurrency, Duration interval, Integer threshold, StateOptions.RetryPolicy.Pattern pattern) { @@ -977,4 +1028,32 @@ public int hashCode() { return result; } } + + private static class GetStateEnvelopeKeyMatcher implements ArgumentMatcher { + + private final String propValue; + + GetStateEnvelopeKeyMatcher(String propValue) { + this.propValue = propValue; + } + + @Override + public boolean matches(DaprProtos.GetStateEnvelope argument) { + if (argument == null) { + return false; + } + if (propValue == null && argument.getKey() != null) { + return false; + } + if (propValue == null && argument.getKey() == null) { + return true; + } + return propValue.equals(argument.getKey()); + } + + @Override + public String toString() { + return ""; + } + } } diff --git a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java index 6b9452be18..a4b5a546ea 100644 --- a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java @@ -187,6 +187,19 @@ public void getHeadersAndStatus(){ System.out.println(daprHttp); } + /** + *

This test will execute the following flow:

+ *
    + *
  1. Exeucte client getState for Key=key1
  2. + *
  3. Block result to the the state
  4. + *
  5. Assert the Returned State is the expected to key1
  6. + *
  7. Execute client getState for Key=key2
  8. + *
  9. Execute client deleteState for Key=key2
  10. + *
  11. Block deleteState call.
  12. + *
  13. Block getState for Key=key2 and Assert they 2 was not found.
  14. + *
+ * @throws Exception + */ @Test () public void testCallbackCalledAtTheExpectedTimeTest() throws IOException { String deletedStateKey = "deletedKey"; From 4dc4f3ccc3bd6243196ed395b690b6bc737cd1b5 Mon Sep 17 00:00:00 2001 From: "andres.robles" Date: Thu, 16 Jan 2020 14:45:20 -0600 Subject: [PATCH 5/6] Fixing merge conflicts --- .../io/dapr/client/DaprClientGrpcAdapter.java | 2 +- .../dapr/client/DaprClientGrpcAdapterTest.java | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java b/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java index 5f1adde32f..13326eeac5 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java @@ -176,7 +176,7 @@ public Mono> getState(StateKeyValue state, StateOptions } catch (NullPointerException npe) { return null; } - return buildStateKeyValue(response, state.getKey(), clazz); + return buildStateKeyValue(response, state.getKey(), stateOptions, clazz); }); } catch (Exception ex) { return Mono.error(ex); } diff --git a/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java b/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java index e0728844d5..1f5a3d27b7 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java @@ -898,15 +898,15 @@ public void getStateDeleteStateThenBlockDeleteThenBlockGet() throws Exception { String expectedValue1 = "Expected state 1"; String key2 = "key2"; String expectedValue2 = "Expected state 2"; - StateKeyValue expectedState1 = buildStateKey(expectedValue1, key1, etag); + StateKeyValue expectedState1 = buildStateKey(expectedValue1, key1, etag, null); Map> futuresMap = new HashMap<>(); futuresMap.put(key1, buildFutureGetStateEnvelop(expectedValue1, etag)); futuresMap.put(key2, buildFutureGetStateEnvelop(expectedValue2, etag)); when(client.getState(argThat(new GetStateEnvelopeKeyMatcher(key1)))).thenReturn(futuresMap.get(key1)); - StateKeyValue keyRequest1 = buildStateKey(null, key1, etag); + StateKeyValue keyRequest1 = buildStateKey(null, key1, etag, null); Mono> resultGet1 = adater.getState(keyRequest1, null, String.class); assertEquals(expectedState1, resultGet1.block()); - StateKeyValue keyRequest2 = buildStateKey(null, key2, etag); + StateKeyValue keyRequest2 = buildStateKey(null, key2, etag, null); Mono> resultGet2 = adater.getState(keyRequest2, null, String.class); SettableFuture settableFutureDelete = SettableFuture.create(); @@ -924,6 +924,17 @@ public void getStateDeleteStateThenBlockDeleteThenBlockGet() throws Exception { StateKeyValue state2 = resultGet2.block(); assertNull(state2); } + + private SettableFuture buildFutureGetStateEnvelop(T value, String etag) throws IOException { + DaprProtos.GetStateResponseEnvelope envelope = buildGetStateResponseEnvelope(value, etag); + SettableFuture settableFuture = SettableFuture.create(); + MockCallback callback = new MockCallback<>(envelope); + addCallback(settableFuture, callback, directExecutor()); + settableFuture.set(envelope); + + return settableFuture; + } + private DaprProtos.GetStateResponseEnvelope buildGetStateResponseEnvelope(T value, String etag) throws IOException { return DaprProtos.GetStateResponseEnvelope.newBuilder() .setData(getAny(value)) From d1b4585bcb327ebf5ecc6c2981089bf8b38fe78d Mon Sep 17 00:00:00 2001 From: "andres.robles" Date: Thu, 16 Jan 2020 15:53:28 -0600 Subject: [PATCH 6/6] Documenting complex test case --- .../dapr/client/DaprClientGrpcAdapterTest.java | 16 ++++++++++++---- .../test/java/io/dapr/client/DaprHttpTest.java | 11 ++++++++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java b/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java index 1f5a3d27b7..e36d8442f2 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java @@ -879,18 +879,26 @@ public void saveStateRetryPolicyNoPatternTest() { private StateKeyValue buildStateKey(T value, String key, String etag, StateOptions options) { return new StateKeyValue(value, key, etag, options); } - /** *

This test will execute the following flow:

+ + /** + * The purpose of this test is to show that it doesn't matter when the client is called, the actual coll to DAPR + * will be done when the output Mono response call the Mono.block method. + * Like for instanche if you call getState, withouth blocking for the response, and then call delete for the same state + * you just retrived but block for the delete response, when later you block for the response of the getState, you will + * not found the state. + *

This test will execute the following flow:

*
    *
  1. Exeucte client getState for Key=key1
  2. - *
  3. Block result to the the state
  4. + *
  5. Block for result to the the state
  6. *
  7. Assert the Returned State is the expected to key1
  8. *
  9. Execute client getState for Key=key2
  10. *
  11. Execute client deleteState for Key=key2
  12. - *
  13. Block deleteState call.
  14. - *
  15. Block getState for Key=key2 and Assert they 2 was not found.
  16. + *
  17. Block for deleteState call.
  18. + *
  19. Block for getState for Key=key2 and Assert they 2 was not found.
  20. *
* @throws Exception */ + @Test public void getStateDeleteStateThenBlockDeleteThenBlockGet() throws Exception { String etag = "ETag1"; diff --git a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java index a4b5a546ea..5b2a7d3235 100644 --- a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java @@ -188,15 +188,20 @@ public void getHeadersAndStatus(){ } /** + * The purpose of this test is to show that it doesn't matter when the client is called, the actual coll to DAPR + * will be done when the output Mono response call the Mono.block method. + * Like for instanche if you call getState, withouth blocking for the response, and then call delete for the same state + * you just retrived but block for the delete response, when later you block for the response of the getState, you will + * not found the state. *

This test will execute the following flow:

*
    *
  1. Exeucte client getState for Key=key1
  2. - *
  3. Block result to the the state
  4. + *
  5. Block for result to the the state
  6. *
  7. Assert the Returned State is the expected to key1
  8. *
  9. Execute client getState for Key=key2
  10. *
  11. Execute client deleteState for Key=key2
  12. - *
  13. Block deleteState call.
  14. - *
  15. Block getState for Key=key2 and Assert they 2 was not found.
  16. + *
  17. Block for deleteState call.
  18. + *
  19. Block for getState for Key=key2 and Assert they 2 was not found.
  20. *
* @throws Exception */