diff --git a/sdk-actors/src/main/java/io/dapr/actors/runtime/ActorStateSerializer.java b/sdk-actors/src/main/java/io/dapr/actors/runtime/ActorStateSerializer.java index 7cf165717..38cb87e2b 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/runtime/ActorStateSerializer.java +++ b/sdk-actors/src/main/java/io/dapr/actors/runtime/ActorStateSerializer.java @@ -6,6 +6,7 @@ package io.dapr.actors.runtime; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonNode; +import io.dapr.utils.DurationUtils; import io.dapr.utils.ObjectSerializer; import java.io.IOException; diff --git a/sdk-actors/src/main/java/io/dapr/actors/runtime/DurationUtils.java b/sdk-actors/src/main/java/io/dapr/actors/runtime/DurationUtils.java deleted file mode 100644 index f09a19573..000000000 --- a/sdk-actors/src/main/java/io/dapr/actors/runtime/DurationUtils.java +++ /dev/null @@ -1,142 +0,0 @@ -// ------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -// ------------------------------------------------------------ - -package io.dapr.actors.runtime; - -import java.time.Duration; - -public class DurationUtils { - - /** - * Converts time from the String format used by Dapr into a Duration. - * - * @param valueString A String representing time in the Dapr runtime's format (e.g. 4h15m50s60ms). - * @return A Duration - */ - public static Duration ConvertDurationFromDaprFormat(String valueString) { - // Convert the format returned by the Dapr runtime into Duration - // An example of the format is: 4h15m50s60ms. It does not include days. - int hIndex = valueString.indexOf('h'); - int mIndex = valueString.indexOf('m'); - int sIndex = valueString.indexOf('s'); - int msIndex = valueString.indexOf("ms"); - - String hoursSpan = valueString.substring(0, hIndex); - - int hours = Integer.parseInt(hoursSpan); - int days = hours / 24; - hours = hours % 24; - - String minutesSpan = valueString.substring(hIndex + 1, mIndex); - int minutes = Integer.parseInt(minutesSpan); - - String secondsSpan = valueString.substring(mIndex + 1, sIndex); - int seconds = Integer.parseInt(secondsSpan); - - String millisecondsSpan = valueString.substring(sIndex + 1, msIndex); - int milliseconds = Integer.parseInt(millisecondsSpan); - - return Duration.ZERO - .plusDays(days) - .plusHours(hours) - .plusMinutes(minutes) - .plusSeconds(seconds) - .plusMillis(milliseconds); - } - - /** - * Converts a Duration to the format used by the Dapr runtime. - * - * @param value Duration - * @return The Duration formatted as a String in the format the Dapr runtime uses (e.g. 4h15m50s60ms) - */ - public static String ConvertDurationToDaprFormat(Duration value) { - String stringValue = ""; - - // return empty string for anything negative, it'll only happen for reminder "periods", not dueTimes. A - // negative "period" means fire once only. - if (value == Duration.ZERO || - (value.compareTo(Duration.ZERO) == 1)) { - long hours = getDaysPart(value) * 24 + getHoursPart(value); - - StringBuilder sb = new StringBuilder(); - - sb.append(hours); - sb.append("h"); - - sb.append(getMinutesPart((value))); - sb.append("m"); - - sb.append(getSecondsPart((value))); - sb.append("s"); - - sb.append(getMilliSecondsPart((value))); - sb.append("ms"); - - return sb.toString(); - } - - return stringValue; - } - - /** - * Helper to get the "days" part of the Duration. For example if the duration is 26 hours, this returns 1. - * - * @param d Duration - * @return Number of days. - */ - static long getDaysPart(Duration d) { - long t = d.getSeconds() / 60 / 60 / 24; - return t; - } - - /** - * Helper to get the "hours" part of the Duration. For example if the duration is 26 hours, this is 1 day, 2 hours, so this returns 2. - * - * @param d The duration to parse - * @return the hour part of the duration - */ - static long getHoursPart(Duration d) { - long u = (d.getSeconds() / 60 / 60) % 24; - - return u; - } - - /** - * Helper to get the "minutes" part of the Duration. - * - * @param d The duration to parse - * @return the minutes part of the duration - */ - static long getMinutesPart(Duration d) { - long u = (d.getSeconds() / 60) % 60; - - return u; - } - - /** - * Helper to get the "seconds" part of the Duration. - * - * @param d The duration to parse - * @return the seconds part of the duration - */ - static long getSecondsPart(Duration d) { - long u = d.getSeconds() % 60; - - return u; - } - - /** - * Helper to get the "millis" part of the Duration. - * - * @param d The duration to parse - * @return the milliseconds part of the duration - */ - static long getMilliSecondsPart(Duration d) { - long u = d.toMillis() % 1000; - - return u; - } -} diff --git a/sdk/src/main/java/io/dapr/client/DaprClient.java b/sdk/src/main/java/io/dapr/client/DaprClient.java index db3dd1fb3..2ab002af8 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClient.java +++ b/sdk/src/main/java/io/dapr/client/DaprClient.java @@ -118,13 +118,12 @@ public interface DaprClient { * Retrieve a State based on their key. * * @param state The key of the State to be retrieved. - * @param stateOptions + * @param stateOptions The options for the call to use. * @param clazz the Type of State needed as return. * @param the Type of the return. - * @param The Type of the key of the State. * @return A Mono Plan for the requested State. */ - Mono getState(StateKeyValue state, StateOptions stateOptions, Class clazz); + Mono> getState(StateKeyValue state, StateOptions stateOptions, Class clazz); /** * Save/Update a list of states. diff --git a/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java b/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java index a0eea0255..aa6885413 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientGrpcAdapter.java @@ -6,6 +6,8 @@ package io.dapr.client; import com.google.common.util.concurrent.ListenableFuture; import com.google.protobuf.Any; +import com.google.protobuf.ByteString; +import com.google.protobuf.Duration; import com.google.protobuf.Empty; import io.dapr.DaprGrpc; import io.dapr.DaprProtos; @@ -15,9 +17,8 @@ import io.dapr.client.domain.Verb; import io.dapr.utils.ObjectSerializer; import reactor.core.publisher.Mono; -import java.lang.reflect.Field; +import java.io.IOException; import java.util.*; -import java.util.concurrent.CompletableFuture; /** * An adapter for the GRPC Client. @@ -64,15 +65,12 @@ class DaprClientGrpcAdapter implements DaprClient { @Override public Mono publishEvent(String topic, T event, Map metadata) { try { - String serializedEvent = objectSerializer.serializeString(event); - Map mapEvent = new HashMap<>(); - mapEvent.put("Topic", topic); - mapEvent.put("Data", serializedEvent); + byte[] byteEvent = objectSerializer.serialize(event); + Any data = Any.newBuilder().setValue(ByteString.copyFrom(byteEvent)).build(); // TODO: handle metadata. - byte[] byteEvent = objectSerializer.serialize(mapEvent); - - DaprProtos.PublishEventEnvelope envelope = DaprProtos.PublishEventEnvelope.parseFrom(byteEvent); + DaprProtos.PublishEventEnvelope envelope = DaprProtos.PublishEventEnvelope.newBuilder() + .setTopic(topic).setData(data).build(); ListenableFuture futureEmpty = client.publishEvent(envelope); return Mono.just(futureEmpty).flatMap(f -> { try { @@ -93,18 +91,12 @@ class DaprClientGrpcAdapter implements DaprClient { @Override public Mono invokeService(Verb verb, String appId, String method, R request, Map metadata, Class clazz) { try { - DaprProtos.InvokeServiceEnvelope.Builder envelopeBuilder = DaprProtos.InvokeServiceEnvelope.newBuilder(); - envelopeBuilder.setId(appId); - envelopeBuilder.setMethod(verb.toString()); - envelopeBuilder.setData(Any.parseFrom(objectSerializer.serialize(request))); - envelopeBuilder.getMetadataMap().putAll(metadata); - - DaprProtos.InvokeServiceEnvelope envelope = envelopeBuilder.build(); + 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().toByteArray(), clazz)); + return Mono.just(objectSerializer.deserialize(f.get().getData().getValue().toByteArray(), clazz)); } catch (Exception ex) { return Mono.error(ex); } @@ -153,11 +145,12 @@ class DaprClientGrpcAdapter implements DaprClient { @Override public Mono invokeBinding(String name, T request) { try { - Map mapMessage = new HashMap<>(); - mapMessage.put("Name", name); - mapMessage.put("Data", objectSerializer.serializeString(request)); - DaprProtos.InvokeBindingEnvelope envelope = - DaprProtos.InvokeBindingEnvelope.parseFrom(objectSerializer.serialize(mapMessage)); + byte[] byteRequest = objectSerializer.serialize(request); + Any data = Any.newBuilder().setValue(ByteString.copyFrom(byteRequest)).build(); + DaprProtos.InvokeBindingEnvelope.Builder builder = DaprProtos.InvokeBindingEnvelope.newBuilder() + .setName(name) + .setData(data); + DaprProtos.InvokeBindingEnvelope envelope = builder.build(); ListenableFuture futureEmpty = client.invokeBinding(envelope); return Mono.just(futureEmpty).flatMap(f -> { try { @@ -173,20 +166,24 @@ class DaprClientGrpcAdapter implements DaprClient { } /** + * @return Returns an io.dapr.client.domain.StateKeyValue + * * {@inheritDoc} */ @Override - public Mono getState(StateKeyValue key, StateOptions stateOptions, Class clazz) { + public Mono> getState(StateKeyValue state, StateOptions stateOptions, Class clazz) { try { - Map request = new HashMap<>(); - request.put("Key", key.getKey()); - request.put("Consistency", stateOptions.getConsistency()); - byte[] serializedRequest = objectSerializer.serialize(request); - DaprProtos.GetStateEnvelope envelope = DaprProtos.GetStateEnvelope.parseFrom(serializedRequest); + DaprProtos.GetStateEnvelope.Builder builder = DaprProtos.GetStateEnvelope.newBuilder() + .setKey(state.getKey()); + if (stateOptions != null && stateOptions.getConsistency() != null) { + builder.setConsistency(stateOptions.getConsistency().getValue()); + } + + DaprProtos.GetStateEnvelope envelope = builder.build(); ListenableFuture futureResponse = client.getState(envelope); return Mono.just(futureResponse).flatMap(f -> { try { - return Mono.just(objectSerializer.deserialize(f.get().getData().getValue().toStringUtf8(), clazz)); + return Mono.just(buildStateKeyValue(f.get(), state.getKey(), clazz)); } catch (Exception ex) { return Mono.error(ex); } @@ -196,22 +193,64 @@ class DaprClientGrpcAdapter implements DaprClient { } } + private StateKeyValue buildStateKeyValue(DaprProtos.GetStateResponseEnvelope resonse, String requestedKey, Class clazz) throws IOException { + T value = objectSerializer.deserialize(resonse.getData().getValue().toByteArray(), clazz); + String etag = resonse.getEtag(); + String key = requestedKey; + + return new StateKeyValue<>(value, key, etag); + } + /** * {@inheritDoc} */ @Override public Mono saveStates(List> states, StateOptions options) { try { - List> listStates = new ArrayList<>(); - Map mapOptions = transformStateOptionsToMap(options); + DaprProtos.StateRequestOptions.Builder optionBuilder = null; + if (options != null) { + DaprProtos.StateRetryPolicy.Builder retryPolicyBuilder = null; + if (options.getRetryPolicy() != null) { + retryPolicyBuilder = DaprProtos.StateRetryPolicy.newBuilder(); + StateOptions.RetryPolicy retryPolicy = options.getRetryPolicy(); + if (options.getRetryPolicy().getInterval() != null) { + Duration.Builder durationBuilder = Duration.newBuilder() + .setNanos(retryPolicy.getInterval().getNano()) + .setSeconds(retryPolicy.getInterval().getSeconds()); + retryPolicyBuilder.setInterval(durationBuilder.build()); + } + retryPolicyBuilder.setThreshold(objectSerializer.deserialize(retryPolicy.getThreshold(), int.class)); + if (retryPolicy.getPattern() != null) { + retryPolicyBuilder.setPattern(retryPolicy.getPattern().getValue()); + } + } + + optionBuilder = DaprProtos.StateRequestOptions.newBuilder(); + if (options.getConcurrency() != null) { + optionBuilder.setConcurrency(options.getConcurrency().getValue()); + } + if (options.getConsistency() != null) { + optionBuilder.setConsistency(options.getConsistency().getValue()); + } + if (retryPolicyBuilder != null) { + optionBuilder.setRetryPolicy(retryPolicyBuilder.build()); + } + } + DaprProtos.SaveStateEnvelope.Builder builder = DaprProtos.SaveStateEnvelope.newBuilder(); for (StateKeyValue state : states) { - Map mapState = transformStateKeyValueToMap(state, mapOptions); - listStates.add(mapState); - }; - Map mapStates = new HashMap<>(); - mapStates.put("Requests", listStates); - byte[] byteRequests = objectSerializer.serialize(mapStates); - DaprProtos.SaveStateEnvelope envelope = DaprProtos.SaveStateEnvelope.parseFrom(byteRequests); + byte[] byteState = objectSerializer.serialize(state.getValue()); + Any data = Any.newBuilder().setValue(ByteString.copyFrom(byteState)).build(); + DaprProtos.StateRequest.Builder stateBuilder = DaprProtos.StateRequest.newBuilder() + .setEtag(state.getEtag()) + .setKey(state.getKey()) + .setValue(data); + if(optionBuilder != null) { + stateBuilder.setOptions(optionBuilder.build()); + } + builder.addRequests(stateBuilder.build()); + } + DaprProtos.SaveStateEnvelope envelope = builder.build(); + ListenableFuture futureEmpty = client.saveState(envelope); return Mono.just(futureEmpty).flatMap(f -> { try { @@ -226,9 +265,6 @@ class DaprClientGrpcAdapter implements DaprClient { } } - /** - * {@inheritDoc} - */ @Override public Mono saveState(String key, String etag, T value, StateOptions options) { StateKeyValue state = new StateKeyValue<>(value, key, etag); @@ -242,10 +278,45 @@ class DaprClientGrpcAdapter implements DaprClient { @Override public Mono deleteState(StateKeyValue state, StateOptions options) { try { - Map mapOptions = transformStateOptionsToMap(options); - Map mapState = transformStateKeyValueToMap(state, mapOptions); - byte[] serializedState = objectSerializer.serialize(mapState); - DaprProtos.DeleteStateEnvelope envelope = DaprProtos.DeleteStateEnvelope.parseFrom(serializedState); + DaprProtos.StateOptions.Builder optionBuilder = null; + + if (options != null) { + optionBuilder = DaprProtos.StateOptions.newBuilder(); + DaprProtos.RetryPolicy.Builder retryPolicyBuilder = null; + if (options.getRetryPolicy() != null) { + retryPolicyBuilder = DaprProtos.RetryPolicy.newBuilder(); + StateOptions.RetryPolicy retryPolicy = options.getRetryPolicy(); + if (options.getRetryPolicy().getInterval() != null) { + Duration.Builder durationBuilder = Duration.newBuilder() + .setNanos(retryPolicy.getInterval().getNano()) + .setSeconds(retryPolicy.getInterval().getSeconds()); + retryPolicyBuilder.setInterval(durationBuilder.build()); + } + retryPolicyBuilder.setThreshold(objectSerializer.deserialize(retryPolicy.getThreshold(), int.class)); + if (retryPolicy.getPattern() != null) { + retryPolicyBuilder.setPattern(retryPolicy.getPattern().getValue()); + } + } + + optionBuilder = DaprProtos.StateOptions.newBuilder(); + if (options.getConcurrency() != null) { + optionBuilder.setConcurrency(options.getConcurrency().getValue()); + } + if (options.getConsistency() != null) { + optionBuilder.setConsistency(options.getConsistency().getValue()); + } + if (retryPolicyBuilder != null) { + optionBuilder.setRetryPolicy(retryPolicyBuilder.build()); + } + } + DaprProtos.DeleteStateEnvelope.Builder builder = DaprProtos.DeleteStateEnvelope.newBuilder() + .setEtag(state.getEtag()) + .setKey(state.getKey()); + if (optionBuilder != null) { + builder.setOptions(optionBuilder.build()); + } + + DaprProtos.DeleteStateEnvelope envelope = builder.build(); ListenableFuture futureEmpty = client.deleteState(envelope); return Mono.just(futureEmpty).flatMap(f -> { try { @@ -262,6 +333,7 @@ class DaprClientGrpcAdapter implements DaprClient { /** * Operation not supported for GRPC + * * @throws UnsupportedOperationException every time is called. */ @Override @@ -271,6 +343,7 @@ class DaprClientGrpcAdapter implements DaprClient { /** * Operation not supported for GRPC + * * @throws UnsupportedOperationException every time is called. */ @Override @@ -280,6 +353,7 @@ class DaprClientGrpcAdapter implements DaprClient { /** * Operation not supported for GRPC + * * @throws UnsupportedOperationException every time is called. */ @Override @@ -289,6 +363,7 @@ class DaprClientGrpcAdapter implements DaprClient { /** * Operation not supported for GRPC + * * @throws UnsupportedOperationException every time is called. */ @Override @@ -298,6 +373,7 @@ class DaprClientGrpcAdapter implements DaprClient { /** * Operation not supported for GRPC + * * @throws UnsupportedOperationException every time is called. */ @Override @@ -307,6 +383,7 @@ class DaprClientGrpcAdapter implements DaprClient { /** * Operation not supported for GRPC + * * @throws UnsupportedOperationException every time is called. */ @Override @@ -316,6 +393,7 @@ class DaprClientGrpcAdapter implements DaprClient { /** * Operation not supported for GRPC + * * @throws UnsupportedOperationException every time is called. */ @Override @@ -324,46 +402,26 @@ class DaprClientGrpcAdapter implements DaprClient { } /** - * Converts state options to map. - * - * TODO: Move this logic to StateOptions. - * @param options Instance to have is methods converted into map. - * @return Map for the state options. - * @throws IllegalAccessException Cannot extract params. + * 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. + * @throws IOException If there's an issue serializing the request. */ - private Map transformStateOptionsToMap(StateOptions options) - throws IllegalAccessException { - Map mapOptions = null; - if (options != null) { - mapOptions = new HashMap<>(); - for (Field field : options.getClass().getFields()) { - Object fieldValue = field.get(options); - if (fieldValue != null) { - mapOptions.put(field.getName(), fieldValue); - } - } + private DaprProtos.InvokeServiceEnvelope buildInvokeServiceEnvelope( + String verb, String appId, String method, K request) throws IOException { + DaprProtos.InvokeServiceEnvelope.Builder envelopeBuilder = DaprProtos.InvokeServiceEnvelope.newBuilder() + .setId(appId) + .setMethod(verb); + if (request != null) { + byte[] byteRequest = objectSerializer.serialize(request); + Any data = Any.newBuilder().setValue(ByteString.copyFrom(byteRequest)).build(); + envelopeBuilder.setData(data); } - return mapOptions; + return envelopeBuilder.build(); } - /** - * Creates an map for the given key-value operation. - * - * // TODO: Move this logic into StateKeyValue. - * @param state Key value for the state change. - * @param mapOptions Options to be applied to this operation. - * @return Map for the key-value operation. - * @throws IllegalAccessException Cannot identify key-value attributes. - */ - private Map transformStateKeyValueToMap(StateKeyValue state, Map mapOptions) - throws IllegalAccessException { - Map mapState = new HashMap<>(); - for (Field field : state.getClass().getFields()) { - mapState.put(field.getName(), field.get(state)); - } - if (mapOptions != null && !mapOptions.isEmpty()) { - mapState.put("Options", mapOptions); - } - return mapState; - } } \ No newline at end of file diff --git a/sdk/src/main/java/io/dapr/client/DaprClientHttpAdapter.java b/sdk/src/main/java/io/dapr/client/DaprClientHttpAdapter.java index 621011cf3..08cb3ad5d 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientHttpAdapter.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientHttpAdapter.java @@ -11,6 +11,7 @@ import io.dapr.utils.Constants; import io.dapr.utils.ObjectSerializer; import reactor.core.publisher.Mono; +import java.io.IOException; import java.lang.reflect.Field; import java.util.Arrays; import java.util.HashMap; @@ -93,10 +94,10 @@ public class DaprClientHttpAdapter implements DaprClient { } String path = String.format("%s/%s/method/%s", Constants.INVOKE_PATH, appId, method); byte[] serializedRequestBody = objectSerializer.serialize(request); - return this.client.invokeAPI(httMethod, path, serializedRequestBody, metadata) - .flatMap(r -> { + Mono response = this.client.invokeAPI(httMethod, path, serializedRequestBody, metadata); + return response.flatMap(r -> { try { - return Mono.just(objectSerializer.deserialize(r, clazz)); + return Mono.just(objectSerializer.deserialize(r.getBody(), clazz)); } catch (Exception ex) { return Mono.error(ex); } @@ -168,7 +169,7 @@ public class DaprClientHttpAdapter implements DaprClient { * {@inheritDoc} */ @Override - public Mono getState(StateKeyValue state, StateOptions options, Class clazz) { + public Mono> getState(StateKeyValue state, StateOptions stateOptions, Class clazz) { try { if (state.getKey() == null) { throw new IllegalArgumentException("Name cannot be null or empty."); @@ -181,12 +182,12 @@ public class DaprClientHttpAdapter implements DaprClient { StringBuilder url = new StringBuilder(Constants.STATE_PATH) .append("/") .append(state.getKey()) - .append(getOptionsAsQueryParameter(options)); + .append(getOptionsAsQueryParameter(stateOptions)); return this.client .invokeAPI(DaprHttp.HttpMethods.GET.name(), url.toString(), headers) .flatMap(s -> { try { - return Mono.just(objectSerializer.deserialize(s, clazz)); + return Mono.just(buildStateKeyValue(s, state.getKey(), clazz)); } catch (Exception ex) { return Mono.error(ex); } @@ -258,7 +259,14 @@ public class DaprClientHttpAdapter implements DaprClient { @Override public Mono invokeActorMethod(String actorType, String actorId, String methodName, String jsonPayload) { String url = String.format(Constants.ACTOR_METHOD_RELATIVE_URL_FORMAT, actorType, actorId, methodName); - return this.client.invokeAPI(DaprHttp.HttpMethods.POST.name(), url, jsonPayload, null); + Mono responseMono = this.client.invokeAPI(DaprHttp.HttpMethods.POST.name(), url, jsonPayload, null); + return responseMono.flatMap(f -> { + try { + return Mono.just(objectSerializer.deserialize(f.getBody(), String.class)); + } catch (Exception ex) { + return Mono.error(ex); + } + }); } /** @@ -267,7 +275,14 @@ public class DaprClientHttpAdapter implements DaprClient { @Override public Mono getActorState(String actorType, String actorId, String keyName) { String url = String.format(Constants.ACTOR_STATE_KEY_RELATIVE_URL_FORMAT, actorType, actorId, keyName); - return this.client.invokeAPI(DaprHttp.HttpMethods.GET.name(), url, "", null); + Mono responseMono = this.client.invokeAPI(DaprHttp.HttpMethods.GET.name(), url, "", null); + return responseMono.flatMap(f -> { + try { + return Mono.just(objectSerializer.deserialize(f.getBody(), String.class)); + } catch (Exception ex) { + return Mono.error(ex); + } + }); } /** @@ -361,4 +376,23 @@ public class DaprClientHttpAdapter implements DaprClient { return mapOptions; } + /** + * Builds a StateKeyValue object based on the Response + * @param resonse The response of the HTTP Call + * @param requestedKey The Key Requested. + * @param clazz The Class of the Value of the state + * @param The Type of the Value of the state + * @return A StateKeyValue instance + * @throws IOException If there's a issue deserialzing the response. + */ + private StateKeyValue buildStateKeyValue(DaprHttp.Response resonse, String requestedKey, 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); + } + } diff --git a/sdk/src/main/java/io/dapr/client/DaprHttp.java b/sdk/src/main/java/io/dapr/client/DaprHttp.java index 1c78474b5..41af03a5c 100644 --- a/sdk/src/main/java/io/dapr/client/DaprHttp.java +++ b/sdk/src/main/java/io/dapr/client/DaprHttp.java @@ -8,16 +8,18 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.dapr.exceptions.DaprError; import io.dapr.exceptions.DaprException; import io.dapr.utils.Constants; -import okhttp3.*; +import io.dapr.utils.ObjectSerializer; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; import reactor.core.publisher.Mono; import java.io.IOException; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -27,7 +29,31 @@ class DaprHttp { /** * HTTP Methods supported. */ - enum HttpMethods { GET, PUT, POST, DELETE; } + enum HttpMethods {GET, PUT, POST, DELETE;} + + static class Response { + private byte[] body; + private Map headers; + private int statusCode; + + public Response(byte[] body, Map headers, int statusCode) { + this.body = body; + this.headers = headers; + this.statusCode = statusCode; + } + + public byte[] getBody() { + return body; + } + + public Map getHeaders() { + return headers; + } + + public int getStatusCode() { + return statusCode; + } + } /** * Defines the standard application/json type for HTTP calls in Dapr. @@ -86,8 +112,8 @@ class DaprHttp { * @param urlString url as String. * @return Asynchronous text */ - public Mono invokeAPI(String method, String urlString, Map headers) { - return this.invokeAPI(method, urlString, (String) null, headers); + public Mono invokeAPI(String method, String urlString, Map headers) { + return this.invokeAPI(method, urlString, (byte[]) null, headers); } /** @@ -98,13 +124,8 @@ class DaprHttp { * @param content payload to be posted. * @return Asynchronous text */ - public Mono invokeAPI(String method, String urlString, String content, Map headers) { - return this.invokeAPI( - method, - urlString, - content == null ? EMPTY_BYTES : content.getBytes(StandardCharsets.UTF_8), - headers) - .map(s -> new String(s, StandardCharsets.UTF_8)); + public Mono invokeAPI(String method, String urlString, String content, Map headers) { + return this.invokeAPI(method, urlString, content == null ? EMPTY_BYTES : content.getBytes(StandardCharsets.UTF_8), headers); } /** @@ -115,12 +136,12 @@ class DaprHttp { * @param content payload to be posted. * @return Asynchronous text */ - public Mono invokeAPI(String method, String urlString, byte[] content, Map headers) { + public Mono invokeAPI(String method, String urlString, byte[] content, Map headers) { return Mono.fromFuture(CompletableFuture.supplyAsync( () -> { try { String requestId = UUID.randomUUID().toString(); - RequestBody body; + RequestBody body = REQUEST_BODY_EMPTY_JSON; String contentType = headers != null ? headers.get("content-type") : null; MediaType mediaType = contentType == null ? MEDIA_TYPE_APPLICATION_JSON : MediaType.get(contentType); @@ -128,7 +149,7 @@ class DaprHttp { body = mediaType.equals(MEDIA_TYPE_APPLICATION_JSON) ? REQUEST_BODY_EMPTY_JSON : RequestBody.Companion.create(new byte[0], mediaType); } else { - body = RequestBody.Companion.create(content, mediaType); + body = RequestBody.Companion.create(content, mediaType); } Request.Builder requestBuilder = new Request.Builder() @@ -150,17 +171,22 @@ class DaprHttp { Request request = requestBuilder.build(); - try (Response response = this.httpClient.newCall(request).execute()) { - byte[] responseBody = response.body().bytes(); + try (okhttp3.Response response = this.httpClient.newCall(request).execute()) { if (!response.isSuccessful()) { - DaprError error = this.parseDaprError(responseBody); + DaprError error = parseDaprError(response.body().bytes()); if ((error != null) && (error.getErrorCode() != null) && (error.getMessage() != null)) { - throw new DaprException(error); + throw new RuntimeException(new DaprException(error)); } - throw new IOException("Unknown error."); + throw new RuntimeException("Unknown error."); } - return responseBody == null ? EMPTY_BYTES : responseBody; + + Map mapHeaders = new HashMap<>(); + byte[] result = response.body().bytes(); + response.headers().forEach(pair -> { + mapHeaders.put(pair.getFirst(), pair.getSecond()); + }); + return new Response(result, mapHeaders, response.code()); } } catch (Exception e) { throw new RuntimeException(e); @@ -178,7 +204,6 @@ class DaprHttp { if (json == null) { return null; } - return OBJECT_MAPPER.readValue(json, DaprError.class); } diff --git a/sdk/src/main/java/io/dapr/client/domain/StateKeyValue.java b/sdk/src/main/java/io/dapr/client/domain/StateKeyValue.java index 599045907..1f1e59c6a 100644 --- a/sdk/src/main/java/io/dapr/client/domain/StateKeyValue.java +++ b/sdk/src/main/java/io/dapr/client/domain/StateKeyValue.java @@ -4,26 +4,89 @@ */ package io.dapr.client.domain; +/** + * This class reprent what a State is + * @param + */ public class StateKeyValue { + /** + * The value of the state + */ private final T value; + /** + * The key of the state + */ private final String key; + /** + * The ETag to be used + * Keep in mind that for some state stores (like reids) only numbers are supported. + */ private final String etag; + /** + * Create an inmutable state + * @param value + * @param key + * @param etag + */ public StateKeyValue(T value, String key, String etag) { this.value = value; this.key = key; this.etag = etag; } + /** + * Retrieves the Value of the state + * @return + */ public T getValue() { return value; } + /** + * Retrieves the Key of the state + * @return + */ public String getKey() { return key; } + /** + * Retrieve the ETag of this state + * @return + */ public String getEtag() { return etag; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof StateKeyValue)) return false; + + StateKeyValue that = (StateKeyValue) 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; + if (getEtag() != null ? !getEtag().equals(that.getEtag()) : that.getEtag() != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = getValue() != null ? getValue().hashCode() : 0; + result = 31 * result + (getKey() != null ? getKey().hashCode() : 0); + result = 31 * result + (getEtag() != null ? getEtag().hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "StateKeyValue{" + + "value=" + value + + ", key='" + key + '\'' + + ", etag='" + etag + '\'' + + '}'; + } } 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 834baaf98..414c84199 100644 --- a/sdk/src/main/java/io/dapr/client/domain/StateOptions.java +++ b/sdk/src/main/java/io/dapr/client/domain/StateOptions.java @@ -4,16 +4,98 @@ */ package io.dapr.client.domain; +import java.time.Duration; + public class StateOptions { + private final Consistency consistency; + private final Concurrency concurrency; + private final RetryPolicy retryPolicy; - private final String consistency; - - public StateOptions(String consistency) { + public StateOptions(Consistency consistency, Concurrency concurrency, RetryPolicy retryPolicy) { this.consistency = consistency; + this.concurrency = concurrency; + this.retryPolicy = retryPolicy; } - public String getConsistency() { + public Concurrency getConcurrency() { + return concurrency; + } + + public Consistency getConsistency() { return consistency; } + public RetryPolicy getRetryPolicy() { + return retryPolicy; + } + + public static enum Consistency { + EVENTUAL("eventual"), + STRONG("strong"); + + private final String value; + + private Consistency(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + } + + public static enum Concurrency { + FIRST_WRITE("first-write"), + LAST_WRITE ("last-write"); + + private final String value; + + private Concurrency(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + } + + public static class RetryPolicy { + public static enum Pattern { + LINEAR("linear"), + EXPONENTIAL("exponential"); + + private String value; + + private Pattern(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + } + + private final Duration interval; + private final String threshold; + private final Pattern pattern; + + + public RetryPolicy(Duration interval, String threshold, Pattern pattern) { + this.interval = interval; + this.threshold = threshold; + this.pattern = pattern; + } + + public Duration getInterval() { + return interval; + } + + public String getThreshold() { + return threshold; + } + + public Pattern getPattern() { + return pattern; + } + } } diff --git a/sdk/src/main/java/io/dapr/utils/DurationUtils.java b/sdk/src/main/java/io/dapr/utils/DurationUtils.java new file mode 100644 index 000000000..1be79fa3a --- /dev/null +++ b/sdk/src/main/java/io/dapr/utils/DurationUtils.java @@ -0,0 +1,142 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// ------------------------------------------------------------ + +package io.dapr.utils; + +import java.time.Duration; + +public class DurationUtils { + + /** + * Converts time from the String format used by Dapr into a Duration. + * + * @param valueString A String representing time in the Dapr runtime's format (e.g. 4h15m50s60ms). + * @return A Duration + */ + public static Duration ConvertDurationFromDaprFormat(String valueString) { + // Convert the format returned by the Dapr runtime into Duration + // An example of the format is: 4h15m50s60ms. It does not include days. + int hIndex = valueString.indexOf('h'); + int mIndex = valueString.indexOf('m'); + int sIndex = valueString.indexOf('s'); + int msIndex = valueString.indexOf("ms"); + + String hoursSpan = valueString.substring(0, hIndex); + + int hours = Integer.parseInt(hoursSpan); + int days = hours / 24; + hours = hours % 24; + + String minutesSpan = valueString.substring(hIndex + 1, mIndex); + int minutes = Integer.parseInt(minutesSpan); + + String secondsSpan = valueString.substring(mIndex + 1, sIndex); + int seconds = Integer.parseInt(secondsSpan); + + String millisecondsSpan = valueString.substring(sIndex + 1, msIndex); + int milliseconds = Integer.parseInt(millisecondsSpan); + + return Duration.ZERO + .plusDays(days) + .plusHours(hours) + .plusMinutes(minutes) + .plusSeconds(seconds) + .plusMillis(milliseconds); + } + + /** + * Converts a Duration to the format used by the Dapr runtime. + * + * @param value Duration + * @return The Duration formatted as a String in the format the Dapr runtime uses (e.g. 4h15m50s60ms) + */ + public static String ConvertDurationToDaprFormat(Duration value) { + String stringValue = ""; + + // return empty string for anything negative, it'll only happen for reminder "periods", not dueTimes. A + // negative "period" means fire once only. + if (value == Duration.ZERO || + (value.compareTo(Duration.ZERO) == 1)) { + long hours = getDaysPart(value) * 24 + getHoursPart(value); + + StringBuilder sb = new StringBuilder(); + + sb.append(hours); + sb.append("h"); + + sb.append(getMinutesPart((value))); + sb.append("m"); + + sb.append(getSecondsPart((value))); + sb.append("s"); + + sb.append(getMilliSecondsPart((value))); + sb.append("ms"); + + return sb.toString(); + } + + return stringValue; + } + + /** + * Helper to get the "days" part of the Duration. For example if the duration is 26 hours, this returns 1. + * + * @param d Duration + * @return Number of days. + */ + static long getDaysPart(Duration d) { + long t = d.getSeconds() / 60 / 60 / 24; + return t; + } + + /** + * Helper to get the "hours" part of the Duration. For example if the duration is 26 hours, this is 1 day, 2 hours, so this returns 2. + * + * @param d The duration to parse + * @return the hour part of the duration + */ + static long getHoursPart(Duration d) { + long u = (d.getSeconds() / 60 / 60) % 24; + + return u; + } + + /** + * Helper to get the "minutes" part of the Duration. + * + * @param d The duration to parse + * @return the minutes part of the duration + */ + static long getMinutesPart(Duration d) { + long u = (d.getSeconds() / 60) % 60; + + return u; + } + + /** + * Helper to get the "seconds" part of the Duration. + * + * @param d The duration to parse + * @return the seconds part of the duration + */ + static long getSecondsPart(Duration d) { + long u = d.getSeconds() % 60; + + return u; + } + + /** + * Helper to get the "millis" part of the Duration. + * + * @param d The duration to parse + * @return the milliseconds part of the duration + */ + static long getMilliSecondsPart(Duration d) { + long u = d.toMillis() % 1000; + + return u; + } +} diff --git a/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java b/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java new file mode 100644 index 000000000..b4a2f6821 --- /dev/null +++ b/sdk/src/test/java/io/dapr/client/DaprClientGrpcAdapterTest.java @@ -0,0 +1,610 @@ +package io.dapr.client; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.SettableFuture; +import com.google.protobuf.Any; +import com.google.protobuf.ByteString; +import com.google.protobuf.Empty; +import io.dapr.DaprGrpc; +import io.dapr.DaprProtos; +import io.dapr.client.domain.StateKeyValue; +import io.dapr.client.domain.StateOptions; +import io.dapr.client.domain.Verb; +import io.dapr.utils.ObjectSerializer; +import org.checkerframework.checker.nullness.compatqual.NullableDecl; +import org.junit.Before; +import org.junit.Test; +import reactor.core.publisher.Mono; + +import javax.annotation.Nullable; + +import java.io.IOException; +import java.time.Duration; + +import static com.google.common.util.concurrent.Futures.addCallback; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +public class DaprClientGrpcAdapterTest { + + private DaprGrpc.DaprFutureStub client; + private DaprClientGrpcAdapter adater; + private ObjectSerializer serializer; + + @Before + public void setup() { + client = mock(DaprGrpc.DaprFutureStub.class); + adater = new DaprClientGrpcAdapter(client); + serializer = new ObjectSerializer(); + } + + @Test(expected = UnsupportedOperationException.class) + public void unregisterActorTimerTest() { + Mono result = adater.unregisterActorTimer("actorType", "actorId", "timerName"); + result.block(); + } + + @Test(expected = UnsupportedOperationException.class) + public void registerActorTimerTest() { + Mono result = adater.registerActorTimer("actorType", "actorId", "timerName" , "DATA"); + result.block(); + } + + @Test(expected = UnsupportedOperationException.class) + public void unregisterActorReminderTest() { + Mono result = adater.unregisterActorReminder("actorType", "actorId", "reminderName"); + result.block(); + } + + @Test(expected = UnsupportedOperationException.class) + public void registerActorReminderTest() { + Mono result = adater.registerActorReminder("actorType", "actorId", "reminderName", "DATA"); + result.block(); + } + + @Test(expected = UnsupportedOperationException.class) + public void saveActorStateTransactionallyTest() { + Mono result = adater.saveActorStateTransactionally("actorType", "actorId", "DATA"); + result.block(); + } + + @Test(expected = UnsupportedOperationException.class) + public void getActorStateTest() { + Mono result = adater.getActorState("actorType", "actorId", "keyName"); + String state = result.block(); + } + + @Test(expected = UnsupportedOperationException.class) + public void invokeActorMethodTest() { + Mono result = adater.invokeActorMethod("actorType", "actorId", "methodName", "jsonPlayload"); + String monoResult = result.block(); + } + + @Test(expected = RuntimeException.class) + public void publishEventExceptionThrownTest() { + when(client.publishEvent(any(DaprProtos.PublishEventEnvelope.class))) + .thenThrow(RuntimeException.class); + Mono result = adater.publishEvent("topic", "object"); + result.block(); + } + + @Test(expected = RuntimeException.class) + public void publishEventCallbackExceptionThrownTest() { + SettableFuture settableFuture = SettableFuture.create(); + RuntimeException ex = new RuntimeException("An Exception"); + MockCallback callback = new MockCallback(ex); + addCallback(settableFuture, callback, directExecutor()); + when(client.publishEvent(any(DaprProtos.PublishEventEnvelope.class))) + .thenReturn(settableFuture); + Mono result = adater.publishEvent("topic", "object"); + settableFuture.setException(ex); + result.block(); + } + + @Test + public void publishEventTest() { + SettableFuture settableFuture = SettableFuture.create(); + MockCallback callback = new MockCallback(Empty.newBuilder().build()); + addCallback(settableFuture, callback, directExecutor()); + when(client.publishEvent(any(DaprProtos.PublishEventEnvelope.class))) + .thenReturn(settableFuture); + Mono result = adater.publishEvent("topic", "object"); + settableFuture.set(Empty.newBuilder().build()); + result.block(); + assertTrue(callback.wasCalled); + } + + @Test + public void publishEventObjectTest() { + SettableFuture settableFuture = SettableFuture.create(); + MockCallback callback = new MockCallback(Empty.newBuilder().build()); + addCallback(settableFuture, callback, directExecutor()); + when(client.publishEvent(any(DaprProtos.PublishEventEnvelope.class))) + .thenReturn(settableFuture); + MyObject event = new MyObject(1, "Event"); + Mono result = adater.publishEvent("topic", event); + settableFuture.set(Empty.newBuilder().build()); + result.block(); + assertTrue(callback.wasCalled); + } + + @Test(expected = RuntimeException.class) + public void invokeBindingExceptionThrownTest() { + when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) + .thenThrow(RuntimeException.class); + Mono result = adater.invokeBinding("BindingName", "request"); + result.block(); + } + + @Test(expected = RuntimeException.class) + public void invokeBindingCallbackExceptionThrownTest() { + SettableFuture settableFuture = SettableFuture.create(); + RuntimeException ex = new RuntimeException("An Exception"); + MockCallback callback = + new MockCallback(ex); + addCallback(settableFuture, callback, directExecutor()); + settableFuture.setException(ex); + when(client.invokeBinding(any(DaprProtos.InvokeBindingEnvelope.class))) + .thenReturn(settableFuture); + Mono result = adater.invokeBinding("BindingName", "request"); + result.block(); + } + + @Test + public void invokeBindingTest() { + SettableFuture settableFuture = SettableFuture.create(); + MockCallback callback = new MockCallback(Empty.newBuilder().build()); + addCallback(settableFuture, callback, directExecutor()); + when(client.invokeBinding(any(DaprProtos.InvokeBindingEnvelope.class))) + .thenReturn(settableFuture); + Mono result = adater.invokeBinding("BindingName", "request"); + settableFuture.set(Empty.newBuilder().build()); + result.block(); + assertTrue(callback.wasCalled); + } + + @Test + public void invokeBindingObjectTest() { + SettableFuture settableFuture = SettableFuture.create(); + MockCallback callback = new MockCallback(Empty.newBuilder().build()); + addCallback(settableFuture, callback, directExecutor()); + when(client.invokeBinding(any(DaprProtos.InvokeBindingEnvelope.class))) + .thenReturn(settableFuture); + MyObject event = new MyObject(1, "Event"); + Mono result = adater.invokeBinding("BindingName", event); + settableFuture.set(Empty.newBuilder().build()); + result.block(); + assertTrue(callback.wasCalled); + } + + @Test(expected = RuntimeException.class) + public void invokeServiceVoidExceptionThrownTest() { + when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) + .thenThrow(RuntimeException.class); + Mono result = adater.invokeService(Verb.GET, "appId", "method", "request", null); + result.block(); + } + + @Test(expected = RuntimeException.class) + public void invokeServiceVoidCallbackExceptionThrownTest() { + SettableFuture settableFuture = SettableFuture.create(); + RuntimeException ex = new RuntimeException("An Exception"); + MockCallback callback = + new MockCallback(ex); + addCallback(settableFuture, callback, directExecutor()); + settableFuture.setException(ex); + when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) + .thenReturn(settableFuture); + Mono result = adater.invokeService(Verb.GET, "appId", "method", "request", null); + result.block(); + } + + @Test + public void invokeServiceVoidTest() throws Exception { + SettableFuture settableFuture = SettableFuture.create(); + + MockCallback callback = + new MockCallback(DaprProtos.InvokeServiceResponseEnvelope.newBuilder() + .setData(getAny("Value")).build()); + addCallback(settableFuture, callback, directExecutor()); + when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) + .thenReturn(settableFuture); + Mono result = adater.invokeService(Verb.GET, "appId", "method", "request", null); + settableFuture.set(DaprProtos.InvokeServiceResponseEnvelope.newBuilder().setData(getAny("Value")).build()); + result.block(); + assertTrue(callback.wasCalled); + } + + @Test + public void invokeServiceVoidObjectTest() throws Exception { + SettableFuture settableFuture = SettableFuture.create(); + + MockCallback callback = + new MockCallback(DaprProtos.InvokeServiceResponseEnvelope.newBuilder() + .setData(getAny("Value")).build()); + addCallback(settableFuture, callback, directExecutor()); + when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) + .thenReturn(settableFuture); + MyObject request = new MyObject(1, "Event"); + Mono result = adater.invokeService(Verb.GET, "appId", "method", request, null); + settableFuture.set(DaprProtos.InvokeServiceResponseEnvelope.newBuilder().setData(getAny("Value")).build()); + result.block(); + assertTrue(callback.wasCalled); + } + + @Test(expected = RuntimeException.class) + public void invokeServiceExceptionThrownTest() { + when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) + .thenThrow(RuntimeException.class); + Mono result = adater.invokeService(Verb.GET, "appId", "method", "request", null, String.class); + result.block(); + } + + @Test(expected = RuntimeException.class) + public void invokeServiceCallbackExceptionThrownTest() { + SettableFuture settableFuture = SettableFuture.create(); + RuntimeException ex = new RuntimeException("An Exception"); + MockCallback callback = + new MockCallback(ex); + addCallback(settableFuture, callback, directExecutor()); + when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) + .thenReturn(settableFuture); + Mono result = adater.invokeService(Verb.GET, "appId", "method", "request", null, String.class); + settableFuture.setException(ex); + result.block(); + } + + @Test + public void invokeServiceTest() throws Exception { + String expected = "Value"; + SettableFuture settableFuture = SettableFuture.create(); + MockCallback callback = + new MockCallback(DaprProtos.InvokeServiceResponseEnvelope.newBuilder() + .setData(getAny(expected)).build()); + addCallback(settableFuture, callback, directExecutor()); + 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", "request", null, String.class); + String strOutput = result.block(); + assertEquals(expected, strOutput); + } + + @Test + public void invokeServiceObjectTest() throws Exception { + MyObject resultObj = new MyObject(1, "Value"); + SettableFuture settableFuture = SettableFuture.create(); + MockCallback callback = + new MockCallback(DaprProtos.InvokeServiceResponseEnvelope.newBuilder() + .setData(getAny(resultObj)).build()); + addCallback(settableFuture, callback, directExecutor()); + 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", "request", null, String.class); + String strOutput = result.block(); + assertEquals(serializer.serializeString(resultObj), strOutput); + } + + @Test(expected = RuntimeException.class) + public void invokeServiceNoRequestBodyExceptionThrownTest() { + when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) + .thenThrow(RuntimeException.class); + Mono result = adater.invokeService(Verb.GET, "appId", "method", null, String.class); + result.block(); + } + + @Test(expected = RuntimeException.class) + public void invokeServiceNoRequestCallbackExceptionThrownTest() { + SettableFuture settableFuture = SettableFuture.create(); + RuntimeException ex = new RuntimeException("An Exception"); + MockCallback callback = + new MockCallback(ex); + addCallback(settableFuture, callback, directExecutor()); + when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) + .thenReturn(settableFuture); + Mono result = adater.invokeService(Verb.GET, "appId", "method", null, String.class); + settableFuture.setException(ex); + result.block(); + } + + @Test + public void invokeServiceNoRequestBodyTest() throws Exception { + String expected = "Value"; + SettableFuture settableFuture = SettableFuture.create(); + + MockCallback callback = + new MockCallback(DaprProtos.InvokeServiceResponseEnvelope.newBuilder() + .setData(getAny(expected)).build()); + addCallback(settableFuture, callback, directExecutor()); + 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); + String strOutput = result.block(); + assertEquals(expected, strOutput); + } + + @Test + public void invokeServiceNoRequestBodyObjectTest() throws Exception { + MyObject resultObj = new MyObject(1, "Value"); + SettableFuture settableFuture = SettableFuture.create(); + + MockCallback callback = + new MockCallback(DaprProtos.InvokeServiceResponseEnvelope.newBuilder() + .setData(getAny(resultObj)).build()); + addCallback(settableFuture, callback, directExecutor()); + 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); + String strOutput = result.block(); + assertEquals(serializer.serializeString(resultObj), strOutput); + } + + @Test(expected = RuntimeException.class) + public void invokeServiceByteRequestExceptionThrownTest() throws IOException { + when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) + .thenThrow(RuntimeException.class); + String request = "Request"; + byte[] byteRequest = serializer.serialize(request); + Mono result = adater.invokeService(Verb.GET, "appId", "method", byteRequest, null); + result.block(); + } + + @Test(expected = RuntimeException.class) + public void invokeServiceByteRequestCallbackExceptionThrownTest() throws IOException { + SettableFuture settableFuture = SettableFuture.create(); + RuntimeException ex = new RuntimeException("An Exception"); + MockCallback callback = + new MockCallback(ex); + addCallback(settableFuture, callback, directExecutor()); + when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) + .thenReturn(settableFuture); + String request = "Request"; + byte[] byteRequest = serializer.serialize(request); + Mono result = adater.invokeService(Verb.GET, "appId", "method", byteRequest, null); + settableFuture.setException(ex); + result.block(); + } + + @Test + public void invokeByteRequestServiceTest() throws Exception { + String expected = "Value"; + SettableFuture settableFuture = SettableFuture.create(); + MockCallback callback = + new MockCallback(DaprProtos.InvokeServiceResponseEnvelope.newBuilder() + .setData(getAny(expected)).build()); + addCallback(settableFuture, callback, directExecutor()); + settableFuture.set(DaprProtos.InvokeServiceResponseEnvelope.newBuilder().setData(getAny(expected)).build()); + when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) + .thenReturn(settableFuture); + String request = "Request"; + byte[] byteRequest = serializer.serialize(request); + Mono result = adater.invokeService(Verb.GET, "appId", "method", byteRequest, null); + byte[] byteOutput = result.block(); + String strOutput = serializer.deserialize(byteOutput, String.class); + assertEquals(expected, strOutput); + } + + @Test + public void invokeServiceByteRequestObjectTest() throws Exception { + MyObject resultObj = new MyObject(1, "Value"); + SettableFuture settableFuture = SettableFuture.create(); + MockCallback callback = + new MockCallback(DaprProtos.InvokeServiceResponseEnvelope.newBuilder() + .setData(getAny(resultObj)).build()); + addCallback(settableFuture, callback, directExecutor()); + settableFuture.set(DaprProtos.InvokeServiceResponseEnvelope.newBuilder().setData(getAny(resultObj)).build()); + when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) + .thenReturn(settableFuture); + String request = "Request"; + byte[] byteRequest = serializer.serialize(request); + Mono result = adater.invokeService(Verb.GET, "appId", "method", byteRequest, null); + byte[] byteOutput = result.block(); + assertEquals(resultObj, serializer.deserialize(byteOutput, MyObject.class)); + } + + @Test(expected = RuntimeException.class) + public void invokeServiceNoRequestNoClassBodyExceptionThrownTest() { + when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) + .thenThrow(RuntimeException.class); + Mono result = adater.invokeService(Verb.GET, "appId", "method", null); + result.block(); + } + + @Test(expected = RuntimeException.class) + public void invokeServiceNoRequestNoClassCallbackExceptionThrownTest() { + SettableFuture settableFuture = SettableFuture.create(); + RuntimeException ex = new RuntimeException("An Exception"); + MockCallback callback = + new MockCallback(ex); + addCallback(settableFuture, callback, directExecutor()); + when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) + .thenReturn(settableFuture); + Mono result = adater.invokeService(Verb.GET, "appId", "method", null); + settableFuture.setException(ex); + result.block(); + } + + @Test + public void invokeServiceNoRequestNoClassBodyTest() throws Exception { + String expected = "Value"; + SettableFuture settableFuture = SettableFuture.create(); + MockCallback callback = + new MockCallback(DaprProtos.InvokeServiceResponseEnvelope.newBuilder() + .setData(getAny(expected)).build()); + addCallback(settableFuture, callback, directExecutor()); + when(client.invokeService(any(DaprProtos.InvokeServiceEnvelope.class))) + .thenReturn(settableFuture); + Mono result = adater.invokeService(Verb.GET, "appId", "method", null); + settableFuture.set(DaprProtos.InvokeServiceResponseEnvelope.newBuilder().setData(getAny(expected)).build()); + result.block(); + assertTrue(callback.wasCalled); + } + + @Test + public void invokeServiceNoRequestNoClassBodyObjectTest() throws Exception { + MyObject resultObj = new MyObject(1, "Value"); + SettableFuture settableFuture = SettableFuture.create(); + + MockCallback callback = + new MockCallback(DaprProtos.InvokeServiceResponseEnvelope.newBuilder() + .setData(getAny(resultObj)).build()); + addCallback(settableFuture, callback, directExecutor()); + 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); + result.block(); + assertTrue(callback.wasCalled); + } + + @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"); + Mono> result = adater.getState(key, null, String.class); + result.block(); + } + + @Test(expected = RuntimeException.class) + public void getStateCallbackExceptionThrownTest() { + SettableFuture settableFuture = SettableFuture.create(); + RuntimeException ex = new RuntimeException("An Exception"); + MockCallback callback = + new MockCallback<>(ex); + addCallback(settableFuture, callback, directExecutor()); + when(client.getState(any(io.dapr.DaprProtos.GetStateEnvelope.class))) + .thenReturn(settableFuture); + StateKeyValue key = buildStateKey(null, "Key1", "ETag1"); + Mono> result = adater.getState(key, null, String.class); + settableFuture.setException(ex); + result.block(); + } + + @Test + public void getStateStringValueNoOptionsTest() throws IOException { + String etag = "ETag1"; + String key = "key1"; + String expectedValue = "Expected state"; + StateKeyValue expectedState = buildStateKey(expectedValue, key, etag); + DaprProtos.GetStateResponseEnvelope responseEnvelope = DaprProtos.GetStateResponseEnvelope.newBuilder() + .setData(getAny(expectedValue)) + .setEtag(etag) + .build(); + 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); + Mono> result = adater.getState(keyRequest, null, String.class); + settableFuture.set(responseEnvelope); + assertEquals(expectedState, result.block()); + } + + private StateKeyValue buildStateKey(T value, String key, String etag) { + return new StateKeyValue(value, key, etag); + } + + private StateOptions buildStateOptions(StateOptions.Consistency consistency, StateOptions.Concurrency concurrency, + Duration interval, String threshold, StateOptions.RetryPolicy.Pattern pattern) { + + StateOptions.RetryPolicy retryPolicy = null; + if (interval != null || threshold != null || pattern != null) { + retryPolicy = new StateOptions.RetryPolicy(interval, threshold, pattern); + } + StateOptions options = null; + if (consistency != null || concurrency != null || retryPolicy != null) { + options = new StateOptions(consistency, concurrency, retryPolicy); + } + return options; + } + + private Any getAny(T value) throws IOException { + byte[] byteValue = serializer.serialize(value); + return Any.newBuilder().setValue(ByteString.copyFrom(byteValue)).build(); + } + + private final class MockCallback implements FutureCallback { + @Nullable + private T value = null; + @Nullable + private Throwable failure = null; + private boolean wasCalled = false; + + public MockCallback(T expectedValue) { + this.value = expectedValue; + } + + public MockCallback(Throwable expectedFailure) { + this.failure = expectedFailure; + } + + @Override + public synchronized void onSuccess(@NullableDecl T result) { + assertFalse(wasCalled); + wasCalled = true; + assertEquals(value, result); + } + + @Override + public synchronized void onFailure(Throwable throwable) { + assertFalse(wasCalled); + wasCalled = true; + assertEquals(failure, throwable); + } + } + + public static class MyObject { + private Integer id; + private String value; + + public MyObject() { + } + + public MyObject(Integer id, String value) { + this.id = id; + this.value = value; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof MyObject)) return false; + + MyObject myObject = (MyObject) o; + + if (!getId().equals(myObject.getId())) return false; + if (getValue() != null ? !getValue().equals(myObject.getValue()) : myObject.getValue() != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = getId().hashCode(); + result = 31 * result + (getValue() != null ? getValue().hashCode() : 0); + return result; + } + } +} diff --git a/sdk/src/test/java/io/dapr/client/DaprHttpStub.java b/sdk/src/test/java/io/dapr/client/DaprHttpStub.java index 391c14ddf..6acad1b19 100644 --- a/sdk/src/test/java/io/dapr/client/DaprHttpStub.java +++ b/sdk/src/test/java/io/dapr/client/DaprHttpStub.java @@ -15,6 +15,11 @@ import java.util.Map; */ public class DaprHttpStub extends DaprHttp { + public static class ResponseStub extends DaprHttp.Response { + public ResponseStub(byte[] body, Map headers, int statusCode) { + super(body, headers, statusCode); + } + } /** * Instantiates a stub for DaprHttp */ @@ -24,9 +29,10 @@ public class DaprHttpStub extends DaprHttp { /** * {@inheritDoc} + * @return */ @Override - public Mono invokeAPI(String method, String urlString, Map headers) { + public Mono invokeAPI(String method, String urlString, Map headers) { return Mono.empty(); } @@ -34,7 +40,7 @@ public class DaprHttpStub extends DaprHttp { * {@inheritDoc} */ @Override - public Mono invokeAPI(String method, String urlString, String content, Map headers) { + public Mono invokeAPI(String method, String urlString, String content, Map headers) { return Mono.empty(); } @@ -42,7 +48,7 @@ public class DaprHttpStub extends DaprHttp { * {@inheritDoc} */ @Override - public Mono invokeAPI(String method, String urlString, byte[] content, Map headers) { + public Mono invokeAPI(String method, String urlString, byte[] content, Map headers) { return Mono.empty(); } } diff --git a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java index 000fc0133..99d41aec6 100644 --- a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java @@ -4,6 +4,7 @@ */ package io.dapr.client; +import io.dapr.utils.ObjectSerializer; import okhttp3.*; import okhttp3.mock.Behavior; import okhttp3.mock.MockInterceptor; @@ -24,6 +25,8 @@ public class DaprHttpTest { private MockInterceptor mockInterceptor; + private ObjectSerializer serializer = new ObjectSerializer(); + private final String EXPECTED_RESULT = "{\"data\":\"ewoJCSJwcm9wZXJ0eUEiOiAidmFsdWVBIiwKCQkicHJvcGVydHlCIjogInZhbHVlQiIKCX0=\"}"; @Before @@ -41,8 +44,10 @@ public class DaprHttpTest { DaprHttp daprHttp = new DaprHttp("http://localhost",3500,okHttpClient); - Mono mono = daprHttp.invokeAPI("POST","v1.0/state",null); - assertEquals(EXPECTED_RESULT,mono.block()); + Mono mono = daprHttp.invokeAPI("POST","v1.0/state",null); + DaprHttp.Response response = mono.block(); + String body = serializer.deserialize(response.getBody(), String.class); + assertEquals(EXPECTED_RESULT,body); } @@ -55,8 +60,10 @@ public class DaprHttpTest { DaprHttp daprHttp = new DaprHttp("http://localhost",3500,okHttpClient); - Mono mono = daprHttp.invokeAPI("DELETE","v1.0/state",null); - assertEquals(EXPECTED_RESULT,mono.block()); + Mono mono = daprHttp.invokeAPI("DELETE","v1.0/state",null); + DaprHttp.Response response = mono.block(); + String body = serializer.deserialize(response.getBody(), String.class); + assertEquals(EXPECTED_RESULT,body); } @@ -69,14 +76,15 @@ public class DaprHttpTest { DaprHttp daprHttp = new DaprHttp("http://localhost",3500,okHttpClient); - Mono mono = daprHttp.invokeAPI("GET","v1.0/get",null); - - assertEquals(EXPECTED_RESULT,mono.block()); + Mono mono = daprHttp.invokeAPI("GET","v1.0/get",null); + DaprHttp.Response response = mono.block(); + String body = serializer.deserialize(response.getBody(), String.class); + assertEquals(EXPECTED_RESULT,body); } @Test - public void invokeMethodWithHeaders() { + public void invokeMethodWithHeaders() throws IOException { Map headers = new HashMap<>(); headers.put("header","value"); @@ -87,14 +95,15 @@ public class DaprHttpTest { .respond(EXPECTED_RESULT); DaprHttp daprHttp = new DaprHttp("http://localhost",3500,okHttpClient); - Mono mono = daprHttp.invokeAPI("GET","v1.0/get",headers); - - assertEquals(EXPECTED_RESULT,mono.block()); + Mono mono = daprHttp.invokeAPI("GET","v1.0/get",headers); + DaprHttp.Response response = mono.block(); + String body = serializer.deserialize(response.getBody(), String.class); + assertEquals(EXPECTED_RESULT,body); } @Test(expected = RuntimeException.class) - public void invokeMethodRuntimeException(){ + public void invokeMethodRuntimeException() throws IOException { Map headers = new HashMap<>(); headers.put("header","value"); @@ -107,9 +116,10 @@ public class DaprHttpTest { DaprHttp daprHttp = new DaprHttp("http://localhost",3500,okHttpClient); - Mono mono = daprHttp.invokeAPI("GET","v1.0/get",headers); - - assertEquals(EXPECTED_RESULT,mono.block()); + Mono mono = daprHttp.invokeAPI("GET","v1.0/get",headers); + DaprHttp.Response response = mono.block(); + String body = serializer.deserialize(response.getBody(), String.class); + assertEquals(EXPECTED_RESULT,body); } } \ No newline at end of file diff --git a/sdk/src/test/java/io/dapr/runtime/DaprRuntimeTest.java b/sdk/src/test/java/io/dapr/runtime/DaprRuntimeTest.java index 5c4e6c5d2..c6c7f374d 100644 --- a/sdk/src/test/java/io/dapr/runtime/DaprRuntimeTest.java +++ b/sdk/src/test/java/io/dapr/runtime/DaprRuntimeTest.java @@ -204,7 +204,8 @@ public class DaprRuntimeTest { this.daprRuntime.handleInvocation( METHOD_NAME, message.data, - message.metadata)); + message.metadata) + .map(r -> new DaprHttpStub.ResponseStub(r, null, 200))); Mono response = client.invokeService(Verb.POST, APP_ID, METHOD_NAME, message.data, message.metadata); Assert.assertEquals( diff --git a/sdk-actors/src/test/java/io/dapr/actors/runtime/DurationUtilsTest.java b/sdk/src/test/java/io/dapr/utils/DurationUtilsTest.java similarity index 98% rename from sdk-actors/src/test/java/io/dapr/actors/runtime/DurationUtilsTest.java rename to sdk/src/test/java/io/dapr/utils/DurationUtilsTest.java index 8b475eef4..cf3bc057c 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/runtime/DurationUtilsTest.java +++ b/sdk/src/test/java/io/dapr/utils/DurationUtilsTest.java @@ -1,5 +1,6 @@ -package io.dapr.actors.runtime; +package io.dapr.utils; +import io.dapr.utils.DurationUtils; import org.junit.Assert; import org.junit.Test; diff --git a/sdk/src/test/java/io/dapr/utils/ObjectSerializerTest.java b/sdk/src/test/java/io/dapr/utils/ObjectSerializerTest.java index e261ca1b1..ae20dc1e8 100644 --- a/sdk/src/test/java/io/dapr/utils/ObjectSerializerTest.java +++ b/sdk/src/test/java/io/dapr/utils/ObjectSerializerTest.java @@ -174,13 +174,13 @@ public class ObjectSerializerTest { } @Test - public void serializeObjectTest() { + public void serializeStringObjectTest() { MyObjectTestToSerialize obj = new MyObjectTestToSerialize(); obj.setStringValue("A String"); obj.setIntValue(2147483647); obj.setBoolValue(true); obj.setCharValue('a'); - obj.setByteValue((byte)65); + obj.setByteValue((byte) 65); obj.setShortValue((short) 32767); obj.setLongValue(9223372036854775807L); obj.setFloatValue(1.0f); @@ -197,13 +197,42 @@ public class ObjectSerializerTest { } } + @Test + public void serializeObjectTest() { + MyObjectTestToSerialize obj = new MyObjectTestToSerialize(); + obj.setStringValue("A String"); + obj.setIntValue(2147483647); + obj.setBoolValue(true); + obj.setCharValue('a'); + obj.setByteValue((byte) 65); + obj.setShortValue((short) 32767); + obj.setLongValue(9223372036854775807L); + obj.setFloatValue(1.0f); + obj.setDoubleValue(1000.0); + //String expectedResult = "{\"stringValue\":\"A String\",\"intValue\":2147483647,\"boolValue\":true,\"charValue\":\"a\",\"byteValue\":65,\"shortValue\":32767,\"longValue\":9223372036854775807,\"floatValue\":1.0,\"doubleValue\":1000.0}"; + + ObjectSerializer serializer = new ObjectSerializer(); + byte[] serializedValue; + try { + serializedValue = serializer.serialize(obj); + assertNotNull(serializedValue); + MyObjectTestToSerialize deserializedValue = serializer.deserialize(serializedValue, MyObjectTestToSerialize.class); + assertEquals(obj, deserializedValue); + } catch (IOException exception) { + fail(exception.getMessage()); + } + } + @Test public void serializeNullTest() { ObjectSerializer serializer = new ObjectSerializer(); String serializedValue; + byte[] byteSerializedValue; try { serializedValue = serializer.serializeString(null); - assertNull("The expected result is null", serializedValue); + assertNull(serializedValue); + byteSerializedValue = serializer.serialize(null); + assertNull(byteSerializedValue); } catch (IOException exception) { fail(exception.getMessage()); } @@ -214,9 +243,14 @@ public class ObjectSerializerTest { String valueToSerialize = "A String"; ObjectSerializer serializer = new ObjectSerializer(); String serializedValue; + byte [] byteValue; try { serializedValue = serializer.serializeString(valueToSerialize); assertEquals(valueToSerialize, serializedValue); + byteValue = serializer.serialize(valueToSerialize); + assertNotNull(byteValue); + String deserializedValue = serializer.deserialize(byteValue, String.class); + assertEquals(valueToSerialize, deserializedValue); } catch (IOException exception) { fail(exception.getMessage()); } @@ -228,9 +262,109 @@ public class ObjectSerializerTest { String expectedResult = valueToSerialize.toString(); ObjectSerializer serializer = new ObjectSerializer(); String serializedValue; + byte [] byteValue; try { serializedValue = serializer.serializeString(valueToSerialize.intValue()); assertEquals(expectedResult, serializedValue); + byteValue = serializer.serialize(valueToSerialize); + assertNotNull(byteValue); + Integer deserializedValue = serializer.deserialize(byteValue, Integer.class); + assertEquals(valueToSerialize, deserializedValue); + } catch (IOException exception) { + fail(exception.getMessage()); + } + } + + @Test + public void serializeShortTest() { + Short valueToSerialize = 1; + String expectedResult = valueToSerialize.toString(); + ObjectSerializer serializer = new ObjectSerializer(); + String serializedValue; + byte [] byteValue; + try { + serializedValue = serializer.serializeString(valueToSerialize.shortValue()); + assertEquals(expectedResult, serializedValue); + byteValue = serializer.serialize(valueToSerialize); + assertNotNull(byteValue); + Short deserializedValue = serializer.deserialize(byteValue, Short.class); + assertEquals(valueToSerialize, deserializedValue); + } catch (IOException exception) { + fail(exception.getMessage()); + } + } + + @Test + public void serializeLongTest() { + Long valueToSerialize = 1L; + String expectedResult = valueToSerialize.toString(); + ObjectSerializer serializer = new ObjectSerializer(); + String serializedValue; + byte [] byteValue; + try { + serializedValue = serializer.serializeString(valueToSerialize.longValue()); + assertEquals(expectedResult, serializedValue); + byteValue = serializer.serialize(valueToSerialize); + assertNotNull(byteValue); + Long deserializedValue = serializer.deserialize(byteValue, Long.class); + assertEquals(valueToSerialize, deserializedValue); + } catch (IOException exception) { + fail(exception.getMessage()); + } + } + + @Test + public void serializeFloatTest() { + Float valueToSerialize = 1.0f; + String expectedResult = valueToSerialize.toString(); + ObjectSerializer serializer = new ObjectSerializer(); + String serializedValue; + byte [] byteValue; + try { + serializedValue = serializer.serializeString(valueToSerialize.floatValue()); + assertEquals(expectedResult, serializedValue); + byteValue = serializer.serialize(valueToSerialize); + assertNotNull(byteValue); + Float deserializedValue = serializer.deserialize(byteValue, Float.class); + assertEquals(valueToSerialize, deserializedValue); + } catch (IOException exception) { + fail(exception.getMessage()); + } + } + + @Test + public void serializeDoubleTest() { + Double valueToSerialize = 1.0; + String expectedResult = valueToSerialize.toString(); + ObjectSerializer serializer = new ObjectSerializer(); + String serializedValue; + byte [] byteValue; + try { + serializedValue = serializer.serializeString(valueToSerialize.doubleValue()); + assertEquals(expectedResult, serializedValue); + byteValue = serializer.serialize(valueToSerialize); + assertNotNull(byteValue); + Double deserializedValue = serializer.deserialize(byteValue, Double.class); + assertEquals(valueToSerialize, deserializedValue); + } catch (IOException exception) { + fail(exception.getMessage()); + } + } + + @Test + public void serializeBooleanTest() { + Boolean valueToSerialize = true; + String expectedResult = valueToSerialize.toString(); + ObjectSerializer serializer = new ObjectSerializer(); + String serializedValue; + byte [] byteValue; + try { + serializedValue = serializer.serializeString(valueToSerialize.booleanValue()); + assertEquals(expectedResult, serializedValue); + byteValue = serializer.serialize(valueToSerialize); + assertNotNull(byteValue); + Boolean deserializedValue = serializer.deserialize(byteValue, Boolean.class); + assertEquals(valueToSerialize, deserializedValue); } catch (IOException exception) { fail(exception.getMessage()); } @@ -244,7 +378,7 @@ public class ObjectSerializerTest { expectedResult.setIntValue(2147483647); expectedResult.setBoolValue(true); expectedResult.setCharValue('a'); - expectedResult.setByteValue((byte)65); + expectedResult.setByteValue((byte) 65); expectedResult.setShortValue((short) 32767); expectedResult.setLongValue(9223372036854775807L); expectedResult.setFloatValue(1.0f); @@ -259,33 +393,47 @@ public class ObjectSerializerTest { } } + @Test + public void deserializeBtyesTest() { + ObjectSerializer serializer = new ObjectSerializer(); + try { + byte[] resultStr = serializer.deserialize("String", byte[].class); + assertNotNull(resultStr); + byte[] result = serializer.deserialize("String".getBytes(), byte[].class); + assertNotNull(result); + } catch (IOException exception) { + fail(exception.getMessage()); + } + } + + @Test public void deserializeNullObjectOrPrimitiveTest() { ObjectSerializer serializer = new ObjectSerializer(); try { MyObjectTestToSerialize expectedObj = null; - MyObjectTestToSerialize objResult = serializer.deserialize(null, MyObjectTestToSerialize.class); - assertEquals(expectedObj, objResult); - boolean expectedBoolResutl = false; - boolean boolResult = serializer.deserialize(null, boolean.class); - assertEquals(expectedBoolResutl, boolResult); - byte expectedByteResult = Byte.valueOf((byte) 0); - byte byteResult = serializer.deserialize(null, byte.class); - assertEquals(expectedByteResult, byteResult); - short expectedShortResult = (short) 0; - short shortResult = serializer.deserialize(null, short.class); - assertEquals(expectedShortResult, shortResult); - int expectedIntResult = 0; - int intResult = serializer.deserialize(null, int.class); - assertEquals(expectedIntResult, intResult); - long expectedLongResult = 0L; - long longResult = serializer.deserialize(null, long.class); - assertEquals(expectedLongResult, longResult); - float expectedFloatResult = 0f; - float floatResult = serializer.deserialize(null, float.class); - assertEquals(expectedFloatResult, floatResult); - double expectedDoubleResult = (double) 0; - double doubleResult = serializer.deserialize(null, double.class); - assertEquals(expectedDoubleResult, doubleResult); + MyObjectTestToSerialize objResult = serializer.deserialize(null, MyObjectTestToSerialize.class); + assertEquals(expectedObj, objResult); + boolean expectedBoolResutl = false; + boolean boolResult = serializer.deserialize(null, boolean.class); + assertEquals(expectedBoolResutl, boolResult); + byte expectedByteResult = Byte.valueOf((byte) 0); + byte byteResult = serializer.deserialize(null, byte.class); + assertEquals(expectedByteResult, byteResult); + short expectedShortResult = (short) 0; + short shortResult = serializer.deserialize(null, short.class); + assertEquals(expectedShortResult, shortResult); + int expectedIntResult = 0; + int intResult = serializer.deserialize(null, int.class); + assertEquals(expectedIntResult, intResult); + long expectedLongResult = 0L; + long longResult = serializer.deserialize(null, long.class); + assertEquals(expectedLongResult, longResult); + float expectedFloatResult = 0f; + float floatResult = serializer.deserialize(null, float.class); + assertEquals(expectedFloatResult, floatResult, 0.0f); + double expectedDoubleResult = (double) 0; + double doubleResult = serializer.deserialize(null, double.class); + assertEquals(expectedDoubleResult, doubleResult, 0.0); } catch (IOException exception) { fail(exception.getMessage()); } @@ -298,7 +446,7 @@ public class ObjectSerializerTest { expectedResult.setIntValue(2147483647); expectedResult.setBoolValue(true); expectedResult.setCharValue('a'); - expectedResult.setByteValue((byte)65); + expectedResult.setByteValue((byte) 65); expectedResult.setShortValue((short) 32767); expectedResult.setLongValue(9223372036854775807L); expectedResult.setFloatValue(1.0f); @@ -320,7 +468,7 @@ public class ObjectSerializerTest { expectedResult.setStringValue("A String"); expectedResult.setBoolValue(true); expectedResult.setCharValue('a'); - expectedResult.setByteValue((byte)65); + expectedResult.setByteValue((byte) 65); expectedResult.setShortValue((short) 32767); expectedResult.setLongValue(9223372036854775807L); expectedResult.setFloatValue(1.0f); @@ -342,7 +490,7 @@ public class ObjectSerializerTest { expectedResult.setStringValue("A String"); expectedResult.setIntValue(2147483647); expectedResult.setCharValue('a'); - expectedResult.setByteValue((byte)65); + expectedResult.setByteValue((byte) 65); expectedResult.setShortValue((short) 32767); expectedResult.setLongValue(9223372036854775807L); expectedResult.setFloatValue(1.0f); @@ -364,7 +512,7 @@ public class ObjectSerializerTest { expectedResult.setStringValue("A String"); expectedResult.setIntValue(2147483647); expectedResult.setBoolValue(true); - expectedResult.setByteValue((byte)65); + expectedResult.setByteValue((byte) 65); expectedResult.setShortValue((short) 32767); expectedResult.setLongValue(9223372036854775807L); expectedResult.setFloatValue(1.0f); @@ -409,7 +557,7 @@ public class ObjectSerializerTest { expectedResult.setIntValue(2147483647); expectedResult.setBoolValue(true); expectedResult.setCharValue('a'); - expectedResult.setByteValue((byte)65); + expectedResult.setByteValue((byte) 65); expectedResult.setLongValue(9223372036854775807L); expectedResult.setFloatValue(1.0f); expectedResult.setDoubleValue(1000.0); @@ -431,7 +579,7 @@ public class ObjectSerializerTest { expectedResult.setIntValue(2147483647); expectedResult.setBoolValue(true); expectedResult.setCharValue('a'); - expectedResult.setByteValue((byte)65); + expectedResult.setByteValue((byte) 65); expectedResult.setShortValue((short) 32767); expectedResult.setFloatValue(1.0f); expectedResult.setDoubleValue(1000.0); @@ -453,7 +601,7 @@ public class ObjectSerializerTest { expectedResult.setIntValue(2147483647); expectedResult.setBoolValue(true); expectedResult.setCharValue('a'); - expectedResult.setByteValue((byte)65); + expectedResult.setByteValue((byte) 65); expectedResult.setShortValue((short) 32767); expectedResult.setLongValue(9223372036854775807L); expectedResult.setDoubleValue(1000.0); @@ -475,7 +623,7 @@ public class ObjectSerializerTest { expectedResult.setIntValue(2147483647); expectedResult.setBoolValue(true); expectedResult.setCharValue('a'); - expectedResult.setByteValue((byte)65); + expectedResult.setByteValue((byte) 65); expectedResult.setShortValue((short) 32767); expectedResult.setLongValue(9223372036854775807L); expectedResult.setFloatValue(1.0f); diff --git a/sdk/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/sdk/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 000000000..ca6ee9cea --- /dev/null +++ b/sdk/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline \ No newline at end of file