From 7bfe9128d21bc6467058e10e914ec75a505cb802 Mon Sep 17 00:00:00 2001 From: "andres.robles" Date: Thu, 16 Jan 2020 13:37:45 -0600 Subject: [PATCH 1/4] Renaming State domain object. Removing duplicate use of State Options. Adding custom serialize and deserialize classes for StateOptions objects. --- .../main/java/io/dapr/client/DaprClient.java | 13 ++-- .../io/dapr/client/DaprClientGrpcAdapter.java | 25 ++++--- .../io/dapr/client/DaprClientHttpAdapter.java | 23 +++--- .../domain/{StateKeyValue.java => State.java} | 23 ++++-- .../io/dapr/client/domain/StateOptions.java | 66 +++++++++++++++++ .../client/DaprClientGrpcAdapterTest.java | 72 +++++++++---------- .../io/dapr/it/state/HttpStateClientIT.java | 62 ++++++++-------- 7 files changed, 179 insertions(+), 105 deletions(-) rename sdk/src/main/java/io/dapr/client/domain/{StateKeyValue.java => State.java} (77%) diff --git a/sdk/src/main/java/io/dapr/client/DaprClient.java b/sdk/src/main/java/io/dapr/client/DaprClient.java index b53a869d18..8c6fb07383 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClient.java +++ b/sdk/src/main/java/io/dapr/client/DaprClient.java @@ -4,7 +4,7 @@ */ package io.dapr.client; -import io.dapr.client.domain.StateKeyValue; +import io.dapr.client.domain.State; import io.dapr.client.domain.StateOptions; import io.dapr.client.domain.Verb; import reactor.core.publisher.Mono; @@ -116,27 +116,23 @@ public interface DaprClient { /** * Retrieve a State based on their key. - * * @param state The key of the State to be retrieved. - * @param stateOptions The options for the call to use. * @param clazz the Type of State needed as return. * @param the Type of the return. * @return A Mono Plan for the requested State. */ - Mono> getState(StateKeyValue state, StateOptions stateOptions, Class clazz); + Mono> getState(State state, Class clazz); /** * Save/Update a list of states. - * * @param states the States to be saved. * @param the Type of the State. * @return a Mono plan of type Void. */ - Mono saveStates(List> states); + Mono saveStates(List> states); /** * Save/Update a state. - * * @param key the key of the state. * @param etag the etag to be used. * @param value the value of the state. @@ -150,11 +146,10 @@ public interface DaprClient { * Delete a state. * * @param state The key of the State to be removed. - * @param options The options of the state. * @param The Type of the key of the State. * @return a Mono plan of type Void. */ - Mono deleteState(StateKeyValue state, StateOptions options); + Mono deleteState(State state); /** * Invokes an Actor method on Dapr. diff --git a/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java b/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java index 13326eeac5..4ef8a51179 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java @@ -11,7 +11,7 @@ import com.google.protobuf.Empty; import io.dapr.DaprGrpc; import io.dapr.DaprProtos; -import io.dapr.client.domain.StateKeyValue; +import io.dapr.client.domain.State; import io.dapr.client.domain.StateOptions; import io.dapr.client.domain.Verb; import io.dapr.utils.ObjectSerializer; @@ -159,12 +159,12 @@ public Mono invokeBinding(String name, T request) { * {@inheritDoc} */ @Override - public Mono> getState(StateKeyValue state, StateOptions stateOptions, Class clazz) { + public Mono> getState(State state, Class clazz) { try { DaprProtos.GetStateEnvelope.Builder builder = DaprProtos.GetStateEnvelope.newBuilder() .setKey(state.getKey()); - if (stateOptions != null && stateOptions.getConsistency() != null) { - builder.setConsistency(stateOptions.getConsistency().getValue()); + if (state.getOptions() != null && state.getOptions().getConsistency() != null) { + builder.setConsistency(state.getOptions().getConsistency().getValue()); } DaprProtos.GetStateEnvelope envelope = builder.build(); @@ -182,21 +182,21 @@ public Mono> getState(StateKeyValue state, StateOptions } } - private StateKeyValue buildStateKeyValue(DaprProtos.GetStateResponseEnvelope response, String requestedKey, StateOptions stateOptions, Class clazz) throws IOException { + private State 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); + return new State<>(value, key, etag, stateOptions); } /** * {@inheritDoc} */ @Override - public Mono saveStates(List> states) { + public Mono saveStates(List> states) { try { DaprProtos.SaveStateEnvelope.Builder builder = DaprProtos.SaveStateEnvelope.newBuilder(); - for (StateKeyValue state : states) { + for (State state : states) { builder.addRequests(buildStateRequest(state).build()); } DaprProtos.SaveStateEnvelope envelope = builder.build(); @@ -214,7 +214,7 @@ public Mono saveStates(List> states) { } } - private DaprProtos.StateRequest.Builder buildStateRequest(StateKeyValue state) throws IOException { + private DaprProtos.StateRequest.Builder buildStateRequest(State state) throws IOException { byte[] byteState = objectSerializer.serialize(state.getValue()); Any data = Any.newBuilder().setValue(ByteString.copyFrom(byteState)).build(); DaprProtos.StateRequest.Builder stateBuilder = DaprProtos.StateRequest.newBuilder() @@ -259,19 +259,18 @@ private DaprProtos.StateRequest.Builder buildStateRequest(StateKeyValue s @Override public Mono saveState(String key, String etag, T value, StateOptions options) { - StateKeyValue state = new StateKeyValue<>(value, key, etag, options); + State state = new State<>(value, key, etag, options); return saveStates(Arrays.asList(state)); } /** - * if stateOptions param is passed it will overrside state.options. * {@inheritDoc} */ @Override - public Mono deleteState(StateKeyValue state, StateOptions options) { + public Mono deleteState(State state) { try { DaprProtos.StateOptions.Builder optionBuilder = null; - + StateOptions options = state.getOptions(); if (options != null) { optionBuilder = DaprProtos.StateOptions.newBuilder(); DaprProtos.RetryPolicy.Builder retryPolicyBuilder = null; diff --git a/sdk/src/main/java/io/dapr/client/DaprClientHttpAdapter.java b/sdk/src/main/java/io/dapr/client/DaprClientHttpAdapter.java index 6a5b2840f8..c1377c49e5 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientHttpAdapter.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientHttpAdapter.java @@ -4,7 +4,7 @@ */ package io.dapr.client; -import io.dapr.client.domain.StateKeyValue; +import io.dapr.client.domain.State; import io.dapr.client.domain.StateOptions; import io.dapr.client.domain.Verb; import io.dapr.utils.Constants; @@ -12,7 +12,6 @@ import reactor.core.publisher.Mono; import java.io.IOException; -import java.lang.reflect.Field; import java.util.*; /** @@ -167,7 +166,7 @@ public Mono invokeBinding(String name, T request) { * {@inheritDoc} */ @Override - public Mono> getState(StateKeyValue state, StateOptions stateOptions, Class clazz) { + public Mono> getState(State state, Class clazz) { try { if (state.getKey() == null) { throw new IllegalArgumentException("Name cannot be null or empty."); @@ -180,12 +179,12 @@ public Mono> getState(StateKeyValue state, StateOptions StringBuilder url = new StringBuilder(Constants.STATE_PATH) .append("/") .append(state.getKey()); - Map urlParameters = Optional.ofNullable(stateOptions).map(options -> options.getStateOptionsAsMap() ).orElse( new HashMap<>());; + Map urlParameters = Optional.ofNullable(state.getOptions()).map(options -> options.getStateOptionsAsMap() ).orElse( new HashMap<>());; return this.client .invokeAPI(DaprHttp.HttpMethods.GET.name(), url.toString(), urlParameters, headers) .flatMap(s -> { try { - return Mono.just(buildStateKeyValue(s, state.getKey(), stateOptions, clazz)); + return Mono.just(buildStateKeyValue(s, state.getKey(), state.getOptions(), clazz)); }catch (Exception ex){ return Mono.error(ex); } @@ -199,14 +198,14 @@ public Mono> getState(StateKeyValue state, StateOptions * {@inheritDoc} */ @Override - public Mono saveStates(List> states) { + public Mono saveStates(List> states) { try { if (states == null || states.isEmpty()) { return Mono.empty(); } final Map headers = new HashMap<>(); final String etag = states.stream().filter(state -> null != state.getEtag() && !state.getEtag().trim().isEmpty()) - .findFirst().orElse(new StateKeyValue<>(null, null, null, null)).getEtag(); + .findFirst().orElse(new State<>(null, null, null, null)).getEtag(); if (etag != null && !etag.trim().isEmpty()) { headers.put(Constants.HEADER_HTTP_ETAG_ID, etag); } @@ -224,7 +223,7 @@ public Mono saveStates(List> states) { */ @Override public Mono saveState(String key, String etag, T value, StateOptions options) { - StateKeyValue state = new StateKeyValue<>(value, key, etag, options); + State state = new State<>(value, key, etag, options); return saveStates(Arrays.asList(state)); } @@ -232,7 +231,7 @@ public Mono saveState(String key, String etag, T value, StateOptions o * {@inheritDoc} */ @Override - public Mono deleteState(StateKeyValue state, StateOptions options) { + public Mono deleteState(State state) { try { if (state == null) { throw new IllegalArgumentException("State cannot be null."); @@ -245,7 +244,7 @@ public Mono deleteState(StateKeyValue state, StateOptions options) headers.put(Constants.HEADER_HTTP_ETAG_ID, state.getEtag()); } String url = Constants.STATE_PATH + "/" + state.getKey(); - Map urlParameters = Optional.ofNullable(options).map(stateOptions -> stateOptions.getStateOptionsAsMap() ).orElse( new HashMap<>());; + Map urlParameters = Optional.ofNullable(state.getOptions()).map(stateOptions -> stateOptions.getStateOptionsAsMap()).orElse( new HashMap<>());; return this.client.invokeAPI(DaprHttp.HttpMethods.DELETE.name(), url, urlParameters, headers).then(); } catch (Exception ex) { return Mono.error(ex); @@ -338,14 +337,14 @@ public Mono unregisterActorTimer(String actorType, String actorId, String * @return A StateKeyValue instance * @throws IOException If there's a issue deserialzing the response. */ - private StateKeyValue buildStateKeyValue(DaprHttp.Response resonse, String requestedKey, StateOptions stateOptions, Class clazz) throws IOException { + private State buildStateKeyValue(DaprHttp.Response resonse, String requestedKey, StateOptions stateOptions, Class clazz) throws IOException { T value = objectSerializer.deserialize(resonse.getBody(), clazz); String key = requestedKey; String etag = null; if (resonse.getHeaders() != null && resonse.getHeaders().containsKey("Etag")) { etag = objectSerializer.deserialize(resonse.getHeaders().get("Etag"), String.class); } - return new StateKeyValue<>(value, key, etag, stateOptions); + return new State<>(value, key, etag, stateOptions); } } diff --git a/sdk/src/main/java/io/dapr/client/domain/StateKeyValue.java b/sdk/src/main/java/io/dapr/client/domain/State.java similarity index 77% rename from sdk/src/main/java/io/dapr/client/domain/StateKeyValue.java rename to sdk/src/main/java/io/dapr/client/domain/State.java index d42eb1e5c4..e37da0af15 100644 --- a/sdk/src/main/java/io/dapr/client/domain/StateKeyValue.java +++ b/sdk/src/main/java/io/dapr/client/domain/State.java @@ -8,7 +8,7 @@ * This class reprent what a State is * @param The type of the value of the sate */ -public class StateKeyValue { +public class State { /** * The value of the state */ @@ -30,12 +30,27 @@ public class StateKeyValue { /** * Create an inmutable state + * This Constructor MUST be used anytime you need to retrieve or delete a State. + * @param key - The key of the state + * @param etag - The etag of the state - Keep in mind that for some state stores (like reids) only numbers are supported. + * @param options - REQUIRED when saving a state. + */ + public State(String key, String etag, StateOptions options) { + this.value = null; + this.key = key; + this.etag = etag; + this.options = options; + } + + /** + * Create an inmutable state + * This Constructor MUST be used anytime you want the state to be send for a Save operation. * @param value - The value of the state * @param key - The key of the state * @param etag - The etag of the state - Keep in mind that for some state stores (like reids) only numbers are supported. * @param options - REQUIRED when saving a state. */ - public StateKeyValue(T value, String key, String etag, StateOptions options) { + public State(T value, String key, String etag, StateOptions options) { this.value = value; this.key = key; this.etag = etag; @@ -77,9 +92,9 @@ public StateOptions getOptions() { @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof StateKeyValue)) return false; + if (!(o instanceof State)) return false; - StateKeyValue that = (StateKeyValue) o; + State that = (State) o; if (getValue() != null ? !getValue().equals(that.getValue()) : that.getValue() != null) return false; if (getKey() != null ? !getKey().equals(that.getKey()) : that.getKey() != null) return false; diff --git a/sdk/src/main/java/io/dapr/client/domain/StateOptions.java b/sdk/src/main/java/io/dapr/client/domain/StateOptions.java index 67938c3d12..f0c2736e61 100644 --- a/sdk/src/main/java/io/dapr/client/domain/StateOptions.java +++ b/sdk/src/main/java/io/dapr/client/domain/StateOptions.java @@ -4,9 +4,21 @@ */ package io.dapr.client.domain; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; import io.dapr.utils.DurationUtils; +import java.io.IOException; import java.time.Duration; import java.util.Collections; import java.util.HashMap; @@ -76,6 +88,10 @@ public String getValue() { return this.value; } + @JsonCreator + public static Consistency fromValue(String value) { + return Consistency.valueOf(value); + } } public static enum Concurrency { @@ -93,6 +109,10 @@ public String getValue() { return this.value; } + @JsonCreator + public static Concurrency fromValue(String value) { + return Concurrency.valueOf(value); + } } public static class RetryPolicy { @@ -106,11 +126,19 @@ private Pattern(String value) { this.value = value; } + @JsonValue public String getValue() { return this.value; } + + @JsonCreator + public static Pattern fromValue(String value) { + return Pattern.valueOf(value); + } } + @JsonSerialize(using = StateOptionDurationSerializer.class) + @JsonDeserialize(using = StateOptionDurationDeserializer.class) private final Duration interval; private final Integer threshold; private final Pattern pattern; @@ -133,6 +161,44 @@ public Integer getThreshold() { public Pattern getPattern() { return pattern; } + } + public static class StateOptionDurationSerializer extends StdSerializer { + public StateOptionDurationSerializer() { + this(Duration.class); + } + public StateOptionDurationSerializer(Class t) { + super(t); + } + + @Override + public void serialize(Duration duration, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { + String value = ""; + if (duration != null && !duration.isZero() && !duration.isNegative()) { + value = DurationUtils.ConvertDurationToDaprFormat(duration); + } + jsonGenerator.writeString(value); + } + } + + public static class StateOptionDurationDeserializer extends StdDeserializer { + public StateOptionDurationDeserializer(Class vc) { + super(vc); + } + + @Override + public Duration deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { + String durationStr = null; + durationStr = jsonParser.readValueAs(String.class); + Duration duration = null; + if (durationStr != null && !durationStr.trim().isEmpty()) { + try { + duration = DurationUtils.ConvertDurationFromDaprFormat(durationStr); + } catch (Exception ex) { + throw InvalidFormatException.from(jsonParser, "Unable to parse duration.", ex); + } + } + return duration; + } } } diff --git a/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java b/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java index e36d8442f2..78d1bc33a3 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java @@ -7,7 +7,7 @@ import com.google.protobuf.Empty; import io.dapr.DaprGrpc; import io.dapr.DaprProtos; -import io.dapr.client.domain.StateKeyValue; +import io.dapr.client.domain.State; import io.dapr.client.domain.StateOptions; import io.dapr.client.domain.Verb; import io.dapr.utils.ObjectSerializer; @@ -468,8 +468,8 @@ public void invokeServiceNoRequestNoClassBodyObjectTest() throws Exception { @Test(expected = RuntimeException.class) public void getStateExceptionThrownTest() { when(client.getState(any(io.dapr.DaprProtos.GetStateEnvelope.class))).thenThrow(RuntimeException.class); - StateKeyValue key = buildStateKey(null, "Key1", "ETag1", null); - Mono> result = adater.getState(key, null, String.class); + State key = buildStateKey(null, "Key1", "ETag1", null); + Mono> result = adater.getState(key, String.class); result.block(); } @@ -482,8 +482,8 @@ public void getStateCallbackExceptionThrownTest() { addCallback(settableFuture, callback, directExecutor()); when(client.getState(any(io.dapr.DaprProtos.GetStateEnvelope.class))) .thenReturn(settableFuture); - StateKeyValue key = buildStateKey(null, "Key1", "ETag1", null); - Mono> result = adater.getState(key, null, String.class); + State key = buildStateKey(null, "Key1", "ETag1", null); + Mono> result = adater.getState(key, String.class); settableFuture.setException(ex); result.block(); } @@ -493,15 +493,15 @@ public void getStateStringValueNoOptionsTest() throws IOException { String etag = "ETag1"; String key = "key1"; String expectedValue = "Expected state"; - StateKeyValue expectedState = buildStateKey(expectedValue, key, etag, null); + State expectedState = buildStateKey(expectedValue, key, etag, null); DaprProtos.GetStateResponseEnvelope responseEnvelope = buildGetStateResponseEnvelope(expectedValue, etag); SettableFuture settableFuture = SettableFuture.create(); MockCallback callback = new MockCallback<>(responseEnvelope); addCallback(settableFuture, callback, directExecutor()); when(client.getState(any(io.dapr.DaprProtos.GetStateEnvelope.class))) .thenReturn(settableFuture); - StateKeyValue keyRequest = buildStateKey(null, key, etag, null); - Mono> result = adater.getState(keyRequest, null, String.class); + State keyRequest = buildStateKey(null, key, etag, null); + Mono> result = adater.getState(keyRequest, String.class); settableFuture.set(responseEnvelope); assertEquals(expectedState, result.block()); } @@ -513,18 +513,18 @@ public void getStateObjectValueWithOptionsTest() throws IOException { MyObject expectedValue = new MyObject(1, "The Value"); StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, StateOptions.Concurrency.FIRST_WRITE, Duration.ofDays(100), 1, StateOptions.RetryPolicy.Pattern.LINEAR); - StateKeyValue expectedState = buildStateKey(expectedValue, key, etag, options); + State expectedState = buildStateKey(expectedValue, key, etag, options); DaprProtos.GetStateResponseEnvelope responseEnvelope = DaprProtos.GetStateResponseEnvelope.newBuilder() .setData(getAny(expectedValue)) .setEtag(etag) .build(); - StateKeyValue keyRequest = buildStateKey(null, key, etag, options); + State keyRequest = buildStateKey(null, key, etag, options); SettableFuture settableFuture = SettableFuture.create(); MockCallback callback = new MockCallback<>(responseEnvelope); addCallback(settableFuture, callback, directExecutor()); when(client.getState(any(io.dapr.DaprProtos.GetStateEnvelope.class))) .thenReturn(settableFuture); - Mono> result = adater.getState(keyRequest, options, MyObject.class); + Mono> result = adater.getState(keyRequest, MyObject.class); settableFuture.set(responseEnvelope); assertEquals(expectedState, result.block()); } @@ -536,18 +536,18 @@ public void getStateObjectValueWithOptionsNoConcurrencyTest() throws IOException MyObject expectedValue = new MyObject(1, "The Value"); StateOptions options = new StateOptions(null, StateOptions.Concurrency.FIRST_WRITE, new StateOptions.RetryPolicy(Duration.ofDays(100), 1, StateOptions.RetryPolicy.Pattern.LINEAR)); - StateKeyValue expectedState = buildStateKey(expectedValue, key, etag, options); + State expectedState = buildStateKey(expectedValue, key, etag, options); DaprProtos.GetStateResponseEnvelope responseEnvelope = DaprProtos.GetStateResponseEnvelope.newBuilder() .setData(getAny(expectedValue)) .setEtag(etag) .build(); - StateKeyValue keyRequest = buildStateKey(null, key, etag, options); + State keyRequest = buildStateKey(null, key, etag, options); SettableFuture settableFuture = SettableFuture.create(); MockCallback callback = new MockCallback<>(responseEnvelope); addCallback(settableFuture, callback, directExecutor()); when(client.getState(any(io.dapr.DaprProtos.GetStateEnvelope.class))) .thenReturn(settableFuture); - Mono> result = adater.getState(keyRequest, options, MyObject.class); + Mono> result = adater.getState(keyRequest, MyObject.class); settableFuture.set(responseEnvelope); assertEquals(expectedState, result.block()); } @@ -555,8 +555,8 @@ public void getStateObjectValueWithOptionsNoConcurrencyTest() throws IOException @Test(expected = RuntimeException.class) public void deleteStateExceptionThrowTest() { when(client.deleteState(any(io.dapr.DaprProtos.DeleteStateEnvelope.class))).thenThrow(RuntimeException.class); - StateKeyValue key = buildStateKey(null, "Key1", "ETag1", null); - Mono result = adater.deleteState(key, null); + State key = buildStateKey(null, "Key1", "ETag1", null); + Mono result = adater.deleteState(key); result.block(); } @@ -569,8 +569,8 @@ public void deleteStateCallbackExcpetionThrownTest() { addCallback(settableFuture, callback, directExecutor()); when(client.deleteState(any(io.dapr.DaprProtos.DeleteStateEnvelope.class))) .thenReturn(settableFuture); - StateKeyValue key = buildStateKey(null, "Key1", "ETag1", null); - Mono result = adater.deleteState(key, null); + State key = buildStateKey(null, "Key1", "ETag1", null); + Mono result = adater.deleteState(key); settableFuture.setException(ex); result.block(); } @@ -584,8 +584,8 @@ public void deleteStateNoOptionsTest() { addCallback(settableFuture, callback, directExecutor()); when(client.deleteState(any(io.dapr.DaprProtos.DeleteStateEnvelope.class))) .thenReturn(settableFuture); - StateKeyValue stateKey = buildStateKey(null, key, etag, null); - Mono result = adater.deleteState(stateKey, null); + State stateKey = buildStateKey(null, key, etag, null); + Mono result = adater.deleteState(stateKey); settableFuture.set(Empty.newBuilder().build()); result.block(); assertTrue(callback.wasCalled); @@ -602,8 +602,8 @@ public void deleteStateTest() { addCallback(settableFuture, callback, directExecutor()); when(client.deleteState(any(io.dapr.DaprProtos.DeleteStateEnvelope.class))) .thenReturn(settableFuture); - StateKeyValue stateKey = buildStateKey(null, key, etag, options); - Mono result = adater.deleteState(stateKey, options); + State stateKey = buildStateKey(null, key, etag, options); + Mono result = adater.deleteState(stateKey); settableFuture.set(Empty.newBuilder().build()); result.block(); assertTrue(callback.wasCalled); @@ -620,8 +620,8 @@ public void deleteStateNoConsistencyTest() { addCallback(settableFuture, callback, directExecutor()); when(client.deleteState(any(io.dapr.DaprProtos.DeleteStateEnvelope.class))) .thenReturn(settableFuture); - StateKeyValue stateKey = buildStateKey(null, key, etag, options); - Mono result = adater.deleteState(stateKey, options); + State stateKey = buildStateKey(null, key, etag, options); + Mono result = adater.deleteState(stateKey); settableFuture.set(Empty.newBuilder().build()); result.block(); assertTrue(callback.wasCalled); @@ -638,8 +638,8 @@ public void deleteStateNoConcurrencyTest() { addCallback(settableFuture, callback, directExecutor()); when(client.deleteState(any(io.dapr.DaprProtos.DeleteStateEnvelope.class))) .thenReturn(settableFuture); - StateKeyValue stateKey = buildStateKey(null, key, etag, options); - Mono result = adater.deleteState(stateKey, options); + State stateKey = buildStateKey(null, key, etag, options); + Mono result = adater.deleteState(stateKey); settableFuture.set(Empty.newBuilder().build()); result.block(); assertTrue(callback.wasCalled); @@ -656,8 +656,8 @@ public void deleteStateNoRetryPolicyTest() { addCallback(settableFuture, callback, directExecutor()); when(client.deleteState(any(io.dapr.DaprProtos.DeleteStateEnvelope.class))) .thenReturn(settableFuture); - StateKeyValue stateKey = buildStateKey(null, key, etag, options); - Mono result = adater.deleteState(stateKey, options); + State stateKey = buildStateKey(null, key, etag, options); + Mono result = adater.deleteState(stateKey); settableFuture.set(Empty.newBuilder().build()); result.block(); assertTrue(callback.wasCalled); @@ -674,8 +674,8 @@ public void deleteStateRetryPolicyNoDurationTest() { addCallback(settableFuture, callback, directExecutor()); when(client.deleteState(any(io.dapr.DaprProtos.DeleteStateEnvelope.class))) .thenReturn(settableFuture); - StateKeyValue stateKey = buildStateKey(null, key, etag, options); - Mono result = adater.deleteState(stateKey, options); + State stateKey = buildStateKey(null, key, etag, options); + Mono result = adater.deleteState(stateKey); settableFuture.set(Empty.newBuilder().build()); result.block(); assertTrue(callback.wasCalled); @@ -692,8 +692,8 @@ public void deleteStateRetryPolicyNoThresholdTest() { addCallback(settableFuture, callback, directExecutor()); when(client.deleteState(any(io.dapr.DaprProtos.DeleteStateEnvelope.class))) .thenReturn(settableFuture); - StateKeyValue stateKey = buildStateKey(null, key, etag, options); - Mono result = adater.deleteState(stateKey, options); + State stateKey = buildStateKey(null, key, etag, options); + Mono result = adater.deleteState(stateKey); settableFuture.set(Empty.newBuilder().build()); result.block(); assertTrue(callback.wasCalled); @@ -710,8 +710,8 @@ public void deleteStateRetryPolicyNoPatternTest() { addCallback(settableFuture, callback, directExecutor()); when(client.deleteState(any(io.dapr.DaprProtos.DeleteStateEnvelope.class))) .thenReturn(settableFuture); - StateKeyValue stateKey = buildStateKey(null, key, etag, options); - Mono result = adater.deleteState(stateKey, options); + State stateKey = buildStateKey(null, key, etag, options); + Mono result = adater.deleteState(stateKey); settableFuture.set(Empty.newBuilder().build()); result.block(); assertTrue(callback.wasCalled); @@ -876,8 +876,8 @@ public void saveStateRetryPolicyNoPatternTest() { assertTrue(callback.wasCalled); } - private StateKeyValue buildStateKey(T value, String key, String etag, StateOptions options) { - return new StateKeyValue(value, key, etag, options); + private State buildStateKey(T value, String key, String etag, StateOptions options) { + return new State(value, key, etag, options); } /** diff --git a/sdk/src/test/java/io/dapr/it/state/HttpStateClientIT.java b/sdk/src/test/java/io/dapr/it/state/HttpStateClientIT.java index 2c6e3325bb..4af3b8f105 100644 --- a/sdk/src/test/java/io/dapr/it/state/HttpStateClientIT.java +++ b/sdk/src/test/java/io/dapr/it/state/HttpStateClientIT.java @@ -7,7 +7,7 @@ import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; -import io.dapr.client.domain.StateKeyValue; +import io.dapr.client.domain.State; import io.dapr.client.domain.StateOptions; import io.dapr.it.BaseIT; import io.dapr.it.services.EmptyService; @@ -53,10 +53,10 @@ public void saveAndGetState() { saveResponse.block(); //create of the deferred call to DAPR to get the state - Mono> response = daprClient.getState(new StateKeyValue(null, stateKey, null, null), null, MyData.class); + Mono> response = daprClient.getState(new State(stateKey, null, null), MyData.class); //retrieve the state - StateKeyValue myDataResponse = response.block(); + State myDataResponse = response.block(); //Assert that the response is the correct one Assert.assertNotNull(myDataResponse.getEtag()); @@ -93,9 +93,9 @@ public void saveUpdateAndGetState() { saveResponse.block(); //Create deferred action to retrieve the action - Mono> response = daprClient.getState(new StateKeyValue(null, stateKey, null, null), null, MyData.class); + Mono> response = daprClient.getState(new State(stateKey, null, null), MyData.class); //execute the retrieve of the state - StateKeyValue myDataResponse = response.block(); + State myDataResponse = response.block(); //review that the update was success action Assert.assertEquals("data in property A", myDataResponse.getValue().getPropertyA()); @@ -120,21 +120,21 @@ public void saveAndDeleteState() { saveResponse.block(); //Create deferred action to retrieve the state - Mono> response = daprClient.getState(new StateKeyValue(null, stateKey, null, null), null, MyData.class); + Mono> response = daprClient.getState(new State(stateKey, null, null), MyData.class); //execute the retrieve of the state - StateKeyValue myDataResponse = response.block(); + State myDataResponse = response.block(); //review that the state was saved correctly Assert.assertEquals("data in property A", myDataResponse.getValue().getPropertyA()); Assert.assertEquals("data in property B", myDataResponse.getValue().getPropertyB()); //create deferred action to delete the state - Mono deleteResponse = daprClient.deleteState(new StateKeyValue(null, stateKey, null, null), null); + Mono deleteResponse = daprClient.deleteState(new State(stateKey, null, null)); //execute the delete action deleteResponse.block(); //Create deferred action to retrieve the state - response = daprClient.getState(new StateKeyValue(null, stateKey, null, null), null, MyData.class); + response = daprClient.getState(new State(stateKey, null, null), MyData.class); //execute the retrieve of the state myDataResponse = response.block(); @@ -160,9 +160,9 @@ public void saveUpdateAndGetStateWithEtag() { saveResponse.block(); //Create deferred action to retrieve the state - Mono> response = daprClient.getState(new StateKeyValue(null, stateKey, null, null), null, MyData.class); + Mono> response = daprClient.getState(new State(stateKey, null, null), MyData.class); //execute the action for retrieve the state and the etag - StateKeyValue myDataResponse = response.block(); + State myDataResponse = response.block(); //review that the etag is not empty Assert.assertNotNull(myDataResponse.getEtag()); @@ -181,7 +181,7 @@ public void saveUpdateAndGetStateWithEtag() { saveResponse.block(); - response = daprClient.getState(new StateKeyValue(null, stateKey, null, null), null, MyData.class); + response = daprClient.getState(new State(stateKey, null, null), MyData.class); //retrive the data wihout any etag myDataResponse = response.block(); @@ -213,9 +213,9 @@ public void saveUpdateAndGetStateWithWrongEtag() { saveResponse.block(); //Create deferred action to retrieve the state - Mono> response = daprClient.getState(new StateKeyValue(null, stateKey, null, null), null, MyData.class); + Mono> response = daprClient.getState(new State(stateKey, null, null), MyData.class); //execute the action for retrieve the state and the etag - StateKeyValue myDataResponse = response.block(); + State myDataResponse = response.block(); //review that the etag is not empty Assert.assertNotNull(myDataResponse.getEtag()); @@ -234,7 +234,7 @@ public void saveUpdateAndGetStateWithWrongEtag() { saveResponse.block(); - response = daprClient.getState(new StateKeyValue(null, stateKey, null, null), null, MyData.class); + response = daprClient.getState(new State(stateKey, null, null), MyData.class); //retrive the data wihout any etag myDataResponse = response.block(); @@ -263,9 +263,9 @@ public void saveAndDeleteStateWithEtag() { saveResponse.block(); //Create deferred action to get the state with the etag - Mono> response = daprClient.getState(new StateKeyValue(null, stateKey, null, null), null, MyData.class); + Mono> response = daprClient.getState(new State(stateKey, null, null), MyData.class); //execute the get state - StateKeyValue myDataResponse = response.block(); + State myDataResponse = response.block(); Assert.assertNotNull(myDataResponse.getEtag()); Assert.assertNotNull(myDataResponse.getKey()); @@ -274,12 +274,12 @@ public void saveAndDeleteStateWithEtag() { Assert.assertEquals("data in property B", myDataResponse.getValue().getPropertyB()); //Create deferred action to delete an state sending the etag - Mono deleteResponse = daprClient.deleteState(new StateKeyValue(null, stateKey, myDataResponse.getEtag(), null), null); + Mono deleteResponse = daprClient.deleteState(new State(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 StateKeyValue(null, stateKey, null, null), null, MyData.class); + response = daprClient.getState(new State(stateKey, null, null), MyData.class); myDataResponse = response.block(); //Review that the response is null, because the state was deleted @@ -303,9 +303,9 @@ public void saveAndDeleteStateWithWrongEtag() { saveResponse.block(); //Create deferred action to get the state with the etag - Mono> response = daprClient.getState(new StateKeyValue(null, stateKey, null, null), null, MyData.class); + Mono> response = daprClient.getState(new State(stateKey, null, null), MyData.class); //execute the get state - StateKeyValue myDataResponse = response.block(); + State myDataResponse = response.block(); Assert.assertNotNull(myDataResponse.getEtag()); Assert.assertNotNull(myDataResponse.getKey()); @@ -314,12 +314,12 @@ public void saveAndDeleteStateWithWrongEtag() { Assert.assertEquals("data in property B", myDataResponse.getValue().getPropertyB()); //Create deferred action to delete an state sending the incorrect etag - Mono deleteResponse = daprClient.deleteState(new StateKeyValue(null, stateKey, "99999999999", null), null); + Mono deleteResponse = daprClient.deleteState(new State(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 StateKeyValue(null, stateKey, null, null), null, MyData.class); + response = daprClient.getState(new State(stateKey, null, null), MyData.class); myDataResponse = response.block(); //Review that the response is null, because the state was deleted @@ -347,9 +347,9 @@ public void saveUpdateAndGetStateWithEtagAndStateOptionsFirstWrite() { //crate deferred action to retrieve the state - Mono> response = daprClient.getState(new StateKeyValue(null, stateKey, null, stateOptions), stateOptions, MyData.class); + Mono> response = daprClient.getState(new State(stateKey, null, stateOptions), MyData.class); //execute the retrieve of the state using options - StateKeyValue myDataResponse = response.block(); + State myDataResponse = response.block(); Assert.assertNotNull(myDataResponse.getEtag()); Assert.assertNotNull(myDataResponse.getKey()); @@ -373,8 +373,8 @@ public void saveUpdateAndGetStateWithEtagAndStateOptionsFirstWrite() { //throws an exception, the state was already udpated saveResponse.block(); - response = daprClient.getState(new StateKeyValue(null, stateKey, null, null), stateOptions, MyData.class); - StateKeyValue myLastDataResponse = response.block(); + response = daprClient.getState(new State(stateKey, null, stateOptions), MyData.class); + State myLastDataResponse = response.block(); Assert.assertNotNull(myLastDataResponse.getEtag()); Assert.assertNotNull(myLastDataResponse.getKey()); @@ -405,9 +405,9 @@ public void saveUpdateAndGetStateWithEtagAndStateOptionsLastWrite() { //crate deferred action to retrieve the state - Mono> response = daprClient.getState(new StateKeyValue(null, stateKey, null, stateOptions), stateOptions, MyData.class); + Mono> response = daprClient.getState(new State(stateKey, null, stateOptions), MyData.class); //execute the retrieve of the state using options - StateKeyValue myDataResponse = response.block(); + State myDataResponse = response.block(); Assert.assertNotNull(myDataResponse.getEtag()); Assert.assertNotNull(myDataResponse.getKey()); @@ -431,8 +431,8 @@ public void saveUpdateAndGetStateWithEtagAndStateOptionsLastWrite() { //update the state without an error saveResponse.block(); - response = daprClient.getState(new StateKeyValue(null, stateKey, null, null), stateOptions, MyData.class); - StateKeyValue myLastDataResponse = response.block(); + response = daprClient.getState(new State(stateKey, null, stateOptions), MyData.class); + State myLastDataResponse = response.block(); Assert.assertNotNull(myLastDataResponse.getEtag()); Assert.assertNotNull(myLastDataResponse.getKey()); From 51db6ee76395c2f9186df382231b3a028a6b01ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Herrera=20de=20la=20Garza?= Date: Thu, 16 Jan 2020 15:06:34 -0600 Subject: [PATCH 2/4] #26 Refractor StateOptions to clean unused code --- .../io/dapr/client/domain/StateOptions.java | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/sdk/src/main/java/io/dapr/client/domain/StateOptions.java b/sdk/src/main/java/io/dapr/client/domain/StateOptions.java index f0c2736e61..7fc192358e 100644 --- a/sdk/src/main/java/io/dapr/client/domain/StateOptions.java +++ b/sdk/src/main/java/io/dapr/client/domain/StateOptions.java @@ -8,7 +8,6 @@ import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @@ -73,13 +72,13 @@ public Map getStateOptionsAsMap() { return Collections.unmodifiableMap(Optional.ofNullable(mapOptions).orElse(Collections.EMPTY_MAP)); } - public static enum Consistency { + public enum Consistency { EVENTUAL("eventual"), STRONG("strong"); private final String value; - private Consistency(String value) { + Consistency(String value) { this.value = value; } @@ -94,13 +93,13 @@ public static Consistency fromValue(String value) { } } - public static enum Concurrency { + public enum Concurrency { FIRST_WRITE("first-write"), LAST_WRITE ("last-write"); private final String value; - private Concurrency(String value) { + Concurrency(String value) { this.value = value; } @@ -116,13 +115,13 @@ public static Concurrency fromValue(String value) { } public static class RetryPolicy { - public static enum Pattern { + public enum Pattern { LINEAR("linear"), EXPONENTIAL("exponential"); private String value; - private Pattern(String value) { + Pattern(String value) { this.value = value; } @@ -164,9 +163,7 @@ public Pattern getPattern() { } public static class StateOptionDurationSerializer extends StdSerializer { - public StateOptionDurationSerializer() { - this(Duration.class); - } + public StateOptionDurationSerializer(Class t) { super(t); } @@ -187,9 +184,8 @@ public StateOptionDurationDeserializer(Class vc) { } @Override - public Duration deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { - String durationStr = null; - durationStr = jsonParser.readValueAs(String.class); + public Duration deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + String durationStr = jsonParser.readValueAs(String.class); Duration duration = null; if (durationStr != null && !durationStr.trim().isEmpty()) { try { From a5230d6dbd0561f50768eb24861bd276c1fdc822 Mon Sep 17 00:00:00 2001 From: "andres.robles" Date: Thu, 16 Jan 2020 17:37:04 -0600 Subject: [PATCH 3/4] Fixing merge issues. --- .../java/io/dapr/client/DaprClientGrpcAdapter.java | 2 +- .../io/dapr/client/DaprClientGrpcAdapterTest.java | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java b/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java index 4ef8a51179..15f88a9bf7 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(State state, Class clazz) { } catch (NullPointerException npe) { return null; } - return buildStateKeyValue(response, state.getKey(), stateOptions, clazz); + return buildStateKeyValue(response, state.getKey(), state.getOptions(), 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 78d1bc33a3..7cf087cdb6 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java @@ -906,30 +906,30 @@ public void getStateDeleteStateThenBlockDeleteThenBlockGet() throws Exception { String expectedValue1 = "Expected state 1"; String key2 = "key2"; String expectedValue2 = "Expected state 2"; - StateKeyValue expectedState1 = buildStateKey(expectedValue1, key1, etag, null); + State 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, null); - Mono> resultGet1 = adater.getState(keyRequest1, null, String.class); + State keyRequest1 = buildStateKey(null, key1, etag, null); + Mono> resultGet1 = adater.getState(keyRequest1, String.class); assertEquals(expectedState1, resultGet1.block()); - StateKeyValue keyRequest2 = buildStateKey(null, key2, etag, null); - Mono> resultGet2 = adater.getState(keyRequest2, null, String.class); + State keyRequest2 = buildStateKey(null, key2, etag, null); + Mono> resultGet2 = adater.getState(keyRequest2, 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); + Mono resultDelete = adater.deleteState(keyRequest2); 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(); + State state2 = resultGet2.block(); assertNull(state2); } From 49c2bb1a19f7aa4ebed74bb33eb89a0111c89c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Herrera=20de=20la=20Garza?= Date: Mon, 20 Jan 2020 13:33:00 -0600 Subject: [PATCH 4/4] #26 Add integration test for states using Retry policies --- .../io/dapr/client/DaprClientBuilder.java | 6 +- .../io/dapr/client/domain/StateOptions.java | 15 +-- .../io/dapr/it/state/HttpStateClientIT.java | 99 +++++++++++++++++++ 3 files changed, 113 insertions(+), 7 deletions(-) diff --git a/sdk/src/main/java/io/dapr/client/DaprClientBuilder.java b/sdk/src/main/java/io/dapr/client/DaprClientBuilder.java index d9d6368b3c..221f9e21b4 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientBuilder.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientBuilder.java @@ -10,6 +10,9 @@ import io.grpc.ManagedChannelBuilder; import okhttp3.OkHttpClient; +import java.time.Duration; +import java.time.temporal.TemporalUnit; + /** * A builder for the DaprClient, * Currently only and HTTP Client will be supported. @@ -84,7 +87,8 @@ private DaprClient buildDaprClientHttp() { if (this.daprHttClient == null) { synchronized (DaprClientBuilder.class) { if (this.daprHttClient == null) { - OkHttpClient okHttpClient = new OkHttpClient.Builder().build(); + OkHttpClient okHttpClient = new OkHttpClient.Builder().callTimeout(Duration.ofSeconds(60)) + .build(); DaprHttp daprHtt = new DaprHttp(port, okHttpClient); this.daprHttClient = new DaprClientHttpAdapter(daprHtt); } diff --git a/sdk/src/main/java/io/dapr/client/domain/StateOptions.java b/sdk/src/main/java/io/dapr/client/domain/StateOptions.java index 7fc192358e..cd31cc7d79 100644 --- a/sdk/src/main/java/io/dapr/client/domain/StateOptions.java +++ b/sdk/src/main/java/io/dapr/client/domain/StateOptions.java @@ -5,6 +5,7 @@ package io.dapr.client.domain; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; @@ -19,6 +20,7 @@ import java.io.IOException; import java.time.Duration; +import java.time.temporal.TemporalUnit; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -47,6 +49,7 @@ public RetryPolicy getRetryPolicy() { return retryPolicy; } + @JsonIgnore public Map getStateOptionsAsMap() { Map mapOptions = null; if (this != null) { @@ -59,7 +62,7 @@ public Map getStateOptionsAsMap() { } if (this.getRetryPolicy() != null) { if (this.getRetryPolicy().getInterval() != null) { - mapOptions.put("retryInterval", DurationUtils.ConvertDurationToDaprFormat(this.getRetryPolicy().getInterval())); + mapOptions.put("retryInterval", String.valueOf(this.getRetryPolicy().getInterval().toMillis())); } if (this.getRetryPolicy().getThreshold() != null) { mapOptions.put("retryThreshold", this.getRetryPolicy().getThreshold().toString()); @@ -164,17 +167,17 @@ public Pattern getPattern() { public static class StateOptionDurationSerializer extends StdSerializer { + public StateOptionDurationSerializer() { + + super(Duration.class); + } public StateOptionDurationSerializer(Class t) { super(t); } @Override public void serialize(Duration duration, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { - String value = ""; - if (duration != null && !duration.isZero() && !duration.isNegative()) { - value = DurationUtils.ConvertDurationToDaprFormat(duration); - } - jsonGenerator.writeString(value); + jsonGenerator.writeNumber(duration.toMillis()); } } diff --git a/sdk/src/test/java/io/dapr/it/state/HttpStateClientIT.java b/sdk/src/test/java/io/dapr/it/state/HttpStateClientIT.java index 4af3b8f105..ccf23f200d 100644 --- a/sdk/src/test/java/io/dapr/it/state/HttpStateClientIT.java +++ b/sdk/src/test/java/io/dapr/it/state/HttpStateClientIT.java @@ -13,9 +13,12 @@ import io.dapr.it.services.EmptyService; import org.junit.Assert; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import reactor.core.publisher.Mono; +import java.time.Duration; + /** * Test State HTTP DAPR capabilities using a DAPR instance with an empty service running */ @@ -442,4 +445,100 @@ public void saveUpdateAndGetStateWithEtagAndStateOptionsLastWrite() { Assert.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 DAPR client + DaprClient daprClient = new DaprClientBuilder().build(); + //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 + Assert.assertNotNull(myDataResponse.getEtag()); + Assert.assertNotNull(myDataResponse.getKey()); + Assert.assertNotNull(myDataResponse.getValue()); + Assert.assertEquals("data in property A", myDataResponse.getValue().getPropertyA()); + Assert.assertEquals("data in property B", myDataResponse.getValue().getPropertyB()); + + + Mono deleteResponse = daprClient.deleteState(new State(stateKey, "99999999", stateOptions)); + + long start = System.currentTimeMillis(); + try { + //delete action + deleteResponse.block(); + }catch(RuntimeException ex){ + Assert.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; + Assert.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.EXPONENTIAL); + StateOptions stateOptions = new StateOptions(null, null, retryPolicy); + + //create DAPR client + DaprClient daprClient = new DaprClientBuilder().build(); + //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 + Assert.assertNotNull(myDataResponse.getEtag()); + Assert.assertNotNull(myDataResponse.getKey()); + Assert.assertNotNull(myDataResponse.getValue()); + Assert.assertEquals("data in property A", myDataResponse.getValue().getPropertyA()); + Assert.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){ + Assert.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; + Assert.assertTrue(elapsedTime>9000 && elapsedTime<9200); + + } + }