diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d0cce82ad8..174f69be43 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,11 +22,11 @@ jobs: GOARCH: amd64 GOPROXY: https://proxy.golang.org JDK_VER: 13.0.x - DAPR_CLI_VER: 1.0.0-rc.2 - DAPR_RUNTIME_VER: 1.0.0-rc.1 + DAPR_CLI_VER: 1.0.0-rc.3 + DAPR_RUNTIME_VER: 1.0.0-rc.2 DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/3dacfb672d55f1436c249057aaebbe597e1066f3/install/install.sh - DAPR_CLI_REF: 3dacfb672d55f1436c249057aaebbe597e1066f3 - DAPR_REF: 3cca3cc1567f1cb955ae69b8fd784f075f62ad42 + DAPR_CLI_REF: + DAPR_REF: 5a15b3e0f093d2d0938b12f144c7047474a290fe OSSRH_USER_TOKEN: ${{ secrets.OSSRH_USER_TOKEN }} OSSRH_PWD_TOKEN: ${{ secrets.OSSRH_PWD_TOKEN }} GPG_KEY: ${{ secrets.GPG_KEY }} @@ -91,8 +91,6 @@ jobs: run: | docker-compose -f ./sdk-tests/deploy/local-test-vault.yml up -d docker ps - - name: Setup Vault's test token - run: echo myroot > /tmp/.hashicorp_vault_token - name: Clean up files run: mvn clean - name: Build sdk diff --git a/examples/components/actors/redis.yaml b/examples/components/actors/redis.yaml index 064922915d..2e5d21a391 100644 --- a/examples/components/actors/redis.yaml +++ b/examples/components/actors/redis.yaml @@ -4,6 +4,7 @@ metadata: name: statestore spec: type: state.redis + version: 1 metadata: - name: redisHost value: localhost:6379 diff --git a/examples/components/bindings/kafka_bindings.yaml b/examples/components/bindings/kafka_bindings.yaml index 280e241e19..687cb61d09 100644 --- a/examples/components/bindings/kafka_bindings.yaml +++ b/examples/components/bindings/kafka_bindings.yaml @@ -4,6 +4,7 @@ metadata: name: sample123 spec: type: bindings.kafka + version: 1 metadata: # Kafka broker connection setting - name: brokers diff --git a/examples/components/pubsub/redis_messagebus.yaml b/examples/components/pubsub/redis_messagebus.yaml index ce67e58e84..de48f22b8d 100644 --- a/examples/components/pubsub/redis_messagebus.yaml +++ b/examples/components/pubsub/redis_messagebus.yaml @@ -4,6 +4,7 @@ metadata: name: messagebus spec: type: pubsub.redis + version: 1 metadata: - name: redisHost value: localhost:6379 diff --git a/examples/components/secrets/hashicorp_vault.yaml b/examples/components/secrets/hashicorp_vault.yaml index 7f52257170..c214a6e2c1 100644 --- a/examples/components/secrets/hashicorp_vault.yaml +++ b/examples/components/secrets/hashicorp_vault.yaml @@ -4,6 +4,7 @@ metadata: name: vault spec: type: secretstores.hashicorp.vault + version: 1 metadata: - name: vaultAddr value: "http://127.0.0.1:8200" diff --git a/examples/components/state/redis.yaml b/examples/components/state/redis.yaml index 064922915d..2e5d21a391 100644 --- a/examples/components/state/redis.yaml +++ b/examples/components/state/redis.yaml @@ -4,6 +4,7 @@ metadata: name: statestore spec: type: state.redis + version: 1 metadata: - name: redisHost value: localhost:6379 diff --git a/examples/pom.xml b/examples/pom.xml index f08e76236a..0947b19f2e 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -173,7 +173,7 @@ repackage - io.dapr.springboot.DaprMainApplication + io.dapr.examples.DaprMainApplication exec dapr-java-sdk-examples diff --git a/examples/src/main/java/io/dapr/springboot/DaprApplication.java b/examples/src/main/java/io/dapr/examples/DaprApplication.java similarity index 74% rename from examples/src/main/java/io/dapr/springboot/DaprApplication.java rename to examples/src/main/java/io/dapr/examples/DaprApplication.java index f97c7bc366..b0623b3d54 100644 --- a/examples/src/main/java/io/dapr/springboot/DaprApplication.java +++ b/examples/src/main/java/io/dapr/examples/DaprApplication.java @@ -3,16 +3,15 @@ * Licensed under the MIT License. */ -package io.dapr.springboot; +package io.dapr.examples; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * Dapr's HTTP callback implementation via SpringBoot. - * Scanning package io.dapr.springboot is required. */ -@SpringBootApplication(scanBasePackages = {"io.dapr.springboot", "io.dapr.examples"}) +@SpringBootApplication public class DaprApplication { /** diff --git a/examples/src/main/java/io/dapr/examples/DaprConfig.java b/examples/src/main/java/io/dapr/examples/DaprConfig.java new file mode 100644 index 0000000000..552cefe30d --- /dev/null +++ b/examples/src/main/java/io/dapr/examples/DaprConfig.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.examples; + +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class DaprConfig { + + private static final DaprClientBuilder BUILDER = new DaprClientBuilder(); + + @Bean + public DaprClient buildDaprClient() { + return BUILDER.build(); + } +} \ No newline at end of file diff --git a/examples/src/main/java/io/dapr/springboot/DaprMainApplication.java b/examples/src/main/java/io/dapr/examples/DaprMainApplication.java similarity index 97% rename from examples/src/main/java/io/dapr/springboot/DaprMainApplication.java rename to examples/src/main/java/io/dapr/examples/DaprMainApplication.java index a9eae7a8bb..7adfafbb5b 100644 --- a/examples/src/main/java/io/dapr/springboot/DaprMainApplication.java +++ b/examples/src/main/java/io/dapr/examples/DaprMainApplication.java @@ -3,7 +3,7 @@ * Licensed under the MIT License. */ -package io.dapr.springboot; +package io.dapr.examples; import java.lang.reflect.Method; import java.util.Arrays; diff --git a/examples/src/main/java/io/dapr/springboot/OpenTelemetryConfig.java b/examples/src/main/java/io/dapr/examples/OpenTelemetryConfig.java similarity index 87% rename from examples/src/main/java/io/dapr/springboot/OpenTelemetryConfig.java rename to examples/src/main/java/io/dapr/examples/OpenTelemetryConfig.java index 0be1761921..e810d48b83 100644 --- a/examples/src/main/java/io/dapr/springboot/OpenTelemetryConfig.java +++ b/examples/src/main/java/io/dapr/examples/OpenTelemetryConfig.java @@ -3,14 +3,13 @@ * Licensed under the MIT License. */ -package io.dapr.springboot; +package io.dapr.examples; import io.dapr.examples.invoke.http.InvokeClient; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.api.trace.propagation.HttpTraceContext; import io.opentelemetry.context.propagation.DefaultContextPropagators; -import io.opentelemetry.exporter.logging.LoggingSpanExporter; import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; @@ -64,10 +63,6 @@ public static Tracer createTracer(String instrumentationName) { System.out.println("WARNING: Zipkin is not available."); } - final LoggingSpanExporter loggingExporter = new LoggingSpanExporter(); - OpenTelemetrySdk.getGlobalTracerManagement() - .addSpanProcessor(SimpleSpanProcessor.builder(loggingExporter).build()); - return tracer; } diff --git a/examples/src/main/java/io/dapr/springboot/OpenTelemetryInterceptor.java b/examples/src/main/java/io/dapr/examples/OpenTelemetryInterceptor.java similarity index 52% rename from examples/src/main/java/io/dapr/springboot/OpenTelemetryInterceptor.java rename to examples/src/main/java/io/dapr/examples/OpenTelemetryInterceptor.java index 7a344240e5..ba11db1fec 100644 --- a/examples/src/main/java/io/dapr/springboot/OpenTelemetryInterceptor.java +++ b/examples/src/main/java/io/dapr/examples/OpenTelemetryInterceptor.java @@ -3,15 +3,12 @@ * Licensed under the MIT License. */ -package io.dapr.springboot; +package io.dapr.examples; import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Context; import io.opentelemetry.context.propagation.TextMapPropagator; import org.jetbrains.annotations.Nullable; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; @@ -36,8 +33,6 @@ public String get(@Nullable HttpServletRequest carrier, String key) { return carrier.getHeader(key); } }; - @Autowired - Tracer tracer; @Override public boolean preHandle( @@ -49,43 +44,15 @@ public boolean preHandle( return true; } - Span span; - try { - Context context = textFormat.extract(Context.current(), request, HTTP_SERVLET_REQUEST_GETTER); - request.setAttribute("opentelemetry-context", context); - span = tracer.spanBuilder(request.getRequestURI()).setParent(context).startSpan(); - span.setAttribute("handler", "pre"); - } catch (Exception e) { - span = tracer.spanBuilder(request.getRequestURI()).startSpan(); - span.setAttribute("handler", "pre"); - - span.addEvent(e.toString()); - span.setAttribute("error", true); - } - request.setAttribute("opentelemetry-span", span); + Context context = textFormat.extract(Context.current(), request, HTTP_SERVLET_REQUEST_GETTER); + request.setAttribute("opentelemetry-context", context); return true; } @Override public void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, - ModelAndView modelAndView) throws Exception { - } - - @Override - public void afterCompletion(HttpServletRequest request, HttpServletResponse response, - Object handler, Exception exception) { - Object contextObject = request.getAttribute("opentelemetry-context"); - Object spanObject = request.getAttribute("opentelemetry-span"); - if ((contextObject == null) || (spanObject == null)) { - return; - } - Context context = (Context) contextObject; - Span span = (Span) spanObject; - span.setAttribute("handler", "afterCompletion"); - final TextMapPropagator textFormat = OpenTelemetry.getGlobalPropagators().getTextMapPropagator(); - textFormat.inject(context, response, HttpServletResponse::addHeader); - span.end(); + ModelAndView modelAndView) { } } diff --git a/examples/src/main/java/io/dapr/springboot/OpenTelemetryInterceptorConfig.java b/examples/src/main/java/io/dapr/examples/OpenTelemetryInterceptorConfig.java similarity index 92% rename from examples/src/main/java/io/dapr/springboot/OpenTelemetryInterceptorConfig.java rename to examples/src/main/java/io/dapr/examples/OpenTelemetryInterceptorConfig.java index 3c97cc7105..f97cf3ad0a 100644 --- a/examples/src/main/java/io/dapr/springboot/OpenTelemetryInterceptorConfig.java +++ b/examples/src/main/java/io/dapr/examples/OpenTelemetryInterceptorConfig.java @@ -3,7 +3,7 @@ * Licensed under the MIT License. */ -package io.dapr.springboot; +package io.dapr.examples; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/examples/src/main/java/io/dapr/examples/actors/DemoActor.java b/examples/src/main/java/io/dapr/examples/actors/DemoActor.java index 4396598b4e..5eee1ed5a6 100644 --- a/examples/src/main/java/io/dapr/examples/actors/DemoActor.java +++ b/examples/src/main/java/io/dapr/examples/actors/DemoActor.java @@ -17,6 +17,7 @@ public interface DemoActor { void registerReminder(); + @ActorMethod(name = "echo_message") String say(String something); void clock(String message); diff --git a/examples/src/main/java/io/dapr/examples/actors/DemoActorClient.java b/examples/src/main/java/io/dapr/examples/actors/DemoActorClient.java index d25065f3b1..fb90d37cb5 100644 --- a/examples/src/main/java/io/dapr/examples/actors/DemoActorClient.java +++ b/examples/src/main/java/io/dapr/examples/actors/DemoActorClient.java @@ -6,6 +6,7 @@ package io.dapr.examples.actors; import io.dapr.actors.ActorId; +import io.dapr.actors.client.ActorClient; import io.dapr.actors.client.ActorProxyBuilder; import java.util.ArrayList; @@ -30,7 +31,8 @@ public class DemoActorClient { * @throws InterruptedException If program has been interrupted. */ public static void main(String[] args) throws InterruptedException { - try (ActorProxyBuilder builder = new ActorProxyBuilder(DemoActor.class)) { + try (ActorClient client = new ActorClient()) { + ActorProxyBuilder builder = new ActorProxyBuilder(DemoActor.class, client); List threads = new ArrayList<>(NUM_ACTORS); // Creates multiple actors. diff --git a/examples/src/main/java/io/dapr/examples/actors/DemoActorService.java b/examples/src/main/java/io/dapr/examples/actors/DemoActorService.java index aeec77e6f7..9b7d3275b9 100644 --- a/examples/src/main/java/io/dapr/examples/actors/DemoActorService.java +++ b/examples/src/main/java/io/dapr/examples/actors/DemoActorService.java @@ -6,7 +6,7 @@ package io.dapr.examples.actors; import io.dapr.actors.runtime.ActorRuntime; -import io.dapr.springboot.DaprApplication; +import io.dapr.examples.DaprApplication; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; diff --git a/examples/src/main/java/io/dapr/examples/actors/README.md b/examples/src/main/java/io/dapr/examples/actors/README.md index 3fd65bbc08..09b3a71d14 100644 --- a/examples/src/main/java/io/dapr/examples/actors/README.md +++ b/examples/src/main/java/io/dapr/examples/actors/README.md @@ -105,6 +105,8 @@ public class DemoActorImpl extends AbstractActor implements DemoActor, Remindabl An actor inherits from `AbstractActor` and implements the constructor to pass through `ActorRuntimeContext` and `ActorId`. By default, the actor's name will be the same as the class' name. Optionally, it can be annotated with `ActorType` and override the actor's name. The actor's methods can be synchronously or use [Project Reactor's Mono](https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html) return type. Finally, state management is done via methods in `super.getActorStateManager()`. The `DemoActor` interface is used by the Actor runtime and also client. See how `DemoActor` interface can be annotated as Dapr Actor. ```java +import io.dapr.actors.ActorMethod; + /** * Example of implementation of an Actor. */ @@ -113,6 +115,7 @@ public interface DemoActor { void registerReminder(); + @ActorMethod(name = "echo_message") String say(String something); void clock(String message); @@ -123,7 +126,10 @@ public interface DemoActor { ``` -The `@ActorType` annotation indicates the Dapr Java SDK that this interface is an Actor Type, allowing a name for the type to be defined. Some methods can return a `Mono` object. In these cases, the `@ActorMethod` annotation is used to hint the Dapr Java SDK of the type encapsulated in the `Mono` object. You can read more about Java generic type erasure [here](https://docs.oracle.com/javase/tutorial/java/generics/erasure.html). +The `@ActorType` annotation indicates the Dapr Java SDK that this interface is an Actor Type, allowing a name for the type to be defined. + +The `@ActorMethod` annotation can be applied to an interface method to specify configuration for that method. In this example, the `say` method, is renamed to `echo_message` - this can be used when invoking an actor method implemented in a different programming language (like C# or Python) and the method name does not match Java's naming conventions. +Some methods can return a `Mono` object. In these cases, the `@ActorMethod` annotation is used to hint the Dapr Java SDK of the type encapsulated in the `Mono` object. You can read more about Java generic type erasure [here](https://docs.oracle.com/javase/tutorial/java/generics/erasure.html). Now, execute the following script in order to run DemoActorService: @@ -143,7 +149,8 @@ public class DemoActorClient { private static final int NUM_ACTORS = 3; public static void main(String[] args) throws InterruptedException { - try (ActorProxyBuilder builder = new ActorProxyBuilder(DemoActor.class)) { + try (ActorClient client = new ActorClient()) { + ActorProxyBuilder builder = new ActorProxyBuilder(DemoActor.class, client); ///... for (int i = 0; i < NUM_ACTORS; i++) { DemoActor actor = builder.build(ActorId.createRandom()); @@ -183,7 +190,7 @@ public class DemoActorClient { } ``` -First, the client defines how many actors it is going to create. The main method declares a `ActorProxyBuilder` to create instances of the `DemoActor` interface, which are implemented automatically by the SDK and make remote calls to the equivalent methods in Actor runtime. `ActorProxyBuilder` implements `Closeable`, which means it holds resources that need to be closed. In this example, we use the "try-resource" feature in Java. +First, the client defines how many actors it is going to create. The main method declares a `ActorClient` and `ActorProxyBuilder` to create instances of the `DemoActor` interface, which are implemented automatically by the SDK and make remote calls to the equivalent methods in Actor runtime. `ActorClient` is reusable for different actor types and should be instantiated only once in your code. `ActorClient` also implements `AutoCloseable`, which means it holds resources that need to be closed. In this example, we use the "try-resource" feature in Java. Then, the code executes the `callActorForever` private method once per actor. Initially, it will invoke `registerReminder()`, which sets the due time and period for the reminder. Then, `incrementAndGet()` increments a counter, persists it and sends it back as response. Finally `say` method which will print a message containing the received string along with the formatted server time. diff --git a/examples/src/main/java/io/dapr/examples/bindings/http/InputBindingExample.java b/examples/src/main/java/io/dapr/examples/bindings/http/InputBindingExample.java index bd9ef022b7..8e44637657 100644 --- a/examples/src/main/java/io/dapr/examples/bindings/http/InputBindingExample.java +++ b/examples/src/main/java/io/dapr/examples/bindings/http/InputBindingExample.java @@ -5,7 +5,7 @@ package io.dapr.examples.bindings.http; -import io.dapr.springboot.DaprApplication; +import io.dapr.examples.DaprApplication; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; diff --git a/examples/src/main/java/io/dapr/examples/bindings/http/README.md b/examples/src/main/java/io/dapr/examples/bindings/http/README.md index 91ff90c1dc..5e0ede2f6e 100644 --- a/examples/src/main/java/io/dapr/examples/bindings/http/README.md +++ b/examples/src/main/java/io/dapr/examples/bindings/http/README.md @@ -170,4 +170,4 @@ For bringing down the kafka cluster that was started in the beginning, run docker-compose -f ./src/main/java/io/dapr/examples/bindings/http/docker-compose-single-kafka.yml down ``` -For more details on Dapr Spring Boot integration, please refer to [Dapr Spring Boot](../../../springboot/DaprApplication.java) Application implementation. +For more details on Dapr Spring Boot integration, please refer to [Dapr Spring Boot](../../DaprApplication.java) Application implementation. diff --git a/examples/src/main/java/io/dapr/examples/exception/README.md b/examples/src/main/java/io/dapr/examples/exception/README.md index 4ba5ef27b1..eb0fef99cc 100644 --- a/examples/src/main/java/io/dapr/examples/exception/README.md +++ b/examples/src/main/java/io/dapr/examples/exception/README.md @@ -53,7 +53,7 @@ public class Client { } ``` -The code uses the `DaprClient` created by the `DaprClientBuilder`. It tries to get a state from state store but provides an unknown state store. It causes Dapr sidecar to return error, which is converted to a `DaprException` to the application. To be compatible with Project Reactor, `DaprException` extends from `RuntimeException` - making it an unchecked exception. +The code uses the `DaprClient` created by the `DaprClientBuilder`. It tries to get a state from state store but provides an unknown state store. It causes Dapr sidecar to return error, which is converted to a `DaprException` to the application. To be compatible with Project Reactor, `DaprException` extends from `RuntimeException` - making it an unchecked exception. Applications might also get `IllegalArgumentException` when invoking methods with invalid input parameters that are validated at the client side. The Dapr client is also within a try-with-resource block to properly close the client at the end. diff --git a/examples/src/main/java/io/dapr/examples/invoke/grpc/HelloWorldClient.java b/examples/src/main/java/io/dapr/examples/invoke/grpc/HelloWorldClient.java index c63d51f420..c39ff140f6 100644 --- a/examples/src/main/java/io/dapr/examples/invoke/grpc/HelloWorldClient.java +++ b/examples/src/main/java/io/dapr/examples/invoke/grpc/HelloWorldClient.java @@ -33,7 +33,7 @@ public static void main(String[] args) throws Exception { while (true) { String message = "Message #" + (count++); System.out.println("Sending message: " + message); - client.invokeService(serviceAppId, method, message, HttpExtension.NONE).block(); + client.invokeMethod(serviceAppId, method, message, HttpExtension.NONE).block(); System.out.println("Message sent: " + message); Thread.sleep(1000); diff --git a/examples/src/main/java/io/dapr/examples/invoke/grpc/HelloWorldService.java b/examples/src/main/java/io/dapr/examples/invoke/grpc/HelloWorldService.java index c63b0b29e5..b08a8104fa 100644 --- a/examples/src/main/java/io/dapr/examples/invoke/grpc/HelloWorldService.java +++ b/examples/src/main/java/io/dapr/examples/invoke/grpc/HelloWorldService.java @@ -8,7 +8,6 @@ import com.google.protobuf.Any; import io.dapr.v1.AppCallbackGrpc; import io.dapr.v1.CommonProtos; -import io.dapr.v1.DaprAppCallbackProtos; import io.grpc.Server; import io.grpc.ServerBuilder; import io.grpc.stub.StreamObserver; diff --git a/examples/src/main/java/io/dapr/examples/invoke/grpc/README.md b/examples/src/main/java/io/dapr/examples/invoke/grpc/README.md index 7b3f541923..faa3e8e29c 100644 --- a/examples/src/main/java/io/dapr/examples/invoke/grpc/README.md +++ b/examples/src/main/java/io/dapr/examples/invoke/grpc/README.md @@ -96,7 +96,7 @@ private static class HelloWorldClient { while (true) { String message = "Message #" + (count++); System.out.println("Sending message: " + message); - client.invokeService(serviceAppId, method, message, HttpExtension.NONE).block(); + client.invokeMethod(serviceAppId, method, message, HttpExtension.NONE).block(); System.out.println("Message sent: " + message); Thread.sleep(1000); @@ -113,7 +113,7 @@ private static class HelloWorldClient { First, it creates an instance of `DaprClient` via `DaprClientBuilder`. The protocol used by DaprClient is transparent to the application. The HTTP and GRPC ports used by Dapr's sidecar are automatically chosen and exported as environment variables: `DAPR_HTTP_PORT` and `DAPR_GRPC_PORT`. Dapr's Java SDK references these environment variables when communicating to Dapr's sidecar. The Dapr client is also within a try-with-resource block to properly close the client at the end. -Finally, it will go through in an infinite loop and invoke the `say` method every second. Notice the use of `block()` on the return from `invokeService` - it is required to actually make the service invocation via a [Mono](https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html) object. +Finally, it will go through in an infinite loop and invoke the `say` method every second. Notice the use of `block()` on the return from `invokeMethod` - it is required to actually make the service invocation via a [Mono](https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html) object. Finally, open a new command line terminal and run the client code to send some messages. diff --git a/examples/src/main/java/io/dapr/examples/invoke/http/DemoService.java b/examples/src/main/java/io/dapr/examples/invoke/http/DemoService.java index 6b64919673..f4ccd94c77 100644 --- a/examples/src/main/java/io/dapr/examples/invoke/http/DemoService.java +++ b/examples/src/main/java/io/dapr/examples/invoke/http/DemoService.java @@ -5,7 +5,7 @@ package io.dapr.examples.invoke.http; -import io.dapr.springboot.DaprApplication; +import io.dapr.examples.DaprApplication; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; diff --git a/examples/src/main/java/io/dapr/examples/invoke/http/InvokeClient.java b/examples/src/main/java/io/dapr/examples/invoke/http/InvokeClient.java index 71aae719ff..3ed2ec7100 100644 --- a/examples/src/main/java/io/dapr/examples/invoke/http/InvokeClient.java +++ b/examples/src/main/java/io/dapr/examples/invoke/http/InvokeClient.java @@ -32,7 +32,7 @@ public class InvokeClient { public static void main(String[] args) throws Exception { try (DaprClient client = (new DaprClientBuilder()).build()) { for (String message : args) { - byte[] response = client.invokeService(SERVICE_APP_ID, "say", message, HttpExtension.POST, null, + byte[] response = client.invokeMethod(SERVICE_APP_ID, "say", message, HttpExtension.POST, null, byte[].class).block(); System.out.println(new String(response)); } diff --git a/examples/src/main/java/io/dapr/examples/invoke/http/README.md b/examples/src/main/java/io/dapr/examples/invoke/http/README.md index 050bf41d19..c4a73f1aef 100644 --- a/examples/src/main/java/io/dapr/examples/invoke/http/README.md +++ b/examples/src/main/java/io/dapr/examples/invoke/http/README.md @@ -113,7 +113,7 @@ private static final String SERVICE_APP_ID = "invokedemo"; public static void main(String[] args) throws Exception { try (DaprClient client = (new DaprClientBuilder()).build()) { for (String message : args) { - byte[] response = client.invokeService(SERVICE_APP_ID, "say", message, HttpExtension.POST, null, + byte[] response = client.invokeMethod(SERVICE_APP_ID, "say", message, HttpExtension.POST, null, byte[].class).block(); System.out.println(new String(response)); } @@ -127,7 +127,7 @@ public static void main(String[] args) throws Exception { } ``` -The class knows the app id for the remote application. It uses the the static `Dapr.getInstance().invokeService` method to invoke the remote method defining the parameters: The verb, application id, method name, and proper data and metadata, as well as the type of the expected return type. The returned payload for this method invocation is plain text and not a [JSON String](https://www.w3schools.com/js/js_json_datatypes.asp), so we expect `byte[]` to get the raw response and not try to deserialize it. +The class knows the app id for the remote application. It uses the the static `Dapr.getInstance().invokeMethod` method to invoke the remote method defining the parameters: The verb, application id, method name, and proper data and metadata, as well as the type of the expected return type. The returned payload for this method invocation is plain text and not a [JSON String](https://www.w3schools.com/js/js_json_datatypes.asp), so we expect `byte[]` to get the raw response and not try to deserialize it. Execute the follow script in order to run the InvokeClient example, passing two messages for the remote method: ```sh @@ -139,4 +139,4 @@ Once running, the output should display the messages sent from invoker in the de Method have been remotely invoked and displaying the remote messages. -For more details on Dapr Spring Boot integration, please refer to [Dapr Spring Boot](../../../springboot/DaprApplication.java) Application implementation. +For more details on Dapr Spring Boot integration, please refer to [Dapr Spring Boot](../../DaprApplication.java) Application implementation. diff --git a/examples/src/main/java/io/dapr/examples/pubsub/http/Publisher.java b/examples/src/main/java/io/dapr/examples/pubsub/http/Publisher.java index ccd272efc5..27b28cba3f 100644 --- a/examples/src/main/java/io/dapr/examples/pubsub/http/Publisher.java +++ b/examples/src/main/java/io/dapr/examples/pubsub/http/Publisher.java @@ -7,9 +7,9 @@ import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; +import io.dapr.client.domain.Metadata; -import java.io.IOException; -import java.util.Collections; +import static java.util.Collections.singletonMap; /** * Message publisher. @@ -22,12 +22,16 @@ */ public class Publisher { - //Number of messages to be sent: 10 + //Number of messages to be sent. private static final int NUM_MESSAGES = 10; + + //Time-to-live for messages published. + private static final String MESSAGE_TTL_IN_SECONDS = "1000"; + //The title of the topic to be used for publishing private static final String TOPIC_NAME = "testingtopic"; - //The name of the pubseb + //The name of the pubsub private static final String PUBSUB_NAME = "messagebus"; /** @@ -41,7 +45,11 @@ public static void main(String[] args) throws Exception { for (int i = 0; i < NUM_MESSAGES; i++) { String message = String.format("This is message #%d", i); //Publishing messages - client.publishEvent(PUBSUB_NAME, TOPIC_NAME, message).block(); + client.publishEvent( + PUBSUB_NAME, + TOPIC_NAME, + message, + singletonMap(Metadata.TTL_IN_SECONDS, MESSAGE_TTL_IN_SECONDS)).block(); System.out.println("Published message: " + message); try { @@ -53,14 +61,6 @@ public static void main(String[] args) throws Exception { } } - //Publishing a single bite: Example of non-string based content published - client.publishEvent( - PUBSUB_NAME, - TOPIC_NAME, - new byte[]{1}, - Collections.singletonMap("content-type", "application/octet-stream")).block(); - System.out.println("Published one byte."); - // This is an example, so for simplicity we are just exiting here. // Normally a dapr app would be a web service and not exit main. System.out.println("Done."); diff --git a/examples/src/main/java/io/dapr/examples/pubsub/http/README.md b/examples/src/main/java/io/dapr/examples/pubsub/http/README.md index c76a67c5d2..38b62eb78e 100644 --- a/examples/src/main/java/io/dapr/examples/pubsub/http/README.md +++ b/examples/src/main/java/io/dapr/examples/pubsub/http/README.md @@ -135,14 +135,112 @@ dapr run --components-path ./components/pubsub --app-id publisher -- java -jar t Once running, the Publisher should print the output as follows: -![publisheroutput](../../../../../../resources/img/publisher.png) +```txt +✅ You're up and running! Both Dapr and your app logs will appear here. + +== APP == Published message: This is message #0 + +== APP == Published message: This is message #1 + +== APP == Published message: This is message #2 + +== APP == Published message: This is message #3 + +== APP == Published message: This is message #4 + +== APP == Published message: This is message #5 + +== APP == Published message: This is message #6 + +== APP == Published message: This is message #7 + +== APP == Published message: This is message #8 + +== APP == Published message: This is message #9 + +== APP == Done. + +``` Messages have been published in the topic. Once running, the Subscriber should print the output as follows: -![publisheroutput](../../../../../../resources/img/subscriber.png) +```txt +== APP == Subscriber got: {"id":"1f646657-0032-4797-b59b-c57b4f40743b","source":"publisher","type":"com.dapr.event.sent","specversion":"1.0","datacontenttype":"application/json","data":"This is message #3","expiration":"2020-12-24T05:29:12Z"} + +== APP == Subscriber got: {"id":"a22b97ce-9008-4fba-8b57-c3c3e1f031b6","source":"publisher","type":"com.dapr.event.sent","specversion":"1.0","datacontenttype":"application/json","data":"This is message #8","expiration":"2020-12-24T05:29:15Z"} + +== APP == Subscriber got: {"id":"abb2f110-6862-49f7-8c8d-189f6dcd177d","source":"publisher","type":"com.dapr.event.sent","specversion":"1.0","datacontenttype":"application/json","data":"This is message #0","expiration":"2020-12-24T05:29:11Z"} + +== APP == Subscriber got: {"id":"043f31d3-c13a-4a02-ac89-64ecca946598","source":"publisher","type":"com.dapr.event.sent","specversion":"1.0","datacontenttype":"application/json","data":"This is message #7","expiration":"2020-12-24T05:29:14Z"} + +== APP == Subscriber got: {"id":"acc554f4-7109-4c31-9374-0e5936b90180","source":"publisher","type":"com.dapr.event.sent","specversion":"1.0","datacontenttype":"application/json","data":"This is message #2","expiration":"2020-12-24T05:29:12Z"} + +== APP == Subscriber got: {"id":"8b3ad160-368d-4b0f-9925-8fa2a2fbf5ca","source":"publisher","type":"com.dapr.event.sent","specversion":"1.0","datacontenttype":"application/json","data":"This is message #9","expiration":"2020-12-24T05:29:15Z"} + +== APP == Subscriber got: {"id":"e41d4512-511a-4a2b-80f3-a0a4d091c9a5","source":"publisher","type":"com.dapr.event.sent","specversion":"1.0","datacontenttype":"application/json","data":"This is message #1","expiration":"2020-12-24T05:29:11Z"} + +== APP == Subscriber got: {"id":"33e21664-128e-4fc4-b5c4-ed257f758336","source":"publisher","type":"com.dapr.event.sent","specversion":"1.0","datacontenttype":"application/json","data":"This is message #4","expiration":"2020-12-24T05:29:13Z"} + +== APP == Subscriber got: {"id":"bd14f1ee-ca6b-47f7-8130-dd1e6de5b03c","source":"publisher","type":"com.dapr.event.sent","specversion":"1.0","datacontenttype":"application/json","data":"This is message #6","expiration":"2020-12-24T05:29:14Z"} + +== APP == Subscriber got: {"id":"acc57cd6-71da-4ba3-9a12-9c921ca49af7","source":"publisher","type":"com.dapr.event.sent","specversion":"1.0","datacontenttype":"application/json","data":"This is message #5","expiration":"2020-12-24T05:29:13Z"} + +``` Messages have been retrieved from the topic. -For more details on Dapr Spring Boot integration, please refer to [Dapr Spring Boot](../../../springboot/DaprApplication.java) Application implementation. +### Message expiration (Optional) + +Optionally, you can see how Dapr can automatically drop expired messages on behalf of the subscriber. +First, make sure the publisher and the subscriber applications are stopped. +Then, change the TTL constant in the `Publisher.java` file from: +```java +private static final String MESSAGE_TTL_IN_SECONDS = "1000"; +``` +To: +```java +private static final String MESSAGE_TTL_IN_SECONDS = "1"; +``` + +Now rebuild the example: +```sh +mvn install +``` + +Run the publisher app: +```sh +dapr run --components-path ./components/pubsub --app-id publisher -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.http.Publisher +``` + +Wait until all 10 messages are published like before, then wait for a few more seconds and run the subscriber app: +```sh +dapr run --components-path ./components/pubsub --app-id subscriber --app-port 3000 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.http.Subscriber -p 3000 +``` + +No message is consumed by the subscriber app and warnings messages are emitted from Dapr sidecar: +```txt +== DAPR == time="2020-12-23T21:21:59.085797-08:00" level=warning msg="dropping expired pub/sub event 461546c1-d2df-42bd-a6b8-3beeb952fe1e as of 2020-12-24T05:21:50Z" app_id=subscriber instance=myhost scope=dapr.runtime type=log ver=edge + +== DAPR == time="2020-12-23T21:21:59.085841-08:00" level=warning msg="dropping expired pub/sub event 2d8cf9a6-4019-4dda-95fd-59218a19381b as of 2020-12-24T05:21:48Z" app_id=subscriber instance=myhost scope=dapr.runtime type=log ver=edge + +== DAPR == time="2020-12-23T21:21:59.085871-08:00" level=warning msg="dropping expired pub/sub event d2a199e0-a4b8-4067-9618-6688391ad68f as of 2020-12-24T05:21:53Z" app_id=subscriber instance=myhost scope=dapr.runtime type=log ver=edge + +== DAPR == time="2020-12-23T21:21:59.085894-08:00" level=warning msg="dropping expired pub/sub event 30719f17-ad8f-4dea-91b5-b77958f360d4 as of 2020-12-24T05:21:49Z" app_id=subscriber instance=myhost scope=dapr.runtime type=log ver=edge + +== DAPR == time="2020-12-23T21:21:59.085797-08:00" level=warning msg="dropping expired pub/sub event d136d5ae-5561-418c-a850-9d1698bc8840 as of 2020-12-24T05:21:51Z" app_id=subscriber instance=myhost scope=dapr.runtime type=log ver=edge + +== DAPR == time="2020-12-23T21:21:59.085958-08:00" level=warning msg="dropping expired pub/sub event 82b334a2-e295-48ea-8c6c-c45b1c4fcd2d as of 2020-12-24T05:21:50Z" app_id=subscriber instance=myhost scope=dapr.runtime type=log ver=edge + +== DAPR == time="2020-12-23T21:21:59.085973-08:00" level=warning msg="dropping expired pub/sub event f6eb3f9f-185f-492f-9df9-45af8c91932b as of 2020-12-24T05:21:53Z" app_id=subscriber instance=myhost scope=dapr.runtime type=log ver=edge + +== DAPR == time="2020-12-23T21:21:59.086041-08:00" level=warning msg="dropping expired pub/sub event a536eb9f-34e0-49fc-ba29-a34854398d96 as of 2020-12-24T05:21:52Z" app_id=subscriber instance=myhost scope=dapr.runtime type=log ver=edge + +== DAPR == time="2020-12-23T21:21:59.085995-08:00" level=warning msg="dropping expired pub/sub event 52cc9528-f9d4-44f4-8f78-8f32341a743a as of 2020-12-24T05:21:49Z" app_id=subscriber instance=myhost scope=dapr.runtime type=log ver=edge + +== DAPR == time="2020-12-23T21:21:59.085797-08:00" level=warning msg="dropping expired pub/sub event 7cf927e8-e832-4f8a-911a-1cae5a1369d2 as of 2020-12-24T05:21:48Z" app_id=subscriber instance=myhost scope=dapr.runtime type=log ver=edge + +``` + +For more details on Dapr Spring Boot integration, please refer to [Dapr Spring Boot](../../DaprApplication.java) Application implementation. diff --git a/examples/src/main/java/io/dapr/examples/pubsub/http/Subscriber.java b/examples/src/main/java/io/dapr/examples/pubsub/http/Subscriber.java index 6fb172c637..8f1be8d5cd 100644 --- a/examples/src/main/java/io/dapr/examples/pubsub/http/Subscriber.java +++ b/examples/src/main/java/io/dapr/examples/pubsub/http/Subscriber.java @@ -5,7 +5,7 @@ package io.dapr.examples.pubsub.http; -import io.dapr.springboot.DaprApplication; +import io.dapr.examples.DaprApplication; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; diff --git a/examples/src/main/java/io/dapr/examples/pubsub/http/SubscriberController.java b/examples/src/main/java/io/dapr/examples/pubsub/http/SubscriberController.java index 18f32dcd84..2db835f0ae 100644 --- a/examples/src/main/java/io/dapr/examples/pubsub/http/SubscriberController.java +++ b/examples/src/main/java/io/dapr/examples/pubsub/http/SubscriberController.java @@ -5,40 +5,33 @@ package io.dapr.examples.pubsub.http; +import com.fasterxml.jackson.databind.ObjectMapper; import io.dapr.Topic; import io.dapr.client.domain.CloudEvent; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; -import java.util.Map; - /** * SpringBoot Controller to handle input binding. */ @RestController public class SubscriberController { + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + /** * Handles a registered publish endpoint on this app. - * @param body The body of the http message. - * @param headers The headers of the http message. + * @param cloudEvent The cloud event received. * @return A message containing the time. */ @Topic(name = "testingtopic", pubsubName = "messagebus") @PostMapping(path = "/testingtopic") - public Mono handleMessage(@RequestBody(required = false) byte[] body, - @RequestHeader Map headers) { + public Mono handleMessage(@RequestBody(required = false) CloudEvent cloudEvent) { return Mono.fromRunnable(() -> { try { - // Dapr's event is compliant to CloudEvent. - CloudEvent envelope = CloudEvent.deserialize(body); - - String message = envelope.getData() == null ? "" : envelope.getData(); - System.out.println("Subscriber got message: " + message); + System.out.println("Subscriber got: " + OBJECT_MAPPER.writeValueAsString(cloudEvent)); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/examples/src/main/java/io/dapr/examples/secrets/SecretClient.java b/examples/src/main/java/io/dapr/examples/secrets/SecretClient.java index d739ca35b5..58e33ce694 100644 --- a/examples/src/main/java/io/dapr/examples/secrets/SecretClient.java +++ b/examples/src/main/java/io/dapr/examples/secrets/SecretClient.java @@ -9,7 +9,6 @@ import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; -import java.io.IOException; import java.util.Map; /** diff --git a/examples/src/main/java/io/dapr/examples/state/README.md b/examples/src/main/java/io/dapr/examples/state/README.md index b84d738a12..5caeb61049 100644 --- a/examples/src/main/java/io/dapr/examples/state/README.md +++ b/examples/src/main/java/io/dapr/examples/state/README.md @@ -43,6 +43,10 @@ public class StateClient { ///... public static void main(String[] args) throws Exception { try (DaprClient client = new DaprClientBuilder().build()) { + System.out.println("Waiting for Dapr sidecar ..."); + client.waitForSidecar(10000).block(); + System.out.println("Dapr sidecar is ready."); + String message = args.length == 0 ? " " : args[0]; MyClass myClass = new MyClass(); @@ -67,7 +71,7 @@ public class StateClient { operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT, new State<>(secondState, SECOND_KEY_NAME, ""))); - client.executeTransaction(STATE_STORE_NAME, operationList).block(); + client.executeStateTransaction(STATE_STORE_NAME, operationList).block(); // get multiple states Mono>> retrievedMessagesMono = client.getStates(STATE_STORE_NAME, @@ -76,17 +80,30 @@ public class StateClient { retrievedMessagesMono.block().forEach(System.out::println); System.out.println("Deleting states..."); - + + System.out.println("Verify delete key request is aborted if an etag different from stored is passed."); // delete state API - Mono mono = client.deleteState(STATE_STORE_NAME, FIRST_KEY_NAME); - mono.block(); + try { + client.deleteState(STATE_STORE_NAME, FIRST_KEY_NAME, "100", null).block(); + } catch (DaprException ex) { + if (ex.getErrorCode().equals(Status.Code.ABORTED.toString())) { + // Expected error due to etag mismatch. + System.out.println(String.format("Expected failure. %s ", ex.getMessage())); + } else { + System.out.println("Unexpected exception."); + throw ex; + } + } + + System.out.println("Trying to delete again with correct etag."); + String storedEtag = client.getState(STATE_STORE_NAME, FIRST_KEY_NAME, MyClass.class).block().getEtag(); + client.deleteState(STATE_STORE_NAME, FIRST_KEY_NAME, storedEtag, null).block(); // Delete operation using transaction API operationList.clear(); operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.DELETE, new State<>(SECOND_KEY_NAME))); - mono = client.executeTransaction(STATE_STORE_NAME, operationList); - mono.block(); + client.executeStateTransaction(STATE_STORE_NAME, operationList).block(); Mono>> retrievedDeletedMessageMono = client.getStates(STATE_STORE_NAME, Arrays.asList(FIRST_KEY_NAME, SECOND_KEY_NAME), MyClass.class); @@ -102,13 +119,14 @@ public class StateClient { ``` The code uses the `DaprClient` created by the `DaprClientBuilder`. Notice that this builder uses default settings. Internally, it is using `DefaultObjectSerializer` for two properties: `objectSerializer` is for Dapr's sent and received objects, and `stateSerializer` is for objects to be persisted. -This example performs multiple operations: +This example performs multiple operations: +* `client.waitForSidecar(...)` for waiting until Dapr sidecar is ready. * `client.saveState(...)` for persisting an instance of `MyClass`. * `client.getState(...)` operation in order to retrieve back the persisted state using the same key. -* `client.executeTransaction(...)` operation in order to update existing state and add new state. -* `client.getStates(...)` operation in order to retrieve back the persisted states using the same keys. -* `client.deleteState(...)` operation to remove one of the persisted states. -* `client.executeTransaction(...)` operation in order to remove the other persisted state. +* `client.executeStateTransaction(...)` operation in order to update existing state and add new state. +* `client.getBulkState(...)` operation in order to retrieve back the persisted states using the same keys. +* `client.deleteState(...)` operation to remove one of the persisted states. An example of etag mismatch error if a different than current etag is added to request. +* `client.executeStateTransaction(...)` operation in order to remove the other persisted state. Finally, the code tries to retrieve the deleted states, which should not be found. diff --git a/examples/src/main/java/io/dapr/examples/state/StateClient.java b/examples/src/main/java/io/dapr/examples/state/StateClient.java index bff742df09..b135d69226 100644 --- a/examples/src/main/java/io/dapr/examples/state/StateClient.java +++ b/examples/src/main/java/io/dapr/examples/state/StateClient.java @@ -9,6 +9,8 @@ import io.dapr.client.DaprClientBuilder; import io.dapr.client.domain.State; import io.dapr.client.domain.TransactionalStateOperation; +import io.dapr.exceptions.DaprException; +import io.grpc.Status; import reactor.core.publisher.Mono; import java.util.ArrayList; @@ -46,6 +48,10 @@ public String toString() { */ public static void main(String[] args) throws Exception { try (DaprClient client = new DaprClientBuilder().build()) { + System.out.println("Waiting for Dapr sidecar ..."); + client.waitForSidecar(10000).block(); + System.out.println("Dapr sidecar is ready."); + String message = args.length == 0 ? " " : args[0]; MyClass myClass = new MyClass(); @@ -70,28 +76,40 @@ public static void main(String[] args) throws Exception { operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT, new State<>(secondState, SECOND_KEY_NAME, ""))); - client.executeTransaction(STATE_STORE_NAME, operationList).block(); + client.executeStateTransaction(STATE_STORE_NAME, operationList).block(); // get multiple states - Mono>> retrievedMessagesMono = client.getStates(STATE_STORE_NAME, + Mono>> retrievedMessagesMono = client.getBulkState(STATE_STORE_NAME, Arrays.asList(FIRST_KEY_NAME, SECOND_KEY_NAME), MyClass.class); System.out.println("Retrieved messages using bulk get:"); retrievedMessagesMono.block().forEach(System.out::println); System.out.println("Deleting states..."); + System.out.println("Verify delete key request is aborted if an etag different from stored is passed."); // delete state API - Mono mono = client.deleteState(STATE_STORE_NAME, FIRST_KEY_NAME); - mono.block(); - + try { + client.deleteState(STATE_STORE_NAME, FIRST_KEY_NAME, "100", null).block(); + } catch (DaprException ex) { + if (ex.getErrorCode().equals(Status.Code.ABORTED.toString())) { + // Expected error due to etag mismatch. + System.out.println(String.format("Expected failure. %s ", ex.getMessage())); + } else { + System.out.println("Unexpected exception."); + throw ex; + } + } + + System.out.println("Trying to delete again with correct etag."); + String storedEtag = client.getState(STATE_STORE_NAME, FIRST_KEY_NAME, MyClass.class).block().getEtag(); + client.deleteState(STATE_STORE_NAME, FIRST_KEY_NAME, storedEtag, null).block(); // Delete operation using transaction API operationList.clear(); operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.DELETE, new State<>(SECOND_KEY_NAME))); - mono = client.executeTransaction(STATE_STORE_NAME, operationList); - mono.block(); + client.executeStateTransaction(STATE_STORE_NAME, operationList).block(); - Mono>> retrievedDeletedMessageMono = client.getStates(STATE_STORE_NAME, + Mono>> retrievedDeletedMessageMono = client.getBulkState(STATE_STORE_NAME, Arrays.asList(FIRST_KEY_NAME, SECOND_KEY_NAME), MyClass.class); System.out.println("Trying to retrieve deleted states: "); retrievedDeletedMessageMono.block().forEach(System.out::println); diff --git a/examples/src/main/java/io/dapr/examples/tracing/InvokeClient.java b/examples/src/main/java/io/dapr/examples/tracing/InvokeClient.java index a18e262b03..264c7ae8a4 100644 --- a/examples/src/main/java/io/dapr/examples/tracing/InvokeClient.java +++ b/examples/src/main/java/io/dapr/examples/tracing/InvokeClient.java @@ -8,9 +8,9 @@ import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; import io.dapr.client.domain.HttpExtension; -import io.dapr.client.domain.InvokeServiceRequest; -import io.dapr.client.domain.InvokeServiceRequestBuilder; -import io.dapr.springboot.OpenTelemetryConfig; +import io.dapr.client.domain.InvokeMethodRequest; +import io.dapr.client.domain.InvokeMethodRequestBuilder; +import io.dapr.examples.OpenTelemetryConfig; import io.dapr.utils.TypeRef; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; @@ -31,7 +31,7 @@ public class InvokeClient { /** * Identifier in Dapr for the service this client will invoke. */ - private static final String SERVICE_APP_ID = "tracingdemo"; + private static final String SERVICE_APP_ID = "tracingdemoproxy"; /** * Starts the invoke client. @@ -45,19 +45,19 @@ public static void main(String[] args) throws Exception { try (DaprClient client = (new DaprClientBuilder()).build()) { for (String message : args) { try (Scope scope = span.makeCurrent()) { - InvokeServiceRequestBuilder builder = new InvokeServiceRequestBuilder(SERVICE_APP_ID, "echo"); - InvokeServiceRequest request + InvokeMethodRequestBuilder builder = new InvokeMethodRequestBuilder(SERVICE_APP_ID, "proxy_echo"); + InvokeMethodRequest request = builder.withBody(message).withHttpExtension(HttpExtension.POST).withContext(Context.current()).build(); - client.invokeService(request, TypeRef.get(byte[].class)) + client.invokeMethod(request, TypeRef.get(byte[].class)) .map(r -> { System.out.println(new String(r.getObject())); return r; }) .flatMap(r -> { - InvokeServiceRequest sleepRequest = new InvokeServiceRequestBuilder(SERVICE_APP_ID, "sleep") + InvokeMethodRequest sleepRequest = new InvokeMethodRequestBuilder(SERVICE_APP_ID, "proxy_sleep") .withHttpExtension(HttpExtension.POST) .withContext(r.getContext()).build(); - return client.invokeService(sleepRequest, TypeRef.get(Void.class)); + return client.invokeMethod(sleepRequest, TypeRef.get(Void.class)); }).block(); } } diff --git a/examples/src/main/java/io/dapr/examples/tracing/README.md b/examples/src/main/java/io/dapr/examples/tracing/README.md index 3bff3cad54..6d0338bc56 100644 --- a/examples/src/main/java/io/dapr/examples/tracing/README.md +++ b/examples/src/main/java/io/dapr/examples/tracing/README.md @@ -3,7 +3,9 @@ In this sample, we'll create two java applications: a service application, which exposes two methods, and a client application which will invoke the methods from the service using Dapr. This sample includes: -* TracingDemoService (Exposes the method to be remotely accessed) +* TracingDemoService (Exposes the methods to be remotely accessed) +* TracingDemoServiceController (Implements two methods: `echo` and `sleep`) +* TracingDemoMiddleServiceController (Implements two methods: `proxy_echo` and `proxy_sleep`) * InvokeClient (Invokes the exposed methods from TracingDemoService) Also consider [getting started with observability in Dapr](https://github.com/dapr/quickstarts/tree/master/observability). @@ -54,7 +56,7 @@ CONTAINER ID IMAGE COMMAND CREATED If Zipkin is not working, [install the newest version of Dapr Cli and initialize it](https://github.com/dapr/cli#install-dapr-on-your-local-machine-self-hosted). -### Running the Demo service sample +### Running the Demo service app The Demo service application exposes two methods that can be remotely invoked. In this example, the service code has two parts: @@ -82,11 +84,11 @@ This Rest Controller exposes the `echo` and `sleep` methods. The `echo` method r public class TracingDemoServiceController { ///... @PostMapping(path = "/echo") - public Mono handleMethod(@RequestBody(required = false) byte[] body, + public Mono handleMethod(@RequestBody(required = false) String body, @RequestHeader Map headers) { return Mono.fromSupplier(() -> { try { - String message = body == null ? "" : new String(body, StandardCharsets.UTF_8); + String message = body == null ? "" : body; Calendar utcNow = Calendar.getInstance(TimeZone.getTimeZone("GMT")); String utcNowAsString = DATE_FORMAT.format(utcNow.getTime()); @@ -95,7 +97,7 @@ public class TracingDemoServiceController { // Handles the request by printing message. System.out.println( - "Server: " + message + " @ " + utcNowAsString + " and metadata: " + metadataString); + "Server: " + message + " @ " + utcNowAsString + " and metadata: " + metadataString); return utcNowAsString; } catch (Exception e) { @@ -130,15 +132,67 @@ dapr run --app-id tracingdemo --app-port 3000 -- java -jar target/dapr-java-sdk- Once running, the TracingDemoService is now ready to be invoked by Dapr. +### Running the Demo middle service app -### Running the InvokeClient sample +This service will handle the `proxy_echo` and `proxy_sleep` methods and invoke the corresponding methods in the service above. +In the code below, the `opentelemetry-context` attribute is used to propagate the tracing context among service invocations in multiple layers. -This sample code uses the Dapr SDK for invoking two remote methods (`echo` and `sleep`). It is also instrumented with OpenTelemetry. See the code snippet below: +```java +@RestController +public class TracingDemoMiddleServiceController { + // ... + @PostMapping(path = "/proxy_echo") + public Mono echo( + @RequestAttribute(name = "opentelemetry-context") Context context, + @RequestBody(required = false) String body) { + InvokeServiceRequestBuilder builder = new InvokeServiceRequestBuilder(INVOKE_APP_ID, "echo"); + InvokeServiceRequest request + = builder.withBody(body).withHttpExtension(HttpExtension.POST).withContext(context).build(); + return client.invokeMethod(request, TypeRef.get(byte[].class)).map(r -> r.getObject()); + } + // ... + @PostMapping(path = "/proxy_sleep") + public Mono sleep(@RequestAttribute(name = "opentelemetry-context") Context context) { + InvokeServiceRequestBuilder builder = new InvokeServiceRequestBuilder(INVOKE_APP_ID, "sleep"); + InvokeServiceRequest request = builder.withHttpExtension(HttpExtension.POST).withContext(context).build(); + return client.invokeMethod(request, TypeRef.get(byte[].class)).then(); + } +} +``` + +The request attribute `opentelemetry-context` in created by parsing the tracing headers in the [OpenTelemetryInterceptor](../OpenTelemetryInterceptor.java) class. See the code below: + +```java +@Component +public class OpenTelemetryInterceptor implements HandlerInterceptor { + // ... + @Override + public boolean preHandle( + HttpServletRequest request, HttpServletResponse response, Object handler) { + final TextMapPropagator textFormat = OpenTelemetry.getGlobalPropagators().getTextMapPropagator(); + // ... + Context context = textFormat.extract(Context.current(), request, HTTP_SERVLET_REQUEST_GETTER); + request.setAttribute("opentelemetry-context", context); + return true; + } + // ... +} +``` + +Use the follow command to execute the service: + +```sh +dapr run --app-id tracingdemoproxy --app-port 3001 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.TracingDemoService -p 3001 +``` + +### Running the InvokeClient app + +This sample code uses the Dapr SDK for invoking two remote methods (`proxy_echo` and `proxy_sleep`). It is also instrumented with OpenTelemetry. See the code snippet below: ```java public class InvokeClient { -private static final String SERVICE_APP_ID = "invokedemo"; +private static final String SERVICE_APP_ID = "tracingdemoproxy"; ///... public static void main(String[] args) throws Exception { Tracer tracer = OpenTelemetryConfig.createTracer(InvokeClient.class.getCanonicalName()); @@ -147,7 +201,7 @@ private static final String SERVICE_APP_ID = "invokedemo"; try (DaprClient client = (new DaprClientBuilder()).build()) { for (String message : args) { try (Scope scope = tracer.withSpan(span)) { - InvokeServiceRequestBuilder builder = new InvokeServiceRequestBuilder(SERVICE_APP_ID, "echo"); + InvokeServiceRequestBuilder builder = new InvokeServiceRequestBuilder(SERVICE_APP_ID, "proxy_echo"); InvokeServiceRequest request = builder.withBody(message).withHttpExtension(HttpExtension.POST).withContext(Context.current()).build(); client.invokeService(request, TypeRef.get(byte[].class)) @@ -156,10 +210,10 @@ private static final String SERVICE_APP_ID = "invokedemo"; return r; }) .flatMap(r -> { - InvokeServiceRequest sleepRequest = new InvokeServiceRequestBuilder(SERVICE_APP_ID, "sleep") + InvokeServiceRequest sleepRequest = new InvokeServiceRequestBuilder(SERVICE_APP_ID, "proxy_sleep") .withHttpExtension(HttpExtension.POST) .withContext(r.getContext()).build(); - return client.invokeService(sleepRequest, TypeRef.get(Void.class)); + return client.invokeMethod(sleepRequest, TypeRef.get(Void.class)); }).block(); } } @@ -175,7 +229,7 @@ private static final String SERVICE_APP_ID = "invokedemo"; } ``` -The class knows the app id for the remote application. It uses `invokeService` method to invoke API calls on the service endpoint. The request object includes an instance of `io.opentelemetry.context.Context` for the proper tracing headers to be propagated. +The class knows the app id for the remote application. It uses `invokeMethod` method to invoke API calls on the service endpoint. The request object includes an instance of `io.opentelemetry.context.Context` for the proper tracing headers to be propagated. Execute the follow script in order to run the InvokeClient example, passing two messages for the remote method: ```sh diff --git a/examples/src/main/java/io/dapr/examples/tracing/TracingDemoMiddleServiceController.java b/examples/src/main/java/io/dapr/examples/tracing/TracingDemoMiddleServiceController.java new file mode 100644 index 0000000000..1cdcf33588 --- /dev/null +++ b/examples/src/main/java/io/dapr/examples/tracing/TracingDemoMiddleServiceController.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.examples.tracing; + +import io.dapr.client.DaprClient; +import io.dapr.client.domain.HttpExtension; +import io.dapr.client.domain.InvokeMethodRequest; +import io.dapr.client.domain.InvokeMethodRequestBuilder; +import io.dapr.examples.OpenTelemetryInterceptor; +import io.dapr.utils.TypeRef; +import io.opentelemetry.context.Context; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; + +/** + * SpringBoot Controller to handle service invocation. + * + *

Instrumentation is handled in {@link OpenTelemetryInterceptor}. + */ +@RestController +public class TracingDemoMiddleServiceController { + + private static final String INVOKE_APP_ID = "tracingdemo"; + + /** + * Dapr client. + */ + @Autowired + private DaprClient client; + + /** + * Handles the 'echo' method invocation, by proxying a call into another service. + * + * @param context The tracing context for the request. + * @param body The body of the http message. + * @return A message containing the time. + */ + @PostMapping(path = "/proxy_echo") + public Mono echo( + @RequestAttribute(name = "opentelemetry-context") Context context, + @RequestBody(required = false) String body) { + InvokeMethodRequestBuilder builder = new InvokeMethodRequestBuilder(INVOKE_APP_ID, "echo"); + InvokeMethodRequest request + = builder.withBody(body).withHttpExtension(HttpExtension.POST).withContext(context).build(); + return client.invokeMethod(request, TypeRef.get(byte[].class)).map(r -> r.getObject()); + } + + /** + * Handles the 'sleep' method invocation, by proxying a call into another service. + * + * @param context The tracing context for the request. + * @return A message containing the time. + */ + @PostMapping(path = "/proxy_sleep") + public Mono sleep(@RequestAttribute(name = "opentelemetry-context") Context context) { + InvokeMethodRequestBuilder builder = new InvokeMethodRequestBuilder(INVOKE_APP_ID, "sleep"); + InvokeMethodRequest request = builder.withHttpExtension(HttpExtension.POST).withContext(context).build(); + return client.invokeMethod(request, TypeRef.get(byte[].class)).then(); + } + +} diff --git a/examples/src/main/java/io/dapr/examples/tracing/TracingDemoService.java b/examples/src/main/java/io/dapr/examples/tracing/TracingDemoService.java index f7a5a25c08..97d6abf8ae 100644 --- a/examples/src/main/java/io/dapr/examples/tracing/TracingDemoService.java +++ b/examples/src/main/java/io/dapr/examples/tracing/TracingDemoService.java @@ -5,7 +5,8 @@ package io.dapr.examples.tracing; -import io.dapr.springboot.DaprApplication; +import io.dapr.examples.DaprApplication; +import io.dapr.examples.OpenTelemetryInterceptor; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; @@ -14,7 +15,7 @@ /** * Main method to invoke DemoService to test tracing. * - *

Instrumentation is handled in {@link io.dapr.springboot.OpenTelemetryInterceptor}. + *

Instrumentation is handled in {@link OpenTelemetryInterceptor}. * *

1. Build and install jars: * mvn clean install @@ -22,6 +23,9 @@ * 3. Run in server mode: * dapr run --app-id tracingdemo --app-port 3000 \ * -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.TracingDemoService -p 3000 + * 4. Run middle server: + * dapr run --app-id tracingdemoproxy --app-port 3001 \ + * -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.TracingDemoService -p 3001 */ public class TracingDemoService { diff --git a/examples/src/main/java/io/dapr/examples/tracing/TracingDemoServiceController.java b/examples/src/main/java/io/dapr/examples/tracing/TracingDemoServiceController.java index 46aee0666c..be333718e7 100644 --- a/examples/src/main/java/io/dapr/examples/tracing/TracingDemoServiceController.java +++ b/examples/src/main/java/io/dapr/examples/tracing/TracingDemoServiceController.java @@ -6,6 +6,7 @@ package io.dapr.examples.tracing; import com.fasterxml.jackson.databind.ObjectMapper; +import io.dapr.examples.OpenTelemetryInterceptor; import io.opentelemetry.api.trace.Tracer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; @@ -14,7 +15,6 @@ import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; -import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; @@ -24,7 +24,7 @@ /** * SpringBoot Controller to handle service invocation. * - *

Instrumentation is handled in {@link io.dapr.springboot.OpenTelemetryInterceptor}. + *

Instrumentation is handled in {@link OpenTelemetryInterceptor}. */ @RestController public class TracingDemoServiceController { @@ -53,11 +53,11 @@ public class TracingDemoServiceController { * @return A message containing the time. */ @PostMapping(path = "/echo") - public Mono handleMethod(@RequestBody(required = false) byte[] body, + public Mono handleMethod(@RequestBody(required = false) String body, @RequestHeader Map headers) { return Mono.fromSupplier(() -> { try { - String message = body == null ? "" : new String(body, StandardCharsets.UTF_8); + String message = body == null ? "" : body; Calendar utcNow = Calendar.getInstance(TimeZone.getTimeZone("GMT")); String utcNowAsString = DATE_FORMAT.format(utcNow.getTime()); diff --git a/examples/src/main/resources/img/publisher.png b/examples/src/main/resources/img/publisher.png deleted file mode 100644 index cea3d8e60f..0000000000 Binary files a/examples/src/main/resources/img/publisher.png and /dev/null differ diff --git a/examples/src/main/resources/img/state.png b/examples/src/main/resources/img/state.png index f07ae1108a..852874abf0 100644 Binary files a/examples/src/main/resources/img/state.png and b/examples/src/main/resources/img/state.png differ diff --git a/examples/src/main/resources/img/subscriber.png b/examples/src/main/resources/img/subscriber.png deleted file mode 100644 index 506456d986..0000000000 Binary files a/examples/src/main/resources/img/subscriber.png and /dev/null differ diff --git a/pom.xml b/pom.xml index 3d7d13a7bf..e8883d5dc2 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ UTF-8 1.33.1 3.13.0 - https://raw.githubusercontent.com/dapr/dapr/3cca3cc1567f1cb955ae69b8fd784f075f62ad42/dapr/proto + https://raw.githubusercontent.com/dapr/dapr/4a6369caaba9cf46eae9bfa4fa6e76b474854c89/dapr/proto 1.6.2 3.1.1 1.8 diff --git a/sdk-actors/src/main/java/io/dapr/actors/ActorMethod.java b/sdk-actors/src/main/java/io/dapr/actors/ActorMethod.java index 424a41ccce..74f380ca17 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/ActorMethod.java +++ b/sdk-actors/src/main/java/io/dapr/actors/ActorMethod.java @@ -21,5 +21,13 @@ * * @return Actor's method return type. */ - Class returns(); + Class returns() default Undefined.class; + + /** + * Actor's method name. This is optional and will override the method's default name for actor invocation. + * + * @return Actor's method name. + */ + String name() default ""; + } diff --git a/sdk-actors/src/main/java/io/dapr/actors/Undefined.java b/sdk-actors/src/main/java/io/dapr/actors/Undefined.java new file mode 100644 index 0000000000..7375493bba --- /dev/null +++ b/sdk-actors/src/main/java/io/dapr/actors/Undefined.java @@ -0,0 +1,16 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.actors; + +/** + * Internal class to represent the undefined value for an optional Class attribute. + */ +final class Undefined { + + private Undefined() { + } + +} diff --git a/sdk-actors/src/main/java/io/dapr/actors/client/ActorClient.java b/sdk-actors/src/main/java/io/dapr/actors/client/ActorClient.java new file mode 100644 index 0000000000..ffd6a1fc70 --- /dev/null +++ b/sdk-actors/src/main/java/io/dapr/actors/client/ActorClient.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.actors.client; + +import io.dapr.client.DaprApiProtocol; +import io.dapr.client.DaprHttpBuilder; +import io.dapr.config.Properties; +import io.dapr.v1.DaprGrpc; +import io.grpc.Channel; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import reactor.core.publisher.Mono; + +/** + * Holds a client for Dapr sidecar communication. ActorClient should be reused. + */ +public class ActorClient implements AutoCloseable { + + /** + * gRPC channel for communication with Dapr sidecar. + */ + private final ManagedChannel grpcManagedChannel; + + /** + * Dapr's client. + */ + private final DaprClient daprClient; + + /** + * Instantiates a new channel for Dapr sidecar communication. + */ + public ActorClient() { + this(Properties.API_PROTOCOL.get()); + } + + /** + * Instantiates a new channel for Dapr sidecar communication. + * + * @param apiProtocol Dapr's API protocol. + */ + private ActorClient(DaprApiProtocol apiProtocol) { + this(apiProtocol, buildManagedChannel(apiProtocol)); + } + + /** + * Instantiates a new channel for Dapr sidecar communication. + * + * @param apiProtocol Dapr's API protocol. + */ + private ActorClient(DaprApiProtocol apiProtocol, ManagedChannel grpcManagedChannel) { + this.grpcManagedChannel = grpcManagedChannel; + this.daprClient = buildDaprClient(apiProtocol, grpcManagedChannel); + } + + /** + * Invokes an Actor method on Dapr. + * + * @param actorType Type of actor. + * @param actorId Actor Identifier. + * @param methodName Method name to invoke. + * @param jsonPayload Serialized body. + * @return Asynchronous result with the Actor's response. + */ + Mono invoke(String actorType, String actorId, String methodName, byte[] jsonPayload) { + return daprClient.invoke(actorType, actorId, methodName, jsonPayload); + } + + /** + * {@inheritDoc} + */ + @Override + public void close() { + if (grpcManagedChannel != null && !grpcManagedChannel.isShutdown()) { + grpcManagedChannel.shutdown(); + } + } + + /** + * Creates a GRPC managed channel (or null, if not applicable). + * + * @param apiProtocol Dapr's API protocol. + * @return GRPC managed channel or null. + */ + private static ManagedChannel buildManagedChannel(DaprApiProtocol apiProtocol) { + if (apiProtocol != DaprApiProtocol.GRPC) { + return null; + } + + int port = Properties.GRPC_PORT.get(); + if (port <= 0) { + throw new IllegalArgumentException("Invalid port."); + } + + return ManagedChannelBuilder.forAddress(Properties.SIDECAR_IP.get(), port).usePlaintext().build(); + } + + /** + * Build an instance of the Client based on the provided setup. + * + * @return an instance of the setup Client + * @throws java.lang.IllegalStateException if any required field is missing + */ + private static DaprClient buildDaprClient(DaprApiProtocol apiProtocol, Channel grpcManagedChannel) { + switch (apiProtocol) { + case GRPC: return new DaprGrpcClient(DaprGrpc.newFutureStub(grpcManagedChannel)); + case HTTP: return new DaprHttpClient(new DaprHttpBuilder().build()); + default: throw new IllegalStateException("Unsupported protocol: " + apiProtocol.name()); + } + } +} diff --git a/sdk-actors/src/main/java/io/dapr/actors/client/ActorProxy.java b/sdk-actors/src/main/java/io/dapr/actors/client/ActorProxy.java index c76b08bfc0..d573a3185a 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/client/ActorProxy.java +++ b/sdk-actors/src/main/java/io/dapr/actors/client/ActorProxy.java @@ -36,7 +36,7 @@ public interface ActorProxy { * @param The type to be returned. * @return Asynchronous result with the Actor's response. */ - Mono invokeActorMethod(String methodName, TypeRef type); + Mono invokeMethod(String methodName, TypeRef type); /** * Invokes an Actor method on Dapr. @@ -46,7 +46,7 @@ public interface ActorProxy { * @param The type to be returned. * @return Asynchronous result with the Actor's response. */ - Mono invokeActorMethod(String methodName, Class clazz); + Mono invokeMethod(String methodName, Class clazz); /** * Invokes an Actor method on Dapr. @@ -57,7 +57,7 @@ public interface ActorProxy { * @param The type to be returned. * @return Asynchronous result with the Actor's response. */ - Mono invokeActorMethod(String methodName, Object data, TypeRef type); + Mono invokeMethod(String methodName, Object data, TypeRef type); /** * Invokes an Actor method on Dapr. @@ -68,7 +68,7 @@ public interface ActorProxy { * @param The type to be returned. * @return Asynchronous result with the Actor's response. */ - Mono invokeActorMethod(String methodName, Object data, Class clazz); + Mono invokeMethod(String methodName, Object data, Class clazz); /** * Invokes an Actor method on Dapr. @@ -76,7 +76,7 @@ public interface ActorProxy { * @param methodName Method name to invoke. * @return Asynchronous result with the Actor's response. */ - Mono invokeActorMethod(String methodName); + Mono invokeMethod(String methodName); /** * Invokes an Actor method on Dapr. @@ -85,6 +85,6 @@ public interface ActorProxy { * @param data Object with the data. * @return Asynchronous result with the Actor's response. */ - Mono invokeActorMethod(String methodName, Object data); + Mono invokeMethod(String methodName, Object data); } diff --git a/sdk-actors/src/main/java/io/dapr/actors/client/ActorProxyBuilder.java b/sdk-actors/src/main/java/io/dapr/actors/client/ActorProxyBuilder.java index e19ad7caf0..389e414efa 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/client/ActorProxyBuilder.java +++ b/sdk-actors/src/main/java/io/dapr/actors/client/ActorProxyBuilder.java @@ -7,28 +7,15 @@ import io.dapr.actors.ActorId; import io.dapr.actors.ActorUtils; -import io.dapr.client.DaprHttpBuilder; -import io.dapr.config.Properties; import io.dapr.serializer.DaprObjectSerializer; import io.dapr.serializer.DefaultObjectSerializer; -import io.dapr.v1.DaprGrpc; -import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; -import java.io.Closeable; import java.lang.reflect.Proxy; -import static io.dapr.exceptions.DaprException.throwIllegalArgumentException; - /** * Builder to generate an ActorProxy instance. Builder can be reused for multiple instances. */ -public class ActorProxyBuilder implements Closeable { - - /** - * Determine if this builder will create GRPC clients instead of HTTP clients. - */ - private final boolean useGrpc; +public class ActorProxyBuilder { /** * Actor's type. @@ -46,14 +33,9 @@ public class ActorProxyBuilder implements Closeable { private DaprObjectSerializer objectSerializer; /** - * Builds Dapr HTTP client. - */ - private DaprHttpBuilder daprHttpBuilder; - - /** - * Channel for communication with Dapr. + * Client for communication with Dapr's Actor APIs. */ - private final ManagedChannel channel; + private final ActorClient actorClient; /** * Instantiates a new builder for a given Actor type, using {@link DefaultObjectSerializer} by default. @@ -61,9 +43,10 @@ public class ActorProxyBuilder implements Closeable { * {@link DefaultObjectSerializer} is not recommended for production scenarios. * * @param actorTypeClass Actor's type class. + * @param actorClient Dapr's sidecar client for Actor APIs. */ - public ActorProxyBuilder(Class actorTypeClass) { - this(ActorUtils.findActorTypeName(actorTypeClass), actorTypeClass); + public ActorProxyBuilder(Class actorTypeClass, ActorClient actorClient) { + this(ActorUtils.findActorTypeName(actorTypeClass), actorTypeClass, actorClient); } /** @@ -73,21 +56,23 @@ public ActorProxyBuilder(Class actorTypeClass) { * * @param actorType Actor's type. * @param actorTypeClass Actor's type class. + * @param actorClient Dapr's sidecar client for Actor APIs. */ - public ActorProxyBuilder(String actorType, Class actorTypeClass) { + public ActorProxyBuilder(String actorType, Class actorTypeClass, ActorClient actorClient) { if ((actorType == null) || actorType.isEmpty()) { - throwIllegalArgumentException("ActorType is required."); + throw new IllegalArgumentException("ActorType is required."); } if (actorTypeClass == null) { - throwIllegalArgumentException("ActorTypeClass is required."); + throw new IllegalArgumentException("ActorTypeClass is required."); + } + if (actorClient == null) { + throw new IllegalArgumentException("ActorClient is required."); } - this.useGrpc = Properties.USE_GRPC.get(); this.actorType = actorType; this.objectSerializer = new DefaultObjectSerializer(); this.clazz = actorTypeClass; - this.daprHttpBuilder = new DaprHttpBuilder(); - this.channel = buildManagedChannel(); + this.actorClient = actorClient; } /** @@ -98,7 +83,7 @@ public ActorProxyBuilder(String actorType, Class actorTypeClass) { */ public ActorProxyBuilder withObjectSerializer(DaprObjectSerializer objectSerializer) { if (objectSerializer == null) { - throwIllegalArgumentException("Serializer is required."); + throw new IllegalArgumentException("Serializer is required."); } this.objectSerializer = objectSerializer; @@ -113,14 +98,14 @@ public ActorProxyBuilder withObjectSerializer(DaprObjectSerializer objectSeri */ public T build(ActorId actorId) { if (actorId == null) { - throwIllegalArgumentException("Cannot instantiate an Actor without Id."); + throw new IllegalArgumentException("Cannot instantiate an Actor without Id."); } ActorProxyImpl proxy = new ActorProxyImpl( this.actorType, actorId, this.objectSerializer, - buildDaprClient()); + this.actorClient); if (this.clazz.equals(ActorProxy.class)) { // If users want to use the not strongly typed API, we respect that here. @@ -133,45 +118,4 @@ public T build(ActorId actorId) { proxy); } - /** - * Build an instance of the Client based on the provided setup. - * - * @return an instance of the setup Client - * @throws java.lang.IllegalStateException if any required field is missing - */ - private DaprClient buildDaprClient() { - if (this.useGrpc) { - return new DaprGrpcClient(DaprGrpc.newFutureStub(this.channel)); - } - - return new DaprHttpClient(daprHttpBuilder.build()); - } - - /** - * {@inheritDoc} - */ - @Override - public void close() { - if (channel != null && !channel.isShutdown()) { - channel.shutdown(); - } - } - - /** - * Creates a GRPC managed channel (or null, if not applicable). - * - * @return GRPC managed channel or null. - */ - private static ManagedChannel buildManagedChannel() { - if (!Properties.USE_GRPC.get()) { - return null; - } - - int port = Properties.GRPC_PORT.get(); - if (port <= 0) { - throwIllegalArgumentException("Invalid port."); - } - - return ManagedChannelBuilder.forAddress(Properties.SIDECAR_IP.get(), port).usePlaintext().build(); - } } diff --git a/sdk-actors/src/main/java/io/dapr/actors/client/ActorProxyImpl.java b/sdk-actors/src/main/java/io/dapr/actors/client/ActorProxyImpl.java index d26e50754f..d17df555c8 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/client/ActorProxyImpl.java +++ b/sdk-actors/src/main/java/io/dapr/actors/client/ActorProxyImpl.java @@ -21,6 +21,8 @@ */ class ActorProxyImpl implements ActorProxy, InvocationHandler { + private static final String UNDEFINED_CLASS_NAME = "io.dapr.actors.Undefined"; + /** * Actor's identifier for this Actor instance. */ @@ -39,7 +41,7 @@ class ActorProxyImpl implements ActorProxy, InvocationHandler { /** * Client to talk to the Dapr's API. */ - private final DaprClient daprClient; + private final ActorClient actorClient; /** * Creates a new instance of {@link ActorProxyImpl}. @@ -47,12 +49,12 @@ class ActorProxyImpl implements ActorProxy, InvocationHandler { * @param actorType actor implementation type of the actor associated with the proxy object. * @param actorId The actorId associated with the proxy * @param serializer Serializer and deserializer for method calls. - * @param daprClient Dapr client. + * @param actorClient Dapr client for Actor APIs. */ - ActorProxyImpl(String actorType, ActorId actorId, DaprObjectSerializer serializer, DaprClient daprClient) { + ActorProxyImpl(String actorType, ActorId actorId, DaprObjectSerializer serializer, ActorClient actorClient) { this.actorType = actorType; this.actorId = actorId; - this.daprClient = daprClient; + this.actorClient = actorClient; this.serializer = serializer; } @@ -74,8 +76,8 @@ public String getActorType() { * {@inheritDoc} */ @Override - public Mono invokeActorMethod(String methodName, Object data, TypeRef type) { - return this.daprClient.invokeActorMethod(actorType, actorId.toString(), methodName, this.serialize(data)) + public Mono invokeMethod(String methodName, Object data, TypeRef type) { + return this.actorClient.invoke(actorType, actorId.toString(), methodName, this.serialize(data)) .filter(s -> s.length > 0) .map(s -> deserialize(s, type)); } @@ -84,16 +86,16 @@ public Mono invokeActorMethod(String methodName, Object data, TypeRef * {@inheritDoc} */ @Override - public Mono invokeActorMethod(String methodName, Object data, Class clazz) { - return this.invokeActorMethod(methodName, data, TypeRef.get(clazz)); + public Mono invokeMethod(String methodName, Object data, Class clazz) { + return this.invokeMethod(methodName, data, TypeRef.get(clazz)); } /** * {@inheritDoc} */ @Override - public Mono invokeActorMethod(String methodName, TypeRef type) { - return this.daprClient.invokeActorMethod(actorType, actorId.toString(), methodName, null) + public Mono invokeMethod(String methodName, TypeRef type) { + return this.actorClient.invoke(actorType, actorId.toString(), methodName, null) .filter(s -> s.length > 0) .map(s -> deserialize(s, type)); } @@ -102,24 +104,24 @@ public Mono invokeActorMethod(String methodName, TypeRef type) { * {@inheritDoc} */ @Override - public Mono invokeActorMethod(String methodName, Class clazz) { - return this.invokeActorMethod(methodName, TypeRef.get(clazz)); + public Mono invokeMethod(String methodName, Class clazz) { + return this.invokeMethod(methodName, TypeRef.get(clazz)); } /** * {@inheritDoc} */ @Override - public Mono invokeActorMethod(String methodName) { - return this.daprClient.invokeActorMethod(actorType, actorId.toString(), methodName, null).then(); + public Mono invokeMethod(String methodName) { + return this.actorClient.invoke(actorType, actorId.toString(), methodName, null).then(); } /** * {@inheritDoc} */ @Override - public Mono invokeActorMethod(String methodName, Object data) { - return this.daprClient.invokeActorMethod(actorType, actorId.toString(), methodName, this.serialize(data)).then(); + public Mono invokeMethod(String methodName, Object data) { + return this.actorClient.invoke(actorType, actorId.toString(), methodName, this.serialize(data)).then(); } /** @@ -136,29 +138,33 @@ public Object invoke(Object proxy, Method method, Object[] args) { throw new UnsupportedOperationException("Actor methods can only have zero or one arguments."); } + ActorMethod actorMethodAnnotation = method.getDeclaredAnnotation(ActorMethod.class); + String methodName = method.getName(); + if ((actorMethodAnnotation != null) && !actorMethodAnnotation.name().isEmpty()) { + methodName = actorMethodAnnotation.name(); + } + if (method.getParameterCount() == 0) { if (method.getReturnType().equals(Mono.class)) { - ActorMethod actorMethodAnnotation = method.getDeclaredAnnotation(ActorMethod.class); - if (actorMethodAnnotation == null) { - return invokeActorMethod(method.getName()); + if ((actorMethodAnnotation == null) || UNDEFINED_CLASS_NAME.equals(actorMethodAnnotation.returns().getName())) { + return invokeMethod(methodName); } - return invokeActorMethod(method.getName(), actorMethodAnnotation.returns()); + return invokeMethod(methodName, actorMethodAnnotation.returns()); } - return invokeActorMethod(method.getName(), method.getReturnType()).block(); + return invokeMethod(methodName, method.getReturnType()).block(); } if (method.getReturnType().equals(Mono.class)) { - ActorMethod actorMethodAnnotation = method.getDeclaredAnnotation(ActorMethod.class); - if (actorMethodAnnotation == null) { - return invokeActorMethod(method.getName(), args[0]); + if ((actorMethodAnnotation == null) || UNDEFINED_CLASS_NAME.equals(actorMethodAnnotation.returns().getName())) { + return invokeMethod(methodName, args[0]); } - return invokeActorMethod(method.getName(), args[0], actorMethodAnnotation.returns()); + return invokeMethod(methodName, args[0], actorMethodAnnotation.returns()); } - return invokeActorMethod(method.getName(), args[0], method.getReturnType()).block(); + return invokeMethod(methodName, args[0], method.getReturnType()).block(); } /** diff --git a/sdk-actors/src/main/java/io/dapr/actors/client/DaprClient.java b/sdk-actors/src/main/java/io/dapr/actors/client/DaprClient.java index 5871f4cdc0..5d803420f9 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/client/DaprClient.java +++ b/sdk-actors/src/main/java/io/dapr/actors/client/DaprClient.java @@ -21,6 +21,6 @@ interface DaprClient { * @param jsonPayload Serialized body. * @return Asynchronous result with the Actor's response. */ - Mono invokeActorMethod(String actorType, String actorId, String methodName, byte[] jsonPayload); + Mono invoke(String actorType, String actorId, String methodName, byte[] jsonPayload); } diff --git a/sdk-actors/src/main/java/io/dapr/actors/client/DaprGrpcClient.java b/sdk-actors/src/main/java/io/dapr/actors/client/DaprGrpcClient.java index 3b64b1a80b..499068d96a 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/client/DaprGrpcClient.java +++ b/sdk-actors/src/main/java/io/dapr/actors/client/DaprGrpcClient.java @@ -40,7 +40,7 @@ class DaprGrpcClient implements DaprClient { * {@inheritDoc} */ @Override - public Mono invokeActorMethod(String actorType, String actorId, String methodName, byte[] jsonPayload) { + public Mono invoke(String actorType, String actorId, String methodName, byte[] jsonPayload) { return Mono.fromCallable(DaprException.wrap(() -> { DaprProtos.InvokeActorRequest req = DaprProtos.InvokeActorRequest.newBuilder() diff --git a/sdk-actors/src/main/java/io/dapr/actors/client/DaprHttpClient.java b/sdk-actors/src/main/java/io/dapr/actors/client/DaprHttpClient.java index a12270beda..728048f058 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/client/DaprHttpClient.java +++ b/sdk-actors/src/main/java/io/dapr/actors/client/DaprHttpClient.java @@ -15,16 +15,6 @@ */ class DaprHttpClient implements DaprClient { - /** - * Base URL for Dapr Actor APIs. - */ - private static final String ACTORS_BASE_URL = DaprHttp.API_VERSION + "/" + "actors"; - - /** - * String format for Actors method invocation relative url. - */ - private static final String ACTOR_METHOD_RELATIVE_URL_FORMAT = ACTORS_BASE_URL + "/%s/%s/method/%s"; - /** * The HTTP client to be used. * @@ -45,10 +35,10 @@ class DaprHttpClient implements DaprClient { * {@inheritDoc} */ @Override - public Mono invokeActorMethod(String actorType, String actorId, String methodName, byte[] jsonPayload) { - String url = String.format(ACTOR_METHOD_RELATIVE_URL_FORMAT, actorType, actorId, methodName); + public Mono invoke(String actorType, String actorId, String methodName, byte[] jsonPayload) { + String[] pathSegments = new String[] { DaprHttp.API_VERSION, "actors", actorType, actorId, "method", methodName }; Mono responseMono = - this.client.invokeApi(DaprHttp.HttpMethods.POST.name(), url, null, jsonPayload, null, null); + this.client.invokeApi(DaprHttp.HttpMethods.POST.name(), pathSegments, null, jsonPayload, null, null); return responseMono.map(r -> r.getBody()); } } diff --git a/sdk-actors/src/main/java/io/dapr/actors/runtime/AbstractActor.java b/sdk-actors/src/main/java/io/dapr/actors/runtime/AbstractActor.java index 540b8cfe46..3d72aafc41 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/runtime/AbstractActor.java +++ b/sdk-actors/src/main/java/io/dapr/actors/runtime/AbstractActor.java @@ -114,7 +114,7 @@ protected Mono registerReminder( try { byte[] data = this.actorRuntimeContext.getObjectSerializer().serialize(state); ActorReminderParams params = new ActorReminderParams(data, dueTime, period); - return this.actorRuntimeContext.getDaprClient().registerActorReminder( + return this.actorRuntimeContext.getDaprClient().registerReminder( this.actorRuntimeContext.getActorTypeInformation().getName(), this.id.toString(), reminderName, @@ -157,7 +157,7 @@ protected Mono registerActorTimer( byte[] data = this.actorRuntimeContext.getObjectSerializer().serialize(state); ActorTimerParams actorTimer = new ActorTimerParams(callback, data, dueTime, period); - return this.actorRuntimeContext.getDaprClient().registerActorTimer( + return this.actorRuntimeContext.getDaprClient().registerTimer( this.actorRuntimeContext.getActorTypeInformation().getName(), this.id.toString(), name, @@ -174,7 +174,7 @@ protected Mono registerActorTimer( * @return Asynchronous void response. */ protected Mono unregisterTimer(String timerName) { - return this.actorRuntimeContext.getDaprClient().unregisterActorTimer( + return this.actorRuntimeContext.getDaprClient().unregisterTimer( this.actorRuntimeContext.getActorTypeInformation().getName(), this.id.toString(), timerName); @@ -187,7 +187,7 @@ protected Mono unregisterTimer(String timerName) { * @return Asynchronous void response. */ protected Mono unregisterReminder(String reminderName) { - return this.actorRuntimeContext.getDaprClient().unregisterActorReminder( + return this.actorRuntimeContext.getDaprClient().unregisterReminder( this.actorRuntimeContext.getActorTypeInformation().getName(), this.id.toString(), reminderName); diff --git a/sdk-actors/src/main/java/io/dapr/actors/runtime/ActorMethodInfoMap.java b/sdk-actors/src/main/java/io/dapr/actors/runtime/ActorMethodInfoMap.java index dc41fd627a..f3f43b53bd 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/runtime/ActorMethodInfoMap.java +++ b/sdk-actors/src/main/java/io/dapr/actors/runtime/ActorMethodInfoMap.java @@ -5,6 +5,8 @@ package io.dapr.actors.runtime; +import io.dapr.actors.ActorMethod; + import java.lang.reflect.Method; import java.util.Collection; import java.util.Collections; @@ -35,7 +37,12 @@ class ActorMethodInfoMap { if (methodInfo.getParameterCount() <= 1) { // If Actor class uses overloading, then one will win. // Document this behavior, so users know how to write their code. - methods.put(methodInfo.getName(), methodInfo); + String methodName = methodInfo.getName(); + ActorMethod actorMethodAnnotation = methodInfo.getAnnotation(ActorMethod.class); + if ((actorMethodAnnotation != null) && !actorMethodAnnotation.name().isEmpty()) { + methodName = actorMethodAnnotation.name(); + } + methods.put(methodName, methodInfo); } } } diff --git a/sdk-actors/src/main/java/io/dapr/actors/runtime/ActorRuntime.java b/sdk-actors/src/main/java/io/dapr/actors/runtime/ActorRuntime.java index 5312046c53..d9a31c41a2 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/runtime/ActorRuntime.java +++ b/sdk-actors/src/main/java/io/dapr/actors/runtime/ActorRuntime.java @@ -7,6 +7,7 @@ import io.dapr.actors.ActorId; import io.dapr.actors.ActorTrace; +import io.dapr.client.DaprApiProtocol; import io.dapr.client.DaprHttpBuilder; import io.dapr.config.Properties; import io.dapr.serializer.DaprObjectSerializer; @@ -307,7 +308,7 @@ private ActorManager getActorManager(String actorTypeName) { * @throws java.lang.IllegalStateException if any required field is missing */ private static DaprClient buildDaprClient(ManagedChannel channel) { - if (Properties.USE_GRPC.get()) { + if (Properties.API_PROTOCOL.get() == DaprApiProtocol.GRPC) { return new DaprGrpcClient(channel); } @@ -320,7 +321,7 @@ private static DaprClient buildDaprClient(ManagedChannel channel) { * @return GRPC managed channel or null. */ private static ManagedChannel buildManagedChannel() { - if (!Properties.USE_GRPC.get()) { + if (Properties.API_PROTOCOL.get() != DaprApiProtocol.GRPC) { return null; } diff --git a/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprClient.java b/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprClient.java index 5da02ca109..878f3ab9fb 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprClient.java +++ b/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprClient.java @@ -22,7 +22,7 @@ interface DaprClient { * @param keyName State name. * @return Asynchronous result with current state value. */ - Mono getActorState(String actorType, String actorId, String keyName); + Mono getState(String actorType, String actorId, String keyName); /** * Saves state batch to Dapr. @@ -32,7 +32,7 @@ interface DaprClient { * @param operations State transaction operations. * @return Asynchronous void result. */ - Mono saveActorStateTransactionally(String actorType, String actorId, List operations); + Mono saveStateTransactionally(String actorType, String actorId, List operations); /** * Register a reminder. @@ -43,7 +43,7 @@ interface DaprClient { * @param reminderParams Parameters for the reminder. * @return Asynchronous void result. */ - Mono registerActorReminder( + Mono registerReminder( String actorType, String actorId, String reminderName, @@ -57,7 +57,7 @@ Mono registerActorReminder( * @param reminderName Name of reminder to be unregistered. * @return Asynchronous void result. */ - Mono unregisterActorReminder(String actorType, String actorId, String reminderName); + Mono unregisterReminder(String actorType, String actorId, String reminderName); /** * Register a timer. @@ -68,7 +68,7 @@ Mono registerActorReminder( * @param timerParams Parameters for the timer. * @return Asynchronous void result. */ - Mono registerActorTimer(String actorType, String actorId, String timerName, ActorTimerParams timerParams); + Mono registerTimer(String actorType, String actorId, String timerName, ActorTimerParams timerParams); /** * Unregisters a timer. @@ -78,5 +78,5 @@ Mono registerActorReminder( * @param timerName Name of timer to be unregistered. * @return Asynchronous void result. */ - Mono unregisterActorTimer(String actorType, String actorId, String timerName); + Mono unregisterTimer(String actorType, String actorId, String timerName); } diff --git a/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprGrpcClient.java b/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprGrpcClient.java index 7f2de0579c..c29b406caf 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprGrpcClient.java +++ b/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprGrpcClient.java @@ -66,7 +66,7 @@ class DaprGrpcClient implements DaprClient { * {@inheritDoc} */ @Override - public Mono getActorState(String actorType, String actorId, String keyName) { + public Mono getState(String actorType, String actorId, String keyName) { return Mono.fromCallable(() -> { DaprProtos.GetActorStateRequest req = DaprProtos.GetActorStateRequest.newBuilder() @@ -84,7 +84,7 @@ public Mono getActorState(String actorType, String actorId, String keyNa * {@inheritDoc} */ @Override - public Mono saveActorStateTransactionally( + public Mono saveStateTransactionally( String actorType, String actorId, List operations) { @@ -134,7 +134,7 @@ public Mono saveActorStateTransactionally( * {@inheritDoc} */ @Override - public Mono registerActorReminder( + public Mono registerReminder( String actorType, String actorId, String reminderName, @@ -160,7 +160,7 @@ public Mono registerActorReminder( * {@inheritDoc} */ @Override - public Mono unregisterActorReminder(String actorType, String actorId, String reminderName) { + public Mono unregisterReminder(String actorType, String actorId, String reminderName) { return Mono.fromCallable(() -> { DaprProtos.UnregisterActorReminderRequest req = DaprProtos.UnregisterActorReminderRequest.newBuilder() @@ -179,7 +179,7 @@ public Mono unregisterActorReminder(String actorType, String actorId, Stri * {@inheritDoc} */ @Override - public Mono registerActorTimer( + public Mono registerTimer( String actorType, String actorId, String timerName, @@ -206,7 +206,7 @@ public Mono registerActorTimer( * {@inheritDoc} */ @Override - public Mono unregisterActorTimer(String actorType, String actorId, String timerName) { + public Mono unregisterTimer(String actorType, String actorId, String timerName) { return Mono.fromCallable(() -> { DaprProtos.UnregisterActorTimerRequest req = DaprProtos.UnregisterActorTimerRequest.newBuilder() diff --git a/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprHttpClient.java b/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprHttpClient.java index f7abe68833..ca5f0deba0 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprHttpClient.java +++ b/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprHttpClient.java @@ -29,31 +29,6 @@ class DaprHttpClient implements DaprClient { */ private static final JsonFactory JSON_FACTORY = new JsonFactory(); - /** - * Base URL for Dapr Actor APIs. - */ - private static final String ACTORS_BASE_URL = DaprHttp.API_VERSION + "/" + "actors"; - - /** - * String format for Actors state management relative url. - */ - private static final String ACTOR_STATE_KEY_RELATIVE_URL_FORMAT = ACTORS_BASE_URL + "/%s/%s/state/%s"; - - /** - * String format for Actors state management relative url. - */ - private static final String ACTOR_STATE_RELATIVE_URL_FORMAT = ACTORS_BASE_URL + "/%s/%s/state"; - - /** - * String format for Actors reminder registration relative url. - */ - private static final String ACTOR_REMINDER_RELATIVE_URL_FORMAT = ACTORS_BASE_URL + "/%s/%s/reminders/%s"; - - /** - * String format for Actors timer registration relative url. - */ - private static final String ACTOR_TIMER_RELATIVE_URL_FORMAT = ACTORS_BASE_URL + "/%s/%s/timers/%s"; - /** * The HTTP client to be used. * @@ -74,10 +49,10 @@ class DaprHttpClient implements DaprClient { * {@inheritDoc} */ @Override - public Mono getActorState(String actorType, String actorId, String keyName) { - String url = String.format(ACTOR_STATE_KEY_RELATIVE_URL_FORMAT, actorType, actorId, keyName); + public Mono getState(String actorType, String actorId, String keyName) { + String[] pathSegments = new String[] { DaprHttp.API_VERSION, "actors", actorType, actorId, "state", keyName }; Mono responseMono = - this.client.invokeApi(DaprHttp.HttpMethods.GET.name(), url, null, "", null, null); + this.client.invokeApi(DaprHttp.HttpMethods.GET.name(), pathSegments, null, "", null, null); return responseMono.map(r -> { if ((r.getStatusCode() != 200) && (r.getStatusCode() != 204)) { throw new IllegalStateException( @@ -91,7 +66,7 @@ public Mono getActorState(String actorType, String actorId, String keyNa * {@inheritDoc} */ @Override - public Mono saveActorStateTransactionally( + public Mono saveStateTransactionally( String actorType, String actorId, List operations) { @@ -144,23 +119,30 @@ public Mono saveActorStateTransactionally( return Mono.error(e); } - String url = String.format(ACTOR_STATE_RELATIVE_URL_FORMAT, actorType, actorId); - return this.client.invokeApi(DaprHttp.HttpMethods.PUT.name(), url, null, payload, null, null).then(); + String[] pathSegments = new String[] { DaprHttp.API_VERSION, "actors", actorType, actorId, "state" }; + return this.client.invokeApi(DaprHttp.HttpMethods.PUT.name(), pathSegments, null, payload, null, null).then(); } /** * {@inheritDoc} */ @Override - public Mono registerActorReminder( + public Mono registerReminder( String actorType, String actorId, String reminderName, ActorReminderParams reminderParams) { - String url = String.format(ACTOR_REMINDER_RELATIVE_URL_FORMAT, actorType, actorId, reminderName); + String[] pathSegments = new String[] { + DaprHttp.API_VERSION, + "actors", + actorType, + actorId, + "reminders", + reminderName + }; return Mono.fromCallable(() -> INTERNAL_SERIALIZER.serialize(reminderParams)) .flatMap(data -> - this.client.invokeApi(DaprHttp.HttpMethods.PUT.name(), url, null, data, null, null) + this.client.invokeApi(DaprHttp.HttpMethods.PUT.name(), pathSegments, null, data, null, null) ).then(); } @@ -168,24 +150,38 @@ public Mono registerActorReminder( * {@inheritDoc} */ @Override - public Mono unregisterActorReminder(String actorType, String actorId, String reminderName) { - String url = String.format(ACTOR_REMINDER_RELATIVE_URL_FORMAT, actorType, actorId, reminderName); - return this.client.invokeApi(DaprHttp.HttpMethods.DELETE.name(), url, null, null, null).then(); + public Mono unregisterReminder(String actorType, String actorId, String reminderName) { + String[] pathSegments = new String[] { + DaprHttp.API_VERSION, + "actors", + actorType, + actorId, + "reminders", + reminderName + }; + return this.client.invokeApi(DaprHttp.HttpMethods.DELETE.name(), pathSegments, null, null, null).then(); } /** * {@inheritDoc} */ @Override - public Mono registerActorTimer( + public Mono registerTimer( String actorType, String actorId, String timerName, ActorTimerParams timerParams) { return Mono.fromCallable(() -> INTERNAL_SERIALIZER.serialize(timerParams)) .flatMap(data -> { - String url = String.format(ACTOR_TIMER_RELATIVE_URL_FORMAT, actorType, actorId, timerName); - return this.client.invokeApi(DaprHttp.HttpMethods.PUT.name(), url, null, data, null, null); + String[] pathSegments = new String[] { + DaprHttp.API_VERSION, + "actors", + actorType, + actorId, + "timers", + timerName + }; + return this.client.invokeApi(DaprHttp.HttpMethods.PUT.name(), pathSegments, null, data, null, null); }).then(); } @@ -193,9 +189,9 @@ public Mono registerActorTimer( * {@inheritDoc} */ @Override - public Mono unregisterActorTimer(String actorType, String actorId, String timerName) { - String url = String.format(ACTOR_TIMER_RELATIVE_URL_FORMAT, actorType, actorId, timerName); - return this.client.invokeApi(DaprHttp.HttpMethods.DELETE.name(), url, null, null, null).then(); + public Mono unregisterTimer(String actorType, String actorId, String timerName) { + String[] pathSegments = new String[] { DaprHttp.API_VERSION, "actors", actorType, actorId, "timers", timerName }; + return this.client.invokeApi(DaprHttp.HttpMethods.DELETE.name(), pathSegments, null, null, null).then(); } } diff --git a/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprStateAsyncProvider.java b/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprStateAsyncProvider.java index 7fa621f6ac..e4882926b6 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprStateAsyncProvider.java +++ b/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprStateAsyncProvider.java @@ -60,7 +60,7 @@ class DaprStateAsyncProvider { } Mono load(String actorType, ActorId actorId, String stateName, TypeRef type) { - Mono result = this.daprClient.getActorState(actorType, actorId.toString(), stateName); + Mono result = this.daprClient.getState(actorType, actorId.toString(), stateName); return result.flatMap(s -> { try { @@ -88,7 +88,7 @@ Mono load(String actorType, ActorId actorId, String stateName, TypeRef } Mono contains(String actorType, ActorId actorId, String stateName) { - Mono result = this.daprClient.getActorState(actorType, actorId.toString(), stateName); + Mono result = this.daprClient.getState(actorType, actorId.toString(), stateName); return result.map(s -> s.length > 0).defaultIfEmpty(false); } @@ -155,7 +155,7 @@ Mono apply(String actorType, ActorId actorId, ActorStateChange... stateCha operations.add(new ActorStateOperation(operationName, key, value)); } - return this.daprClient.saveActorStateTransactionally(actorType, actorId.toString(), operations); + return this.daprClient.saveStateTransactionally(actorType, actorId.toString(), operations); } } diff --git a/sdk-actors/src/test/java/io/dapr/actors/client/ActorProxyBuilderTest.java b/sdk-actors/src/test/java/io/dapr/actors/client/ActorProxyBuilderTest.java index 900ecad46d..b53efeca30 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/client/ActorProxyBuilderTest.java +++ b/sdk-actors/src/test/java/io/dapr/actors/client/ActorProxyBuilderTest.java @@ -7,44 +7,56 @@ import io.dapr.actors.ActorId; import io.dapr.actors.ActorType; -import io.dapr.exceptions.DaprException; +import org.junit.AfterClass; import org.junit.Assert; +import org.junit.BeforeClass; import org.junit.Test; public class ActorProxyBuilderTest { - @Test(expected = DaprException.class) + private static ActorClient actorClient; + + @BeforeClass + public static void initClass() { + actorClient = new ActorClient(); + } + + @AfterClass + public static void tearDownClass() { + actorClient.close(); + } + + @Test(expected = IllegalArgumentException.class) public void buildWithNullActorId() { - new ActorProxyBuilder("test", Object.class) + new ActorProxyBuilder("test", Object.class, actorClient) .build(null); - } - @Test(expected = DaprException.class) + @Test(expected = IllegalArgumentException.class) public void buildWithEmptyActorType() { - new ActorProxyBuilder("", Object.class) - .build(new ActorId("100")); - + new ActorProxyBuilder("", Object.class, actorClient); } - @Test(expected = DaprException.class) + @Test(expected = IllegalArgumentException.class) public void buildWithNullActorType() { - new ActorProxyBuilder(null, Object.class) - .build(new ActorId("100")); - + new ActorProxyBuilder(null, Object.class, actorClient); } - @Test(expected = DaprException.class) + @Test(expected = IllegalArgumentException.class) public void buildWithNullSerializer() { - new ActorProxyBuilder("MyActor", Object.class) + new ActorProxyBuilder("MyActor", Object.class, actorClient) .withObjectSerializer(null) .build(new ActorId("100")); + } + @Test(expected = IllegalArgumentException.class) + public void buildWithNullClient() { + new ActorProxyBuilder("MyActor", Object.class, null); } @Test() public void build() { - ActorProxyBuilder builder = new ActorProxyBuilder("test", ActorProxy.class); + ActorProxyBuilder builder = new ActorProxyBuilder("test", ActorProxy.class, actorClient); ActorProxy actorProxy = builder.build(new ActorId("100")); Assert.assertNotNull(actorProxy); @@ -54,7 +66,7 @@ public void build() { @Test() public void buildWithType() { - ActorProxyBuilder builder = new ActorProxyBuilder(MyActor.class); + ActorProxyBuilder builder = new ActorProxyBuilder(MyActor.class, actorClient); MyActor actorProxy = builder.build(new ActorId("100")); Assert.assertNotNull(actorProxy); @@ -62,8 +74,8 @@ public void buildWithType() { @Test() public void buildWithTypeDefaultName() { - ActorProxyBuilder builder = new ActorProxyBuilder(MyActorWithDefaultName.class); - MyActorWithDefaultName actorProxy = builder.build(new ActorId("100")); + ActorProxyBuilder builder = new ActorProxyBuilder(ActorWithDefaultName.class, actorClient); + ActorWithDefaultName actorProxy = builder.build(new ActorId("100")); Assert.assertNotNull(actorProxy); } @@ -72,6 +84,7 @@ public void buildWithTypeDefaultName() { public interface MyActor { } - public interface MyActorWithDefaultName { + public interface ActorWithDefaultName { } -} \ No newline at end of file + +} diff --git a/sdk-actors/src/test/java/io/dapr/actors/client/ActorProxyForTestsImpl.java b/sdk-actors/src/test/java/io/dapr/actors/client/ActorProxyForTestsImpl.java deleted file mode 100644 index faa237136a..0000000000 --- a/sdk-actors/src/test/java/io/dapr/actors/client/ActorProxyForTestsImpl.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - */ - -package io.dapr.actors.client; - -import io.dapr.actors.ActorId; -import io.dapr.serializer.DaprObjectSerializer; - -public class ActorProxyForTestsImpl extends ActorProxyImpl { - - public ActorProxyForTestsImpl(String actorType, ActorId actorId, DaprObjectSerializer serializer, DaprClient daprClient) { - super(actorType, actorId, serializer, daprClient); - } -} diff --git a/sdk-actors/src/test/java/io/dapr/actors/client/ActorProxyImplForTests.java b/sdk-actors/src/test/java/io/dapr/actors/client/ActorProxyImplForTests.java new file mode 100644 index 0000000000..a5160ace2a --- /dev/null +++ b/sdk-actors/src/test/java/io/dapr/actors/client/ActorProxyImplForTests.java @@ -0,0 +1,16 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.actors.client; + +import io.dapr.actors.ActorId; +import io.dapr.serializer.DaprObjectSerializer; + +public class ActorProxyImplForTests extends ActorProxyImpl { + + public ActorProxyImplForTests(String actorType, ActorId actorId, DaprObjectSerializer serializer, ActorClient actorClient) { + super(actorType, actorId, serializer, actorClient); + } +} diff --git a/sdk-actors/src/test/java/io/dapr/actors/client/ActorProxyImplTest.java b/sdk-actors/src/test/java/io/dapr/actors/client/ActorProxyImplTest.java index 5bbe2213d7..d9b867fbc1 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/client/ActorProxyImplTest.java +++ b/sdk-actors/src/test/java/io/dapr/actors/client/ActorProxyImplTest.java @@ -23,7 +23,7 @@ public class ActorProxyImplTest { @Test() public void constructorActorProxyTest() { - final DaprClient daprClient = mock(DaprClient.class); + final ActorClient daprClient = mock(ActorClient.class); final DaprObjectSerializer serializer = mock(DaprObjectSerializer.class); final ActorProxyImpl actorProxy = new ActorProxyImpl( "myActorType", @@ -36,11 +36,11 @@ public void constructorActorProxyTest() { @Test() public void invokeActorMethodWithoutDataWithReturnType() { - final DaprClient daprClient = mock(DaprClient.class); + final ActorClient daprClient = mock(ActorClient.class); Mono daprResponse = Mono.just( "{\n\t\t\"propertyA\": \"valueA\",\n\t\t\"propertyB\": \"valueB\"\n\t}".getBytes()); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNull())) + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.isNull())) .thenReturn(daprResponse); final ActorProxy actorProxy = new ActorProxyImpl( @@ -49,7 +49,7 @@ public void invokeActorMethodWithoutDataWithReturnType() { new DefaultObjectSerializer(), daprClient); - Mono result = actorProxy.invokeActorMethod("getData", MyData.class); + Mono result = actorProxy.invokeMethod("getData", MyData.class); MyData myData = result.block(); Assert.assertNotNull(myData); Assert.assertEquals("valueA", myData.getPropertyA()); @@ -58,11 +58,11 @@ public void invokeActorMethodWithoutDataWithReturnType() { @Test() public void invokeActorMethodWithoutDataWithReturnTypeViaReflection() throws NoSuchMethodException { - final DaprClient daprClient = mock(DaprClient.class); + final ActorClient daprClient = mock(ActorClient.class); Mono daprResponse = Mono.just( "{\n\t\t\"propertyA\": \"valueA\",\n\t\t\"propertyB\": \"valueB\"\n\t}".getBytes()); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNull())) + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.isNull())) .thenReturn(daprResponse); final ActorProxyImpl actorProxy = new ActorProxyImpl( @@ -79,11 +79,11 @@ public void invokeActorMethodWithoutDataWithReturnTypeViaReflection() throws NoS @Test() public void invokeActorMethodWithoutDataWithReturnMonoTypeViaReflection() throws NoSuchMethodException { - final DaprClient daprClient = mock(DaprClient.class); + final ActorClient daprClient = mock(ActorClient.class); Mono daprResponse = Mono.just( "{\n\t\t\"propertyA\": \"valueA\",\n\t\t\"propertyB\": \"valueB\"\n\t}".getBytes()); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNull())) + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.isNull())) .thenReturn(daprResponse); final ActorProxyImpl actorProxy = new ActorProxyImpl( @@ -102,11 +102,11 @@ public void invokeActorMethodWithoutDataWithReturnMonoTypeViaReflection() throws @Test() public void invokeActorMethodWithDataWithReturnTypeViaReflection() throws NoSuchMethodException { - final DaprClient daprClient = mock(DaprClient.class); + final ActorClient daprClient = mock(ActorClient.class); Mono daprResponse = Mono.just( "\"OK\"".getBytes()); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.eq("\"hello world\"".getBytes()))) + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.eq("\"hello world\"".getBytes()))) .thenReturn(daprResponse); final ActorProxyImpl actorProxy = new ActorProxyImpl( @@ -125,11 +125,11 @@ public void invokeActorMethodWithDataWithReturnTypeViaReflection() throws NoSuch @Test() public void invokeActorMethodWithDataWithReturnMonoTypeViaReflection() throws NoSuchMethodException { - final DaprClient daprClient = mock(DaprClient.class); + final ActorClient daprClient = mock(ActorClient.class); Mono daprResponse = Mono.just( "\"OK\"".getBytes()); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.eq("\"hello world\"".getBytes()))) + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.eq("\"hello world\"".getBytes()))) .thenReturn(daprResponse); final ActorProxyImpl actorProxy = new ActorProxyImpl( @@ -149,10 +149,10 @@ public void invokeActorMethodWithDataWithReturnMonoTypeViaReflection() throws No @Test() public void invokeActorMethodWithoutDataWithoutReturnTypeViaReflection() throws NoSuchMethodException { - final DaprClient daprClient = mock(DaprClient.class); + final ActorClient daprClient = mock(ActorClient.class); Mono daprResponse = Mono.empty(); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNull())) + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.isNull())) .thenReturn(daprResponse); final ActorProxyImpl actorProxy = new ActorProxyImpl( @@ -167,10 +167,10 @@ public void invokeActorMethodWithoutDataWithoutReturnTypeViaReflection() throws @Test() public void invokeActorMethodWithoutDataWithoutReturnTypeMonoViaReflection() throws NoSuchMethodException { - final DaprClient daprClient = mock(DaprClient.class); + final ActorClient daprClient = mock(ActorClient.class); Mono daprResponse = Mono.empty(); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNull())) + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.isNull())) .thenReturn(daprResponse); final ActorProxyImpl actorProxy = new ActorProxyImpl( @@ -186,10 +186,10 @@ public void invokeActorMethodWithoutDataWithoutReturnTypeMonoViaReflection() thr @Test() public void invokeActorMethodWithDataWithoutReturnTypeMonoViaReflection() throws NoSuchMethodException { - final DaprClient daprClient = mock(DaprClient.class); + final ActorClient daprClient = mock(ActorClient.class); Mono daprResponse = Mono.empty(); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.eq("\"hello world\"".getBytes()))) + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.eq("\"hello world\"".getBytes()))) .thenReturn(daprResponse); final ActorProxyImpl actorProxy = new ActorProxyImpl( @@ -209,7 +209,7 @@ public void invokeActorMethodWithDataWithoutReturnTypeMonoViaReflection() throws @Test(expected = UnsupportedOperationException.class) public void invokeActorMethodWithTooManyArgsViaReflection() throws NoSuchMethodException { - final DaprClient daprClient = mock(DaprClient.class); + final ActorClient daprClient = mock(ActorClient.class); final ActorProxyImpl actorProxy = new ActorProxyImpl( "myActorType", @@ -228,10 +228,10 @@ public void invokeActorMethodWithTooManyArgsViaReflection() throws NoSuchMethodE @Test() public void invokeActorMethodWithDataWithoutReturnTypeViaReflection() throws NoSuchMethodException { - final DaprClient daprClient = mock(DaprClient.class); + final ActorClient daprClient = mock(ActorClient.class); Mono daprResponse = Mono.empty(); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.eq("\"hello world\"".getBytes()))) + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.eq("\"hello world\"".getBytes()))) .thenReturn(daprResponse); final ActorProxyImpl actorProxy = new ActorProxyImpl( @@ -250,8 +250,8 @@ public void invokeActorMethodWithDataWithoutReturnTypeViaReflection() throws NoS @Test() public void invokeActorMethodWithoutDataWithEmptyReturnType() { - final DaprClient daprClient = mock(DaprClient.class); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNull())) + final ActorClient daprClient = mock(ActorClient.class); + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.isNull())) .thenReturn(Mono.just("".getBytes())); final ActorProxy actorProxy = new ActorProxyImpl( @@ -260,15 +260,15 @@ public void invokeActorMethodWithoutDataWithEmptyReturnType() { new DefaultObjectSerializer(), daprClient); - Mono result = actorProxy.invokeActorMethod("getData", MyData.class); + Mono result = actorProxy.invokeMethod("getData", MyData.class); MyData myData = result.block(); Assert.assertNull(myData); } @Test(expected = RuntimeException.class) public void invokeActorMethodWithIncorrectReturnType() { - final DaprClient daprClient = mock(DaprClient.class); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNull())) + final ActorClient daprClient = mock(ActorClient.class); + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.isNull())) .thenReturn(Mono.just("{test}".getBytes())); final ActorProxy actorProxy = new ActorProxyImpl( @@ -277,7 +277,7 @@ public void invokeActorMethodWithIncorrectReturnType() { new DefaultObjectSerializer(), daprClient); - Mono result = actorProxy.invokeActorMethod("getData", MyData.class); + Mono result = actorProxy.invokeMethod("getData", MyData.class); result.doOnSuccess(x -> Assert.fail("Not exception was throw")) @@ -287,8 +287,8 @@ public void invokeActorMethodWithIncorrectReturnType() { @Test() public void invokeActorMethodSavingDataWithReturnType() { - final DaprClient daprClient = mock(DaprClient.class); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNotNull())) + final ActorClient daprClient = mock(ActorClient.class); + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.isNotNull())) .thenReturn( Mono.just("{\n\t\t\"propertyA\": \"valueA\",\n\t\t\"propertyB\": \"valueB\"\n\t}".getBytes())); @@ -302,7 +302,7 @@ public void invokeActorMethodSavingDataWithReturnType() { saveData.setPropertyA("valueA"); saveData.setPropertyB("valueB"); - Mono result = actorProxy.invokeActorMethod("getData", saveData, MyData.class); + Mono result = actorProxy.invokeMethod("getData", saveData, MyData.class); MyData myData = result.block(); Assert.assertNotNull(myData); Assert.assertEquals("valueA", myData.getPropertyA()); @@ -312,8 +312,8 @@ public void invokeActorMethodSavingDataWithReturnType() { @Test(expected = DaprException.class) public void invokeActorMethodSavingDataWithIncorrectReturnType() { - final DaprClient daprClient = mock(DaprClient.class); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNotNull())) + final ActorClient daprClient = mock(ActorClient.class); + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.isNotNull())) .thenReturn(Mono.just("{test}".getBytes())); final ActorProxy actorProxy = new ActorProxyImpl( @@ -326,7 +326,7 @@ public void invokeActorMethodSavingDataWithIncorrectReturnType() { saveData.setPropertyA("valueA"); saveData.setPropertyB("valueB"); - Mono result = actorProxy.invokeActorMethod("getData", saveData, MyData.class); + Mono result = actorProxy.invokeMethod("getData", saveData, MyData.class); result.doOnSuccess(x -> Assert.fail("Not exception was throw")) .doOnError(Throwable::printStackTrace @@ -336,8 +336,8 @@ public void invokeActorMethodSavingDataWithIncorrectReturnType() { @Test() public void invokeActorMethodSavingDataWithEmptyReturnType() { - final DaprClient daprClient = mock(DaprClient.class); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNotNull())) + final ActorClient daprClient = mock(ActorClient.class); + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.isNotNull())) .thenReturn(Mono.just("".getBytes())); final ActorProxy actorProxy = new ActorProxyImpl( @@ -350,7 +350,7 @@ public void invokeActorMethodSavingDataWithEmptyReturnType() { saveData.setPropertyA("valueA"); saveData.setPropertyB("valueB"); - Mono result = actorProxy.invokeActorMethod("getData", saveData, MyData.class); + Mono result = actorProxy.invokeMethod("getData", saveData, MyData.class); MyData myData = result.block(); Assert.assertNull(myData); } @@ -358,8 +358,8 @@ public void invokeActorMethodSavingDataWithEmptyReturnType() { @Test(expected = DaprException.class) public void invokeActorMethodSavingDataWithIncorrectInputType() { - final DaprClient daprClient = mock(DaprClient.class); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNotNull())) + final ActorClient daprClient = mock(ActorClient.class); + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.isNotNull())) .thenReturn(Mono.just("{test}".getBytes())); final ActorProxy actorProxy = new ActorProxyImpl( @@ -373,7 +373,7 @@ public void invokeActorMethodSavingDataWithIncorrectInputType() { saveData.setPropertyB("valueB"); saveData.setMyData(saveData); - Mono result = actorProxy.invokeActorMethod("getData", saveData, MyData.class); + Mono result = actorProxy.invokeMethod("getData", saveData, MyData.class); result.doOnSuccess(x -> Assert.fail("Not exception was throw")) .doOnError(Throwable::printStackTrace @@ -387,8 +387,8 @@ public void invokeActorMethodWithDataWithVoidReturnType() { saveData.setPropertyA("valueA"); saveData.setPropertyB("valueB"); - final DaprClient daprClient = mock(DaprClient.class); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNotNull())) + final ActorClient daprClient = mock(ActorClient.class); + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.isNotNull())) .thenReturn(Mono.empty()); final ActorProxy actorProxy = new ActorProxyImpl( @@ -397,7 +397,7 @@ public void invokeActorMethodWithDataWithVoidReturnType() { new DefaultObjectSerializer(), daprClient); - Mono result = actorProxy.invokeActorMethod("getData", saveData); + Mono result = actorProxy.invokeMethod("getData", saveData); Void emptyResponse = result.block(); Assert.assertNull(emptyResponse); } @@ -410,8 +410,8 @@ public void invokeActorMethodWithDataWithVoidIncorrectInputType() { saveData.setPropertyB("valueB"); saveData.setMyData(saveData); - final DaprClient daprClient = mock(DaprClient.class); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNotNull())) + final ActorClient daprClient = mock(ActorClient.class); + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.isNotNull())) .thenReturn(Mono.empty()); final ActorProxy actorProxy = new ActorProxyImpl( @@ -420,15 +420,15 @@ public void invokeActorMethodWithDataWithVoidIncorrectInputType() { new DefaultObjectSerializer(), daprClient); - Mono result = actorProxy.invokeActorMethod("getData", saveData); + Mono result = actorProxy.invokeMethod("getData", saveData); Void emptyResponse = result.doOnError(Throwable::printStackTrace).block(); Assert.assertNull(emptyResponse); } @Test() public void invokeActorMethodWithoutDataWithVoidReturnType() { - final DaprClient daprClient = mock(DaprClient.class); - when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNull())) + final ActorClient daprClient = mock(ActorClient.class); + when(daprClient.invoke(anyString(), anyString(), anyString(), Mockito.isNull())) .thenReturn(Mono.empty()); final ActorProxy actorProxy = new ActorProxyImpl( @@ -437,7 +437,7 @@ public void invokeActorMethodWithoutDataWithVoidReturnType() { new DefaultObjectSerializer(), daprClient); - Mono result = actorProxy.invokeActorMethod("getData"); + Mono result = actorProxy.invokeMethod("getData"); Void emptyResponse = result.block(); Assert.assertNull(emptyResponse); } diff --git a/sdk-actors/src/test/java/io/dapr/actors/client/DaprClientStub.java b/sdk-actors/src/test/java/io/dapr/actors/client/DaprClientStub.java index 374b61a316..9e7f668423 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/client/DaprClientStub.java +++ b/sdk-actors/src/test/java/io/dapr/actors/client/DaprClientStub.java @@ -7,10 +7,10 @@ import reactor.core.publisher.Mono; -public class DaprClientStub implements DaprClient { +public class DaprClientStub extends ActorClient implements DaprClient { @Override - public Mono invokeActorMethod(String actorType, String actorId, String methodName, byte[] jsonPayload) { + public Mono invoke(String actorType, String actorId, String methodName, byte[] jsonPayload) { return Mono.just(new byte[0]); } diff --git a/sdk-actors/src/test/java/io/dapr/actors/client/DaprGrpcClientTest.java b/sdk-actors/src/test/java/io/dapr/actors/client/DaprGrpcClientTest.java index a43f8adf1d..9869bc756c 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/client/DaprGrpcClientTest.java +++ b/sdk-actors/src/test/java/io/dapr/actors/client/DaprGrpcClientTest.java @@ -54,7 +54,7 @@ public void invoke() { assertArrayEquals(payload, argument.getData().toByteArray()); return true; }))).thenReturn(settableFuture); - Mono result = client.invokeActorMethod(ACTOR_TYPE, ACTOR_ID, methodName, payload); + Mono result = client.invoke(ACTOR_TYPE, ACTOR_ID, methodName, payload); assertArrayEquals(response, result.block()); } @@ -73,7 +73,7 @@ public void invokeNullPayload() { assertArrayEquals(new byte[0], argument.getData().toByteArray()); return true; }))).thenReturn(settableFuture); - Mono result = client.invokeActorMethod(ACTOR_TYPE, ACTOR_ID, methodName, null); + Mono result = client.invoke(ACTOR_TYPE, ACTOR_ID, methodName, null); assertArrayEquals(response, result.block()); } @@ -91,7 +91,7 @@ public void invokeException() { assertArrayEquals(new byte[0], argument.getData().toByteArray()); return true; }))).thenReturn(settableFuture); - Mono result = client.invokeActorMethod(ACTOR_TYPE, ACTOR_ID, methodName, null); + Mono result = client.invoke(ACTOR_TYPE, ACTOR_ID, methodName, null); assertThrowsDaprException( ExecutionException.class, @@ -114,7 +114,7 @@ public void invokeNotHotMono() { assertArrayEquals(new byte[0], argument.getData().toByteArray()); return true; }))).thenReturn(settableFuture); - client.invokeActorMethod(ACTOR_TYPE, ACTOR_ID, methodName, null); + client.invoke(ACTOR_TYPE, ACTOR_ID, methodName, null); // No exception thrown because Mono is ignored here. } diff --git a/sdk-actors/src/test/java/io/dapr/actors/client/DaprHttpClientTest.java b/sdk-actors/src/test/java/io/dapr/actors/client/DaprHttpClientTest.java index 2fabe7ced7..c486db65a9 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/client/DaprHttpClientTest.java +++ b/sdk-actors/src/test/java/io/dapr/actors/client/DaprHttpClientTest.java @@ -43,7 +43,7 @@ public void invokeActorMethod() { DaprHttp daprHttp = new DaprHttpProxy(Properties.SIDECAR_IP.get(), 3000, okHttpClient); DaprHttpClient = new DaprHttpClient(daprHttp); Mono mono = - DaprHttpClient.invokeActorMethod("DemoActor", "1", "Payment", "".getBytes()); + DaprHttpClient.invoke("DemoActor", "1", "Payment", "".getBytes()); assertEquals(new String(mono.block()), EXPECTED_RESULT); } @@ -58,7 +58,7 @@ public void invokeActorMethodError() { DaprHttp daprHttp = new DaprHttpProxy(Properties.SIDECAR_IP.get(), 3000, okHttpClient); DaprHttpClient = new DaprHttpClient(daprHttp); Mono mono = - DaprHttpClient.invokeActorMethod("DemoActor", "1", "Payment", "".getBytes()); + DaprHttpClient.invoke("DemoActor", "1", "Payment", "".getBytes()); assertThrowsDaprException( "ERR_SOMETHING", diff --git a/sdk-actors/src/test/java/io/dapr/actors/runtime/ActorCustomSerializerTest.java b/sdk-actors/src/test/java/io/dapr/actors/runtime/ActorCustomSerializerTest.java index d85ab428f2..608374acc5 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/runtime/ActorCustomSerializerTest.java +++ b/sdk-actors/src/test/java/io/dapr/actors/runtime/ActorCustomSerializerTest.java @@ -8,7 +8,7 @@ import io.dapr.actors.ActorId; import io.dapr.actors.ActorType; import io.dapr.actors.client.ActorProxy; -import io.dapr.actors.client.ActorProxyForTestsImpl; +import io.dapr.actors.client.ActorProxyImplForTests; import io.dapr.actors.client.DaprClientStub; import io.dapr.serializer.DaprObjectSerializer; import org.junit.Assert; @@ -98,7 +98,7 @@ public void classInClassOut() { ActorProxy actorProxy = createActorProxy(); MyData d = new MyData("hi", 3); - MyData response = actorProxy.invokeActorMethod("classInClassOut", d, MyData.class).block(); + MyData response = actorProxy.invokeMethod("classInClassOut", d, MyData.class).block(); Assert.assertEquals("hihi", response.getName()); Assert.assertEquals(6, response.getNum()); @@ -107,7 +107,7 @@ public void classInClassOut() { @Test public void stringInStringOut() { ActorProxy actorProxy = createActorProxy(); - String response = actorProxy.invokeActorMethod("stringInStringOut", "oi", String.class).block(); + String response = actorProxy.invokeMethod("stringInStringOut", "oi", String.class).block(); Assert.assertEquals("oioi", response); } @@ -115,7 +115,7 @@ public void stringInStringOut() { @Test public void intInIntOut() { ActorProxy actorProxy = createActorProxy(); - int response = actorProxy.invokeActorMethod("intInIntOut", 2, int.class).block(); + int response = actorProxy.invokeMethod("intInIntOut", 2, int.class).block(); Assert.assertEquals(4, response); } @@ -130,7 +130,7 @@ private ActorProxy createActorProxy() { // Mock daprClient for ActorProxy only, not for runtime. DaprClientStub daprClient = mock(DaprClientStub.class); - when(daprClient.invokeActorMethod( + when(daprClient.invoke( eq(context.getActorTypeInformation().getName()), eq(actorId.toString()), any(), @@ -143,7 +143,7 @@ private ActorProxy createActorProxy() { this.manager.activateActor(actorId).block(); - return new ActorProxyForTestsImpl( + return new ActorProxyImplForTests( context.getActorTypeInformation().getName(), actorId, CUSTOM_SERIALIZER, @@ -153,10 +153,10 @@ private ActorProxy createActorProxy() { private static ActorRuntimeContext createContext() { DaprClient daprClient = mock(DaprClient.class); - when(daprClient.registerActorTimer(any(), any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.registerActorReminder(any(), any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.unregisterActorTimer(any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.unregisterActorReminder(any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.registerTimer(any(), any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.registerReminder(any(), any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.unregisterTimer(any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.unregisterReminder(any(), any(), any())).thenReturn(Mono.empty()); return new ActorRuntimeContext( mock(ActorRuntime.class), diff --git a/sdk-actors/src/test/java/io/dapr/actors/runtime/ActorManagerTest.java b/sdk-actors/src/test/java/io/dapr/actors/runtime/ActorManagerTest.java index f8eb562738..7b679b8df8 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/runtime/ActorManagerTest.java +++ b/sdk-actors/src/test/java/io/dapr/actors/runtime/ActorManagerTest.java @@ -287,10 +287,10 @@ private static String executeSayMethod(String something) { private static ActorRuntimeContext createContext(Class clazz) { DaprClient daprClient = mock(DaprClient.class); - when(daprClient.registerActorTimer(any(), any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.registerActorReminder(any(), any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.unregisterActorTimer(any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.unregisterActorReminder(any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.registerTimer(any(), any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.registerReminder(any(), any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.unregisterTimer(any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.unregisterReminder(any(), any(), any())).thenReturn(Mono.empty()); return new ActorRuntimeContext( mock(ActorRuntime.class), diff --git a/sdk-actors/src/test/java/io/dapr/actors/runtime/ActorNoStateTest.java b/sdk-actors/src/test/java/io/dapr/actors/runtime/ActorNoStateTest.java index fd5c99e72d..c7e7fc66fe 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/runtime/ActorNoStateTest.java +++ b/sdk-actors/src/test/java/io/dapr/actors/runtime/ActorNoStateTest.java @@ -6,9 +6,10 @@ package io.dapr.actors.runtime; import io.dapr.actors.ActorId; +import io.dapr.actors.ActorMethod; import io.dapr.actors.ActorType; import io.dapr.actors.client.ActorProxy; -import io.dapr.actors.client.ActorProxyForTestsImpl; +import io.dapr.actors.client.ActorProxyImplForTests; import io.dapr.actors.client.DaprClientStub; import io.dapr.serializer.DefaultObjectSerializer; import org.junit.Assert; @@ -43,6 +44,8 @@ public interface MyActor { Mono classInClassOut(MyData input); Mono registerBadCallbackName(); String registerTimerAutoName(); + @ActorMethod(name = "DotNetMethodASync") + Mono dotNetMethod(); } @ActorType(name = "MyActor") @@ -108,6 +111,11 @@ public Mono registerBadCallbackName() { public String registerTimerAutoName() { return super.registerActorTimer("", "anything", "state", Duration.ofSeconds(1), Duration.ofSeconds(1)).block(); } + + @Override + public Mono dotNetMethod() { + return Mono.empty(); + } } static class MyData { @@ -139,7 +147,7 @@ public void actorId() { Assert.assertEquals( proxy.getActorId().toString(), - proxy.invokeActorMethod("getMyId", String.class).block()); + proxy.invokeMethod("getMyId", String.class).block()); } @Test @@ -149,7 +157,7 @@ public void stringInStringOut() { // these should only call the actor methods for ActorChild. The implementations in ActorParent will throw. Assert.assertEquals( "abcabc", - proxy.invokeActorMethod("stringInStringOut", "abc", String.class).block()); + proxy.invokeMethod("stringInStringOut", "abc", String.class).block()); } @Test @@ -159,11 +167,11 @@ public void stringInBooleanOut() { // these should only call the actor methods for ActorChild. The implementations in ActorParent will throw. Assert.assertEquals( false, - proxy.invokeActorMethod("stringInBooleanOut", "hello world", Boolean.class).block()); + proxy.invokeMethod("stringInBooleanOut", "hello world", Boolean.class).block()); Assert.assertEquals( true, - proxy.invokeActorMethod("stringInBooleanOut", "true", Boolean.class).block()); + proxy.invokeMethod("stringInBooleanOut", "true", Boolean.class).block()); } @Test(expected = IllegalMonitorStateException.class) @@ -171,7 +179,13 @@ public void stringInVoidOutIntentionallyThrows() { ActorProxy actorProxy = createActorProxy(); // these should only call the actor methods for ActorChild. The implementations in ActorParent will throw. - actorProxy.invokeActorMethod("stringInVoidOutIntentionallyThrows", "hello world").block(); + actorProxy.invokeMethod("stringInVoidOutIntentionallyThrows", "hello world").block(); + } + + @Test + public void testMethodNameChange() { + MyActor actor = createActorProxy(MyActor.class); + actor.dotNetMethod(); } @Test @@ -180,7 +194,7 @@ public void classInClassOut() { MyData d = new MyData("hi", 3); // this should only call the actor methods for ActorChild. The implementations in ActorParent will throw. - MyData response = actorProxy.invokeActorMethod("classInClassOut", d, MyData.class).block(); + MyData response = actorProxy.invokeMethod("classInClassOut", d, MyData.class).block(); Assert.assertEquals( "hihi", @@ -218,7 +232,7 @@ private ActorProxy createActorProxy() { // Mock daprClient for ActorProxy only, not for runtime. DaprClientStub daprClient = mock(DaprClientStub.class); - when(daprClient.invokeActorMethod( + when(daprClient.invoke( eq(context.getActorTypeInformation().getName()), eq(actorId.toString()), any(), @@ -231,7 +245,7 @@ private ActorProxy createActorProxy() { this.manager.activateActor(actorId).block(); - return new ActorProxyForTestsImpl( + return new ActorProxyImplForTests( context.getActorTypeInformation().getName(), actorId, new DefaultObjectSerializer(), @@ -244,7 +258,7 @@ private T createActorProxy(Class clazz) { // Mock daprClient for ActorProxy only, not for runtime. DaprClientStub daprClient = mock(DaprClientStub.class); - when(daprClient.invokeActorMethod( + when(daprClient.invoke( eq(context.getActorTypeInformation().getName()), eq(actorId.toString()), any(), @@ -257,13 +271,13 @@ private T createActorProxy(Class clazz) { this.manager.activateActor(actorId).block(); - ActorProxyForTestsImpl proxy = new ActorProxyForTestsImpl( + ActorProxyImplForTests proxy = new ActorProxyImplForTests( context.getActorTypeInformation().getName(), actorId, new DefaultObjectSerializer(), daprClient); return (T) Proxy.newProxyInstance( - ActorProxyForTestsImpl.class.getClassLoader(), + ActorProxyImplForTests.class.getClassLoader(), new Class[]{clazz}, proxy); } @@ -271,10 +285,10 @@ private T createActorProxy(Class clazz) { private static ActorRuntimeContext createContext() { DaprClient daprClient = mock(DaprClient.class); - when(daprClient.registerActorTimer(any(), any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.registerActorReminder(any(), any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.unregisterActorTimer(any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.unregisterActorReminder(any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.registerTimer(any(), any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.registerReminder(any(), any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.unregisterTimer(any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.unregisterReminder(any(), any(), any())).thenReturn(Mono.empty()); return new ActorRuntimeContext( mock(ActorRuntime.class), diff --git a/sdk-actors/src/test/java/io/dapr/actors/runtime/ActorStatefulTest.java b/sdk-actors/src/test/java/io/dapr/actors/runtime/ActorStatefulTest.java index 7af99614b1..7b43c0bfe1 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/runtime/ActorStatefulTest.java +++ b/sdk-actors/src/test/java/io/dapr/actors/runtime/ActorStatefulTest.java @@ -8,7 +8,7 @@ import io.dapr.actors.ActorId; import io.dapr.actors.ActorType; import io.dapr.actors.client.ActorProxy; -import io.dapr.actors.client.ActorProxyForTestsImpl; +import io.dapr.actors.client.ActorProxyImplForTests; import io.dapr.actors.client.DaprClientStub; import io.dapr.serializer.DefaultObjectSerializer; import io.dapr.utils.TypeRef; @@ -289,33 +289,33 @@ public MyMethodContext setName(String name) { public void happyGetSetDeleteContains() { ActorProxy proxy = newActorProxy(); Assert.assertEquals( - proxy.getActorId().toString(), proxy.invokeActorMethod("getIdString", String.class).block()); - Assert.assertFalse(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + proxy.getActorId().toString(), proxy.invokeMethod("getIdString", String.class).block()); + Assert.assertFalse(proxy.invokeMethod("hasMessage", Boolean.class).block()); - proxy.invokeActorMethod("setMessage", "hello world").block(); - Assert.assertTrue(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + proxy.invokeMethod("setMessage", "hello world").block(); + Assert.assertTrue(proxy.invokeMethod("hasMessage", Boolean.class).block()); Assert.assertEquals( - "hello world", proxy.invokeActorMethod("getMessage", String.class).block()); + "hello world", proxy.invokeMethod("getMessage", String.class).block()); Assert.assertEquals( executeSayMethod("hello world"), - proxy.invokeActorMethod("setMessage", "hello world", String.class).block()); + proxy.invokeMethod("setMessage", "hello world", String.class).block()); - proxy.invokeActorMethod("deleteMessage").block(); - Assert.assertFalse(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + proxy.invokeMethod("deleteMessage").block(); + Assert.assertFalse(proxy.invokeMethod("hasMessage", Boolean.class).block()); } @Test(expected = IllegalStateException.class) public void lazyGet() { ActorProxy proxy = newActorProxy(); - Assert.assertFalse(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); - proxy.invokeActorMethod("setMessage", "first message").block(); + Assert.assertFalse(proxy.invokeMethod("hasMessage", Boolean.class).block()); + proxy.invokeMethod("setMessage", "first message").block(); // Creates the mono plan but does not call it yet. - Mono getMessageCall = proxy.invokeActorMethod("getMessage", String.class); + Mono getMessageCall = proxy.invokeMethod("getMessage", String.class); - proxy.invokeActorMethod("deleteMessage").block(); + proxy.invokeMethod("deleteMessage").block(); // Call should fail because the message was deleted. getMessageCall.block(); @@ -324,96 +324,96 @@ public void lazyGet() { @Test public void lazySet() { ActorProxy proxy = newActorProxy(); - Assert.assertFalse(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertFalse(proxy.invokeMethod("hasMessage", Boolean.class).block()); // Creates the mono plan but does not call it yet. - Mono setMessageCall = proxy.invokeActorMethod("setMessage", "first message"); + Mono setMessageCall = proxy.invokeMethod("setMessage", "first message"); // No call executed yet, so message should not be set. - Assert.assertFalse(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertFalse(proxy.invokeMethod("hasMessage", Boolean.class).block()); setMessageCall.block(); // Now the message has been set. - Assert.assertTrue(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertTrue(proxy.invokeMethod("hasMessage", Boolean.class).block()); } @Test public void lazyContains() { ActorProxy proxy = newActorProxy(); - Assert.assertFalse(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertFalse(proxy.invokeMethod("hasMessage", Boolean.class).block()); // Creates the mono plan but does not call it yet. - Mono hasMessageCall = proxy.invokeActorMethod("hasMessage", Boolean.class); + Mono hasMessageCall = proxy.invokeMethod("hasMessage", Boolean.class); // Sets the message. - proxy.invokeActorMethod("setMessage", "hello world").block(); + proxy.invokeMethod("setMessage", "hello world").block(); // Now we check if message is set. hasMessageCall.block(); // Now the message should be set. - Assert.assertTrue(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertTrue(proxy.invokeMethod("hasMessage", Boolean.class).block()); } @Test public void lazyDelete() { ActorProxy proxy = newActorProxy(); - Assert.assertFalse(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertFalse(proxy.invokeMethod("hasMessage", Boolean.class).block()); - proxy.invokeActorMethod("setMessage", "first message").block(); + proxy.invokeMethod("setMessage", "first message").block(); // Message is set. - Assert.assertTrue(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertTrue(proxy.invokeMethod("hasMessage", Boolean.class).block()); // Created the mono plan but does not execute it yet. - Mono deleteMessageCall = proxy.invokeActorMethod("deleteMessage"); + Mono deleteMessageCall = proxy.invokeMethod("deleteMessage"); // Message is still set. - Assert.assertTrue(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertTrue(proxy.invokeMethod("hasMessage", Boolean.class).block()); deleteMessageCall.block(); // Now message is not set. - Assert.assertFalse(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertFalse(proxy.invokeMethod("hasMessage", Boolean.class).block()); } @Test public void lazyAdd() { ActorProxy proxy = newActorProxy(); - Assert.assertFalse(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertFalse(proxy.invokeMethod("hasMessage", Boolean.class).block()); - proxy.invokeActorMethod("setMessage", "first message").block(); + proxy.invokeMethod("setMessage", "first message").block(); // Message is set. - Assert.assertTrue(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertTrue(proxy.invokeMethod("hasMessage", Boolean.class).block()); // Created the mono plan but does not execute it yet. - Mono addMessageCall = proxy.invokeActorMethod("addMessage", "second message"); + Mono addMessageCall = proxy.invokeMethod("addMessage", "second message"); // Message is still set. Assert.assertEquals("first message", - proxy.invokeActorMethod("getMessage", String.class).block()); + proxy.invokeMethod("getMessage", String.class).block()); // Delete message - proxy.invokeActorMethod("deleteMessage").block(); + proxy.invokeMethod("deleteMessage").block(); // Should work since previous message was deleted. addMessageCall.block(); // New message is still set. Assert.assertEquals("second message", - proxy.invokeActorMethod("getMessage", String.class).block()); + proxy.invokeMethod("getMessage", String.class).block()); } @Test public void onActivateAndOnDeactivate() { ActorProxy proxy = newActorProxy(); - Assert.assertTrue(proxy.invokeActorMethod("isActive", Boolean.class).block()); + Assert.assertTrue(proxy.invokeMethod("isActive", Boolean.class).block()); Assert.assertFalse(DEACTIVATED_ACTOR_IDS.contains(proxy.getActorId().toString())); - proxy.invokeActorMethod("hasMessage", Boolean.class).block(); + proxy.invokeMethod("hasMessage", Boolean.class).block(); this.manager.deactivateActor(proxy.getActorId()).block(); @@ -424,15 +424,15 @@ public void onActivateAndOnDeactivate() { public void onPreMethodAndOnPostMethod() { ActorProxy proxy = newActorProxy(); - proxy.invokeActorMethod("hasMessage", Boolean.class).block(); + proxy.invokeMethod("hasMessage", Boolean.class).block(); MyMethodContext preContext = - proxy.invokeActorMethod("getPreCallMethodContext", MyMethodContext.class).block(); + proxy.invokeMethod("getPreCallMethodContext", MyMethodContext.class).block(); Assert.assertEquals("hasMessage", preContext.getName()); Assert.assertEquals(ActorCallType.ACTOR_INTERFACE_METHOD.toString(), preContext.getType()); MyMethodContext postContext = - proxy.invokeActorMethod("getPostCallMethodContext", MyMethodContext.class).block(); + proxy.invokeMethod("getPostCallMethodContext", MyMethodContext.class).block(); Assert.assertEquals("hasMessage", postContext.getName()); Assert.assertEquals(ActorCallType.ACTOR_INTERFACE_METHOD.toString(), postContext.getType()); } @@ -444,12 +444,12 @@ public void invokeTimer() { this.manager.invokeTimer(proxy.getActorId(), "mytimer", "{ \"callback\": \"hasMessage\" }".getBytes()).block(); MyMethodContext preContext = - proxy.invokeActorMethod("getPreCallMethodContext", MyMethodContext.class).block(); + proxy.invokeMethod("getPreCallMethodContext", MyMethodContext.class).block(); Assert.assertEquals("mytimer", preContext.getName()); Assert.assertEquals(ActorCallType.TIMER_METHOD.toString(), preContext.getType()); MyMethodContext postContext = - proxy.invokeActorMethod("getPostCallMethodContext", MyMethodContext.class).block(); + proxy.invokeMethod("getPostCallMethodContext", MyMethodContext.class).block(); Assert.assertEquals("mytimer", postContext.getName()); Assert.assertEquals(ActorCallType.TIMER_METHOD.toString(), postContext.getType()); } @@ -467,7 +467,7 @@ public void invokeTimerAfterDeactivate() { public void invokeTimerAfterUnregister() { ActorProxy proxy = newActorProxy(); - proxy.invokeActorMethod("unregisterTimerAndReminder").block(); + proxy.invokeMethod("unregisterTimerAndReminder").block(); // This call succeeds because the SDK does not control register/unregister timer, the Dapr runtime does. this.manager.invokeTimer(proxy.getActorId(), "mytimer", "{ \"callback\": \"hasMessage\" }".getBytes()).block(); @@ -490,12 +490,12 @@ public void invokeReminder() throws Exception { this.manager.invokeReminder(proxy.getActorId(), "myreminder", params).block(); MyMethodContext preContext = - proxy.invokeActorMethod("getPreCallMethodContext", MyMethodContext.class).block(); + proxy.invokeMethod("getPreCallMethodContext", MyMethodContext.class).block(); Assert.assertEquals("myreminder", preContext.getName()); Assert.assertEquals(ActorCallType.REMINDER_METHOD.toString(), preContext.getType()); MyMethodContext postContext = - proxy.invokeActorMethod("getPostCallMethodContext", MyMethodContext.class).block(); + proxy.invokeMethod("getPostCallMethodContext", MyMethodContext.class).block(); Assert.assertEquals("myreminder", postContext.getName()); Assert.assertEquals(ActorCallType.REMINDER_METHOD.toString(), postContext.getType()); } @@ -517,8 +517,8 @@ public void classTypeRequestResponseInStateStore() { MyMethodContext expectedContext = new MyMethodContext().setName("MyName").setType("MyType"); - proxy.invokeActorMethod("setMethodContext", expectedContext).block(); - MyMethodContext context = proxy.invokeActorMethod("getMethodContext", MyMethodContext.class).block(); + proxy.invokeMethod("setMethodContext", expectedContext).block(); + MyMethodContext context = proxy.invokeMethod("getMethodContext", MyMethodContext.class).block(); Assert.assertEquals(expectedContext.getName(), context.getName()); Assert.assertEquals(expectedContext.getType(), context.getType()); @@ -528,8 +528,8 @@ public void classTypeRequestResponseInStateStore() { public void intTypeRequestResponseInStateStore() { ActorProxy proxy = newActorProxy(); - Assert.assertEquals(1, (int)proxy.invokeActorMethod("incrementAndGetCount", 1, int.class).block()); - Assert.assertEquals(6, (int)proxy.invokeActorMethod("incrementAndGetCount", 5, int.class).block()); + Assert.assertEquals(1, (int)proxy.invokeMethod("incrementAndGetCount", 1, int.class).block()); + Assert.assertEquals(6, (int)proxy.invokeMethod("incrementAndGetCount", 5, int.class).block()); } @Test(expected = NumberFormatException.class) @@ -537,68 +537,68 @@ public void intTypeWithMethodException() { ActorProxy proxy = newActorProxy(); // Zero is a magic input that will make method throw an exception. - proxy.invokeActorMethod("incrementAndGetCount", 0, int.class).block(); + proxy.invokeMethod("incrementAndGetCount", 0, int.class).block(); } @Test(expected = IllegalStateException.class) public void intTypeWithRuntimeException() { ActorProxy proxy = newActorProxy(); - proxy.invokeActorMethod("getCountButThrowsException", int.class).block(); + proxy.invokeMethod("getCountButThrowsException", int.class).block(); } @Test(expected = IllegalStateException.class) public void actorRuntimeException() { ActorProxy proxy = newActorProxy(); - Assert.assertFalse(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertFalse(proxy.invokeMethod("hasMessage", Boolean.class).block()); - proxy.invokeActorMethod("forceDuplicateException").block(); + proxy.invokeMethod("forceDuplicateException").block(); } @Test(expected = IllegalCharsetNameException.class) public void actorMethodException() { ActorProxy proxy = newActorProxy(); - Assert.assertFalse(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertFalse(proxy.invokeMethod("hasMessage", Boolean.class).block()); - proxy.invokeActorMethod("throwsWithoutSaving").block(); + proxy.invokeMethod("throwsWithoutSaving").block(); - Assert.assertFalse(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertFalse(proxy.invokeMethod("hasMessage", Boolean.class).block()); } @Test public void rollbackChanges() { ActorProxy proxy = newActorProxy(); - Assert.assertFalse(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertFalse(proxy.invokeMethod("hasMessage", Boolean.class).block()); // Runs a method that will add one message but fail because tries to add a second one. - proxy.invokeActorMethod("forceDuplicateException") + proxy.invokeMethod("forceDuplicateException") .onErrorResume(throwable -> Mono.empty()) .block(); // No message is set - Assert.assertFalse(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertFalse(proxy.invokeMethod("hasMessage", Boolean.class).block()); } @Test public void partialChanges() { ActorProxy proxy = newActorProxy(); - Assert.assertFalse(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertFalse(proxy.invokeMethod("hasMessage", Boolean.class).block()); // Runs a method that will add one message, commit but fail because tries to add a second one. - proxy.invokeActorMethod("forcePartialChange") + proxy.invokeMethod("forcePartialChange") .onErrorResume(throwable -> Mono.empty()) .block(); // Message is set. - Assert.assertTrue(proxy.invokeActorMethod("hasMessage", Boolean.class).block()); + Assert.assertTrue(proxy.invokeMethod("hasMessage", Boolean.class).block()); // It is first message and not the second due to a save() in the middle but an exception in the end. Assert.assertEquals("first message", - proxy.invokeActorMethod("getMessage", String.class).block()); + proxy.invokeMethod("getMessage", String.class).block()); } private ActorProxy newActorProxy() { @@ -607,7 +607,7 @@ private ActorProxy newActorProxy() { // Mock daprClient for ActorProxy only, not for runtime. DaprClientStub daprClient = mock(DaprClientStub.class); - when(daprClient.invokeActorMethod( + when(daprClient.invoke( eq(context.getActorTypeInformation().getName()), eq(actorId.toString()), any(), @@ -620,7 +620,7 @@ private ActorProxy newActorProxy() { this.manager.activateActor(actorId).block(); - return new ActorProxyForTestsImpl( + return new ActorProxyImplForTests( context.getActorTypeInformation().getName(), actorId, new DefaultObjectSerializer(), @@ -644,10 +644,10 @@ private static String executeSayMethod(String something) { private static ActorRuntimeContext createContext() { DaprClient daprClient = mock(DaprClient.class); - when(daprClient.registerActorTimer(any(), any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.registerActorReminder(any(), any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.unregisterActorTimer(any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.unregisterActorReminder(any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.registerTimer(any(), any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.registerReminder(any(), any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.unregisterTimer(any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.unregisterReminder(any(), any(), any())).thenReturn(Mono.empty()); return new ActorRuntimeContext( mock(ActorRuntime.class), diff --git a/sdk-actors/src/test/java/io/dapr/actors/runtime/DaprGrpcClientTest.java b/sdk-actors/src/test/java/io/dapr/actors/runtime/DaprGrpcClientTest.java index 2c01318c14..1e8cf0bcb8 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/runtime/DaprGrpcClientTest.java +++ b/sdk-actors/src/test/java/io/dapr/actors/runtime/DaprGrpcClientTest.java @@ -56,7 +56,7 @@ public void getActorStateException() { ACTOR_ID, "MyKey" )))).thenReturn(settableFuture); - Mono result = client.getActorState(ACTOR_TYPE, ACTOR_ID, "MyKey"); + Mono result = client.getState(ACTOR_TYPE, ACTOR_ID, "MyKey"); Exception exception = assertThrows(Exception.class, () -> result.block()); assertTrue(exception.getCause().getCause() instanceof ArithmeticException); } @@ -72,7 +72,7 @@ public void getActorState() { ACTOR_ID, "MyKey" )))).thenReturn(settableFuture); - Mono result = client.getActorState(ACTOR_TYPE, ACTOR_ID, "MyKey"); + Mono result = client.getState(ACTOR_TYPE, ACTOR_ID, "MyKey"); assertArrayEquals(data, result.block()); } @@ -86,7 +86,7 @@ public void saveActorStateTransactionallyException() { ACTOR_ID, new ArrayList<>() )))).thenReturn(settableFuture); - Mono result = client.saveActorStateTransactionally(ACTOR_TYPE, ACTOR_ID, new ArrayList<>()); + Mono result = client.saveStateTransactionally(ACTOR_TYPE, ACTOR_ID, new ArrayList<>()); Exception exception = assertThrows(Exception.class, () -> result.block()); assertTrue(exception.getCause().getCause() instanceof ArithmeticException); } @@ -106,7 +106,7 @@ public void saveActorStateTransactionally() { ACTOR_ID, Arrays.asList(operations) )))).thenReturn(settableFuture); - Mono result = client.saveActorStateTransactionally(ACTOR_TYPE, ACTOR_ID, Arrays.asList(operations)); + Mono result = client.saveStateTransactionally(ACTOR_TYPE, ACTOR_ID, Arrays.asList(operations)); result.block(); } @@ -125,7 +125,7 @@ public void saveActorStateTransactionallyByteArray() { ACTOR_ID, Arrays.asList(operations) )))).thenReturn(settableFuture); - Mono result = client.saveActorStateTransactionally(ACTOR_TYPE, ACTOR_ID, Arrays.asList(operations)); + Mono result = client.saveStateTransactionally(ACTOR_TYPE, ACTOR_ID, Arrays.asList(operations)); result.block(); } @@ -136,7 +136,7 @@ public void saveActorStateTransactionallyInvalidValueType() { new ActorStateOperation("delete", "mykey", null), }; - Mono result = client.saveActorStateTransactionally(ACTOR_TYPE, ACTOR_ID, Arrays.asList(operations)); + Mono result = client.saveStateTransactionally(ACTOR_TYPE, ACTOR_ID, Arrays.asList(operations)); assertThrows(IllegalArgumentException.class, () -> result.block()); } @@ -161,7 +161,7 @@ public void registerActorReminder() { assertEquals(DurationUtils.convertDurationToDaprFormat(params.getPeriod()), argument.getPeriod()); return true; }))).thenReturn(settableFuture); - Mono result = client.registerActorReminder(ACTOR_TYPE, ACTOR_ID, reminderName, params); + Mono result = client.registerReminder(ACTOR_TYPE, ACTOR_ID, reminderName, params); result.block(); } @@ -178,7 +178,7 @@ public void unregisterActorReminder() { assertEquals(reminderName, argument.getName()); return true; }))).thenReturn(settableFuture); - Mono result = client.unregisterActorReminder(ACTOR_TYPE, ACTOR_ID, reminderName); + Mono result = client.unregisterReminder(ACTOR_TYPE, ACTOR_ID, reminderName); result.block(); } @@ -205,7 +205,7 @@ public void registerActorTimer() { assertEquals(DurationUtils.convertDurationToDaprFormat(params.getPeriod()), argument.getPeriod()); return true; }))).thenReturn(settableFuture); - Mono result = client.registerActorTimer(ACTOR_TYPE, ACTOR_ID, timerName, params); + Mono result = client.registerTimer(ACTOR_TYPE, ACTOR_ID, timerName, params); result.block(); } @@ -222,7 +222,7 @@ public void unregisterActorTimer() { assertEquals(timerName, argument.getName()); return true; }))).thenReturn(settableFuture); - Mono result = client.unregisterActorTimer(ACTOR_TYPE, ACTOR_ID, timerName); + Mono result = client.unregisterTimer(ACTOR_TYPE, ACTOR_ID, timerName); result.block(); } diff --git a/sdk-actors/src/test/java/io/dapr/actors/runtime/DaprHttpClientTest.java b/sdk-actors/src/test/java/io/dapr/actors/runtime/DaprHttpClientTest.java index 4cbe6e5078..81a0b7ea3f 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/runtime/DaprHttpClientTest.java +++ b/sdk-actors/src/test/java/io/dapr/actors/runtime/DaprHttpClientTest.java @@ -54,7 +54,7 @@ public void getActorState() { .respond(EXPECTED_RESULT); DaprHttp daprHttp = new DaprHttpProxy(Properties.SIDECAR_IP.get(), 3000, okHttpClient); DaprHttpClient = new DaprHttpClient(daprHttp); - Mono mono = DaprHttpClient.getActorState("DemoActor", "1", "order"); + Mono mono = DaprHttpClient.getState("DemoActor", "1", "order"); assertEquals(new String(mono.block()), EXPECTED_RESULT); } @@ -67,7 +67,7 @@ public void saveActorStateTransactionally() { DaprHttp daprHttp = new DaprHttpProxy(Properties.SIDECAR_IP.get(), 3000, okHttpClient); DaprHttpClient = new DaprHttpClient(daprHttp); List ops = Collections.singletonList(new ActorStateOperation("UPSERT", "key", "value")); - Mono mono = DaprHttpClient.saveActorStateTransactionally("DemoActor", "1", ops); + Mono mono = DaprHttpClient.saveStateTransactionally("DemoActor", "1", ops); assertNull(mono.block()); } @@ -79,7 +79,7 @@ public void registerActorReminder() { DaprHttp daprHttp = new DaprHttpProxy(Properties.SIDECAR_IP.get(), 3000, okHttpClient); DaprHttpClient = new DaprHttpClient(daprHttp); Mono mono = - DaprHttpClient.registerActorReminder( + DaprHttpClient.registerReminder( "DemoActor", "1", "reminder", @@ -94,7 +94,7 @@ public void unregisterActorReminder() { .respond(EXPECTED_RESULT); DaprHttp daprHttp = new DaprHttpProxy(Properties.SIDECAR_IP.get(), 3000, okHttpClient); DaprHttpClient = new DaprHttpClient(daprHttp); - Mono mono = DaprHttpClient.unregisterActorReminder("DemoActor", "1", "reminder"); + Mono mono = DaprHttpClient.unregisterReminder("DemoActor", "1", "reminder"); assertNull(mono.block()); } @@ -127,7 +127,7 @@ public Response.Builder respond(Request request) { DaprHttp daprHttp = new DaprHttpProxy(Properties.SIDECAR_IP.get(), 3000, okHttpClient); DaprHttpClient = new DaprHttpClient(daprHttp); Mono mono = - DaprHttpClient.registerActorTimer( + DaprHttpClient.registerTimer( "DemoActor", "1", "timer", @@ -146,7 +146,7 @@ public void unregisterActorTimer() { .respond(EXPECTED_RESULT); DaprHttp daprHttp = new DaprHttpProxy(Properties.SIDECAR_IP.get(), 3000, okHttpClient); DaprHttpClient = new DaprHttpClient(daprHttp); - Mono mono = DaprHttpClient.unregisterActorTimer("DemoActor", "1", "timer"); + Mono mono = DaprHttpClient.unregisterTimer("DemoActor", "1", "timer"); assertNull(mono.block()); } } \ No newline at end of file diff --git a/sdk-actors/src/test/java/io/dapr/actors/runtime/DaprStateAsyncProviderTest.java b/sdk-actors/src/test/java/io/dapr/actors/runtime/DaprStateAsyncProviderTest.java index 62d0f956d7..75240a122e 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/runtime/DaprStateAsyncProviderTest.java +++ b/sdk-actors/src/test/java/io/dapr/actors/runtime/DaprStateAsyncProviderTest.java @@ -78,7 +78,7 @@ public int hashCode() { public void happyCaseApply() { DaprClient daprClient = mock(DaprClient.class); when(daprClient - .saveActorStateTransactionally( + .saveStateTransactionally( eq("MyActor"), eq("123"), argThat(operations -> { @@ -133,41 +133,41 @@ public void happyCaseApply() { createUpdateChange("bytes", new byte[]{0x1})) .block(); - verify(daprClient).saveActorStateTransactionally(eq("MyActor"), eq("123"), any()); + verify(daprClient).saveStateTransactionally(eq("MyActor"), eq("123"), any()); } @Test public void happyCaseLoad() throws Exception { DaprClient daprClient = mock(DaprClient.class); when(daprClient - .getActorState(any(), any(), eq("name"))) + .getState(any(), any(), eq("name"))) .thenReturn(Mono.just(SERIALIZER.serialize("Jon Doe"))); when(daprClient - .getActorState(any(), any(), eq("zipcode"))) + .getState(any(), any(), eq("zipcode"))) .thenReturn(Mono.just(SERIALIZER.serialize(98021))); when(daprClient - .getActorState(any(), any(), eq("goals"))) + .getState(any(), any(), eq("goals"))) .thenReturn(Mono.just(SERIALIZER.serialize(98))); when(daprClient - .getActorState(any(), any(), eq("balance"))) + .getState(any(), any(), eq("balance"))) .thenReturn(Mono.just(SERIALIZER.serialize(46.55))); when(daprClient - .getActorState(any(), any(), eq("active"))) + .getState(any(), any(), eq("active"))) .thenReturn(Mono.just(SERIALIZER.serialize(true))); when(daprClient - .getActorState(any(), any(), eq("customer"))) + .getState(any(), any(), eq("customer"))) .thenReturn(Mono.just("{ \"id\": 1000, \"name\": \"Roxane\"}".getBytes())); when(daprClient - .getActorState(any(), any(), eq("anotherCustomer"))) + .getState(any(), any(), eq("anotherCustomer"))) .thenReturn(Mono.just("{ \"id\": 2000, \"name\": \"Max\"}".getBytes())); when(daprClient - .getActorState(any(), any(), eq("nullCustomer"))) + .getState(any(), any(), eq("nullCustomer"))) .thenReturn(Mono.empty()); when(daprClient - .getActorState(any(), any(), eq("bytes"))) + .getState(any(), any(), eq("bytes"))) .thenReturn(Mono.just("\"QQ==\"".getBytes())); when(daprClient - .getActorState(any(), any(), eq("emptyBytes"))) + .getState(any(), any(), eq("emptyBytes"))) .thenReturn(Mono.just(new byte[0])); DaprStateAsyncProvider provider = new DaprStateAsyncProvider(daprClient, SERIALIZER); @@ -203,33 +203,33 @@ public void happyCaseContains() { // Keys that exists. when(daprClient - .getActorState(any(), any(), eq("name"))) + .getState(any(), any(), eq("name"))) .thenReturn(Mono.just("Jon Doe".getBytes())); when(daprClient - .getActorState(any(), any(), eq("zipcode"))) + .getState(any(), any(), eq("zipcode"))) .thenReturn(Mono.just("98021".getBytes())); when(daprClient - .getActorState(any(), any(), eq("goals"))) + .getState(any(), any(), eq("goals"))) .thenReturn(Mono.just("98".getBytes())); when(daprClient - .getActorState(any(), any(), eq("balance"))) + .getState(any(), any(), eq("balance"))) .thenReturn(Mono.just("46.55".getBytes())); when(daprClient - .getActorState(any(), any(), eq("active"))) + .getState(any(), any(), eq("active"))) .thenReturn(Mono.just("true".getBytes())); when(daprClient - .getActorState(any(), any(), eq("customer"))) + .getState(any(), any(), eq("customer"))) .thenReturn(Mono.just("{ \"id\": \"3000\", \"name\": \"Ely\" }".getBytes())); // Keys that do not exist. when(daprClient - .getActorState(any(), any(), eq("Does not exist"))) + .getState(any(), any(), eq("Does not exist"))) .thenReturn(Mono.empty()); when(daprClient - .getActorState(any(), any(), eq("NAME"))) + .getState(any(), any(), eq("NAME"))) .thenReturn(Mono.empty()); when(daprClient - .getActorState(any(), any(), eq(null))) + .getState(any(), any(), eq(null))) .thenReturn(Mono.empty()); DaprStateAsyncProvider provider = new DaprStateAsyncProvider(daprClient, SERIALIZER); diff --git a/sdk-actors/src/test/java/io/dapr/actors/runtime/DerivedActorTest.java b/sdk-actors/src/test/java/io/dapr/actors/runtime/DerivedActorTest.java index 3d59ae8c56..ad46016dd0 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/runtime/DerivedActorTest.java +++ b/sdk-actors/src/test/java/io/dapr/actors/runtime/DerivedActorTest.java @@ -8,7 +8,7 @@ import io.dapr.actors.ActorId; import io.dapr.actors.ActorType; import io.dapr.actors.client.ActorProxy; -import io.dapr.actors.client.ActorProxyForTestsImpl; +import io.dapr.actors.client.ActorProxyImplForTests; import io.dapr.actors.client.DaprClientStub; import io.dapr.serializer.DefaultObjectSerializer; import org.junit.Assert; @@ -223,7 +223,7 @@ public void stringInStringOut() { // these should only call the actor methods for ActorChild. The implementations in ActorParent will throw. Assert.assertEquals( "abcabc", - proxy.invokeActorMethod("stringInStringOut", "abc", String.class).block()); + proxy.invokeMethod("stringInStringOut", "abc", String.class).block()); } @Test @@ -233,11 +233,11 @@ public void stringInBooleanOut() { // these should only call the actor methods for ActorChild. The implementations in ActorParent will throw. Assert.assertEquals( false, - proxy.invokeActorMethod("stringInBooleanOut", "hello world", Boolean.class).block()); + proxy.invokeMethod("stringInBooleanOut", "hello world", Boolean.class).block()); Assert.assertEquals( true, - proxy.invokeActorMethod("stringInBooleanOut", "true", Boolean.class).block()); + proxy.invokeMethod("stringInBooleanOut", "true", Boolean.class).block()); } @Test @@ -247,14 +247,14 @@ public void stringInVoidOut() { // stringInVoidOut() has not been invoked so this is false Assert.assertEquals( false, - actorProxy.invokeActorMethod("methodReturningVoidInvoked", Boolean.class).block()); + actorProxy.invokeMethod("methodReturningVoidInvoked", Boolean.class).block()); // these should only call the actor methods for ActorChild. The implementations in ActorParent will throw. - actorProxy.invokeActorMethod("stringInVoidOut", "hello world").block(); + actorProxy.invokeMethod("stringInVoidOut", "hello world").block(); Assert.assertEquals( true, - actorProxy.invokeActorMethod("methodReturningVoidInvoked", Boolean.class).block()); + actorProxy.invokeMethod("methodReturningVoidInvoked", Boolean.class).block()); } @Test(expected = IllegalMonitorStateException.class) @@ -262,7 +262,7 @@ public void stringInVoidOutIntentionallyThrows() { ActorProxy actorProxy = createActorProxyForActorChild(); // these should only call the actor methods for ActorChild. The implementations in ActorParent will throw. - actorProxy.invokeActorMethod("stringInVoidOutIntentionallyThrows", "hello world").block(); + actorProxy.invokeMethod("stringInVoidOutIntentionallyThrows", "hello world").block(); } @Test @@ -271,7 +271,7 @@ public void classInClassOut() { MyData d = new MyData("hi", 3); // this should only call the actor methods for ActorChild. The implementations in ActorParent will throw. - MyData response = actorProxy.invokeActorMethod("classInClassOut", d, MyData.class).block(); + MyData response = actorProxy.invokeMethod("classInClassOut", d, MyData.class).block(); Assert.assertEquals( "hihi", @@ -288,26 +288,26 @@ public void testInheritedActorMethods() { Assert.assertEquals( "www", - actorProxy.invokeActorMethod("onlyImplementedInParentStringInStringOut", "w", String.class).block()); + actorProxy.invokeMethod("onlyImplementedInParentStringInStringOut", "w", String.class).block()); Assert.assertEquals( true, - actorProxy.invokeActorMethod("onlyImplementedInParentStringInBooleanOut", "icecream", Boolean.class).block()); + actorProxy.invokeMethod("onlyImplementedInParentStringInBooleanOut", "icecream", Boolean.class).block()); // onlyImplementedInParentStringInVoidOut() has not been invoked so this is false Assert.assertEquals( false, - actorProxy.invokeActorMethod("methodReturningVoidInvoked", Boolean.class).block()); + actorProxy.invokeMethod("methodReturningVoidInvoked", Boolean.class).block()); - actorProxy.invokeActorMethod("onlyImplementedInParentStringInVoidOut", "icecream", Boolean.class).block(); + actorProxy.invokeMethod("onlyImplementedInParentStringInVoidOut", "icecream", Boolean.class).block(); // now it should return true. Assert.assertEquals( true, - actorProxy.invokeActorMethod("methodReturningVoidInvoked", Boolean.class).block()); + actorProxy.invokeMethod("methodReturningVoidInvoked", Boolean.class).block()); MyData d = new MyData("hi", 3); - MyData response = actorProxy.invokeActorMethod("onlyImplementedInParentClassInClassOut", d, MyData.class).block(); + MyData response = actorProxy.invokeMethod("onlyImplementedInParentClassInClassOut", d, MyData.class).block(); Assert.assertEquals( "hihihi", @@ -327,7 +327,7 @@ private ActorProxy createActorProxyForActorChild() { // Mock daprClient for ActorProxy only, not for runtime. DaprClientStub daprClient = mock(DaprClientStub.class); - when(daprClient.invokeActorMethod( + when(daprClient.invoke( eq(context.getActorTypeInformation().getName()), eq(actorId.toString()), any(), @@ -340,7 +340,7 @@ private ActorProxy createActorProxyForActorChild() { this.manager.activateActor(actorId).block(); - return new ActorProxyForTestsImpl( + return new ActorProxyImplForTests( context.getActorTypeInformation().getName(), actorId, new DefaultObjectSerializer(), @@ -350,10 +350,10 @@ private ActorProxy createActorProxyForActorChild() { private static ActorRuntimeContext createContext() { DaprClient daprClient = mock(DaprClient.class); - when(daprClient.registerActorTimer(any(), any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.registerActorReminder(any(), any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.unregisterActorTimer(any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.unregisterActorReminder(any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.registerTimer(any(), any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.registerReminder(any(), any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.unregisterTimer(any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.unregisterReminder(any(), any(), any())).thenReturn(Mono.empty()); return new ActorRuntimeContext( mock(ActorRuntime.class), diff --git a/sdk-actors/src/test/java/io/dapr/actors/runtime/ThrowFromPreAndPostActorMethodsTest.java b/sdk-actors/src/test/java/io/dapr/actors/runtime/ThrowFromPreAndPostActorMethodsTest.java index a0a418dec6..5dbb1e9380 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/runtime/ThrowFromPreAndPostActorMethodsTest.java +++ b/sdk-actors/src/test/java/io/dapr/actors/runtime/ThrowFromPreAndPostActorMethodsTest.java @@ -8,7 +8,7 @@ import io.dapr.actors.ActorId; import io.dapr.actors.ActorType; import io.dapr.actors.client.ActorProxy; -import io.dapr.actors.client.ActorProxyForTestsImpl; +import io.dapr.actors.client.ActorProxyImplForTests; import io.dapr.actors.client.DaprClientStub; import io.dapr.serializer.DefaultObjectSerializer; import org.junit.Assert; @@ -121,7 +121,7 @@ public void stringInBooleanOut1() { // these should only call the actor methods for ActorChild. The implementations in ActorParent will throw. Assert.assertEquals( false, - proxy.invokeActorMethod("stringInBooleanOut", "hello world", Boolean.class).block()); + proxy.invokeMethod("stringInBooleanOut", "hello world", Boolean.class).block()); } // IllegalMonitorStateException should be intentionally thrown. This type was chosen for this test just because @@ -133,7 +133,7 @@ public void stringInBooleanOut2() { // these should only call the actor methods for ActorChild. The implementations in ActorParent will throw. Assert.assertEquals( true, - proxy.invokeActorMethod("stringInBooleanOut", "true", Boolean.class).block()); + proxy.invokeMethod("stringInBooleanOut", "true", Boolean.class).block()); } private static ActorId newActorId() { @@ -146,7 +146,7 @@ private ActorProxy createActorProxyForActorChild() { // Mock daprClient for ActorProxy only, not for runtime. DaprClientStub daprClient = mock(DaprClientStub.class); - when(daprClient.invokeActorMethod( + when(daprClient.invoke( eq(context.getActorTypeInformation().getName()), eq(actorId.toString()), any(), @@ -159,7 +159,7 @@ private ActorProxy createActorProxyForActorChild() { this.manager.activateActor(actorId).block(); - return new ActorProxyForTestsImpl( + return new ActorProxyImplForTests( context.getActorTypeInformation().getName(), actorId, new DefaultObjectSerializer(), @@ -169,10 +169,10 @@ private ActorProxy createActorProxyForActorChild() { private static ActorRuntimeContext createContext() { DaprClient daprClient = mock(DaprClient.class); - when(daprClient.registerActorTimer(any(), any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.registerActorReminder(any(), any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.unregisterActorTimer(any(), any(), any())).thenReturn(Mono.empty()); - when(daprClient.unregisterActorReminder(any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.registerTimer(any(), any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.registerReminder(any(), any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.unregisterTimer(any(), any(), any())).thenReturn(Mono.empty()); + when(daprClient.unregisterReminder(any(), any(), any())).thenReturn(Mono.empty()); return new ActorRuntimeContext( mock(ActorRuntime.class), diff --git a/sdk-springboot/pom.xml b/sdk-springboot/pom.xml index 93576e9eb6..38a6707a3e 100644 --- a/sdk-springboot/pom.xml +++ b/sdk-springboot/pom.xml @@ -29,8 +29,21 @@ false + 2.3.5.RELEASE + + + + org.springframework.boot + spring-boot-dependencies + ${springboot.version} + pom + import + + + + io.dapr @@ -88,6 +101,17 @@ 5.2.10.RELEASE compile + + org.springframework.boot + spring-boot-autoconfigure + compile + + + org.springframework.boot + spring-boot-configuration-processor + compile + true + diff --git a/sdk-springboot/src/main/java/io/dapr/springboot/DaprAutoConfiguration.java b/sdk-springboot/src/main/java/io/dapr/springboot/DaprAutoConfiguration.java new file mode 100644 index 0000000000..893ecd7a3e --- /dev/null +++ b/sdk-springboot/src/main/java/io/dapr/springboot/DaprAutoConfiguration.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.springboot; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +/** + * Dapr's Spring Boot AutoConfiguration. + */ +@Configuration +@ConditionalOnWebApplication +@ComponentScan("io.dapr.springboot") +public class DaprAutoConfiguration { +} diff --git a/sdk-springboot/src/main/java/io/dapr/springboot/DaprBeanPostProcessor.java b/sdk-springboot/src/main/java/io/dapr/springboot/DaprBeanPostProcessor.java index 8671a7c102..3b5d2f9f29 100644 --- a/sdk-springboot/src/main/java/io/dapr/springboot/DaprBeanPostProcessor.java +++ b/sdk-springboot/src/main/java/io/dapr/springboot/DaprBeanPostProcessor.java @@ -7,11 +7,8 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.dapr.Topic; -import io.dapr.client.ObjectSerializer; -import io.dapr.serializer.DefaultObjectSerializer; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.stereotype.Component; diff --git a/sdk-springboot/src/main/java/io/dapr/springboot/DaprController.java b/sdk-springboot/src/main/java/io/dapr/springboot/DaprController.java index 886ae21734..154d7366bb 100644 --- a/sdk-springboot/src/main/java/io/dapr/springboot/DaprController.java +++ b/sdk-springboot/src/main/java/io/dapr/springboot/DaprController.java @@ -12,7 +12,6 @@ import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; diff --git a/sdk-springboot/src/main/resources/META-INF/spring.factories b/sdk-springboot/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000..58ff4b58d6 --- /dev/null +++ b/sdk-springboot/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +io.dapr.springboot.DaprAutoConfiguration diff --git a/sdk-tests/.hashicorp_vault_token b/sdk-tests/.hashicorp_vault_token new file mode 100644 index 0000000000..18309abed3 --- /dev/null +++ b/sdk-tests/.hashicorp_vault_token @@ -0,0 +1 @@ +myroot diff --git a/sdk-tests/components/kafka_bindings.yaml b/sdk-tests/components/kafka_bindings.yaml index 280e241e19..687cb61d09 100644 --- a/sdk-tests/components/kafka_bindings.yaml +++ b/sdk-tests/components/kafka_bindings.yaml @@ -4,6 +4,7 @@ metadata: name: sample123 spec: type: bindings.kafka + version: 1 metadata: # Kafka broker connection setting - name: brokers diff --git a/sdk-tests/components/pubsub.yaml b/sdk-tests/components/pubsub.yaml index ce67e58e84..de48f22b8d 100644 --- a/sdk-tests/components/pubsub.yaml +++ b/sdk-tests/components/pubsub.yaml @@ -4,6 +4,7 @@ metadata: name: messagebus spec: type: pubsub.redis + version: 1 metadata: - name: redisHost value: localhost:6379 diff --git a/sdk-tests/components/statestore.yaml b/sdk-tests/components/statestore.yaml index 064922915d..2e5d21a391 100644 --- a/sdk-tests/components/statestore.yaml +++ b/sdk-tests/components/statestore.yaml @@ -4,6 +4,7 @@ metadata: name: statestore spec: type: state.redis + version: 1 metadata: - name: redisHost value: localhost:6379 diff --git a/sdk-tests/components/vault.yaml b/sdk-tests/components/vault.yaml index 633c6426d3..c214a6e2c1 100644 --- a/sdk-tests/components/vault.yaml +++ b/sdk-tests/components/vault.yaml @@ -4,12 +4,13 @@ metadata: name: vault spec: type: secretstores.hashicorp.vault + version: 1 metadata: - name: vaultAddr value: "http://127.0.0.1:8200" - name: skipVerify value : true - name: vaultTokenMountPath - value : "/tmp/.hashicorp_vault_token" + value : ".hashicorp_vault_token" - name: vaultKVPrefix value : "dapr" diff --git a/sdk-tests/src/test/java/io/dapr/actors/runtime/DaprClientHttpUtils.java b/sdk-tests/src/test/java/io/dapr/actors/runtime/DaprClientHttpUtils.java index 4f060d16c3..2faa404ff4 100644 --- a/sdk-tests/src/test/java/io/dapr/actors/runtime/DaprClientHttpUtils.java +++ b/sdk-tests/src/test/java/io/dapr/actors/runtime/DaprClientHttpUtils.java @@ -16,6 +16,6 @@ public static void unregisterActorReminder( String actorType, String actorId, String reminderName) throws Exception { - new DaprHttpClient(client).unregisterActorReminder(actorType, actorId, reminderName).block(); + new DaprHttpClient(client).unregisterReminder(actorType, actorId, reminderName).block(); } } diff --git a/sdk-tests/src/test/java/io/dapr/it/AppRun.java b/sdk-tests/src/test/java/io/dapr/it/AppRun.java index 5a275fc8ae..620a5365c0 100644 --- a/sdk-tests/src/test/java/io/dapr/it/AppRun.java +++ b/sdk-tests/src/test/java/io/dapr/it/AppRun.java @@ -5,6 +5,7 @@ package io.dapr.it; +import io.dapr.client.DaprApiProtocol; import io.dapr.config.Properties; import java.io.IOException; @@ -19,7 +20,7 @@ public class AppRun implements Stoppable { private static final String APP_COMMAND = - "mvn exec:java -D exec.mainClass=%s -D exec.classpathScope=test -D exec.args=\"%s\" -D dapr.grpc.enabled=%b"; + "mvn exec:java -D exec.mainClass=%s -D exec.classpathScope=test -D exec.args=\"%s\" -D %s=%s -D %s=%s"; private final DaprPorts ports; @@ -31,10 +32,10 @@ public class AppRun implements Stoppable { String successMessage, Class serviceClass, int maxWaitMilliseconds, - boolean useGRPC) { + DaprApiProtocol protocol) { this.command = new Command( successMessage, - buildCommand(serviceClass, ports, useGRPC), + buildCommand(serviceClass, ports, protocol), new HashMap<>() {{ put("DAPR_HTTP_PORT", ports.getHttpPort().toString()); put("DAPR_GRPC_PORT", ports.getGrpcPort().toString()); @@ -72,10 +73,11 @@ public void stop() throws InterruptedException { } } - private static String buildCommand(Class serviceClass, DaprPorts ports, boolean useGRPC) { + private static String buildCommand(Class serviceClass, DaprPorts ports, DaprApiProtocol protocol) { return String.format(APP_COMMAND, serviceClass.getCanonicalName(), ports.getAppPort() != null ? ports.getAppPort().toString() : "", - useGRPC); + Properties.API_PROTOCOL.getName(), protocol, + Properties.API_METHOD_INVOCATION_PROTOCOL.getName(), protocol); } private static void assertListeningOnPort(int port) { diff --git a/sdk-tests/src/test/java/io/dapr/it/BaseIT.java b/sdk-tests/src/test/java/io/dapr/it/BaseIT.java index 3f538861be..5ce0c6ce90 100644 --- a/sdk-tests/src/test/java/io/dapr/it/BaseIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/BaseIT.java @@ -5,12 +5,11 @@ package io.dapr.it; +import io.dapr.actors.client.ActorClient; +import io.dapr.client.DaprApiProtocol; import org.apache.commons.lang3.tuple.ImmutablePair; import org.junit.AfterClass; -import java.io.Closeable; -import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; @@ -24,7 +23,7 @@ public abstract class BaseIT { private static final Queue TO_BE_STOPPED = new LinkedList<>(); - private static final Queue TO_BE_CLOSED = new LinkedList<>(); + private static final Queue TO_BE_CLOSED = new LinkedList<>(); protected static DaprRun startDaprApp( String testName, @@ -32,7 +31,7 @@ protected static DaprRun startDaprApp( Class serviceClass, Boolean useAppPort, int maxWaitMilliseconds) throws Exception { - return startDaprApp(testName, successMessage, serviceClass, useAppPort, maxWaitMilliseconds, true); + return startDaprApp(testName, successMessage, serviceClass, useAppPort, maxWaitMilliseconds, DaprApiProtocol.GRPC); } protected static DaprRun startDaprApp( @@ -41,14 +40,15 @@ protected static DaprRun startDaprApp( Class serviceClass, Boolean useAppPort, int maxWaitMilliseconds, - boolean useGRPC) throws Exception { - return startDaprApp(testName, successMessage, serviceClass, useAppPort, true, maxWaitMilliseconds, useGRPC); + DaprApiProtocol protocol) throws Exception { + return startDaprApp(testName, successMessage, serviceClass, useAppPort, true, maxWaitMilliseconds, protocol); } protected static DaprRun startDaprApp( String testName, int maxWaitMilliseconds) throws Exception { - return startDaprApp(testName, "You're up and running!", null, false, true, maxWaitMilliseconds, true); + return startDaprApp( + testName, "You're up and running!", null, false, true, maxWaitMilliseconds, DaprApiProtocol.GRPC); } protected static DaprRun startDaprApp( @@ -58,13 +58,13 @@ protected static DaprRun startDaprApp( Boolean useAppPort, Boolean useDaprPorts, int maxWaitMilliseconds, - boolean useGRPC) throws Exception { + DaprApiProtocol protocol) throws Exception { DaprRun.Builder builder = new DaprRun.Builder( testName, () -> DaprPorts.build(useAppPort, useDaprPorts, useDaprPorts), successMessage, maxWaitMilliseconds, - useGRPC).withServiceClass(serviceClass); + protocol).withServiceClass(serviceClass); DaprRun run = builder.build(); TO_BE_STOPPED.add(run); DAPR_RUN_BUILDERS.put(run.getAppName(), builder); @@ -79,7 +79,8 @@ protected static ImmutablePair startSplitDaprAndApp( Class serviceClass, Boolean useAppPort, int maxWaitMilliseconds) throws Exception { - return startSplitDaprAndApp(testName, successMessage, serviceClass, useAppPort, maxWaitMilliseconds, true); + return startSplitDaprAndApp( + testName, successMessage, serviceClass, useAppPort, maxWaitMilliseconds, DaprApiProtocol.GRPC); } protected static ImmutablePair startSplitDaprAndApp( @@ -88,13 +89,13 @@ protected static ImmutablePair startSplitDaprAndApp( Class serviceClass, Boolean useAppPort, int maxWaitMilliseconds, - boolean useGRPC) throws Exception { + DaprApiProtocol protocol) throws Exception { DaprRun.Builder builder = new DaprRun.Builder( testName, () -> DaprPorts.build(useAppPort, true, true), successMessage, maxWaitMilliseconds, - useGRPC).withServiceClass(serviceClass); + protocol).withServiceClass(serviceClass); ImmutablePair runs = builder.splitBuild(); TO_BE_STOPPED.add(runs.left); TO_BE_STOPPED.add(runs.right); @@ -108,18 +109,17 @@ protected static ImmutablePair startSplitDaprAndApp( @AfterClass public static void cleanUp() throws Exception { while (!TO_BE_CLOSED.isEmpty()) { - Closeable toBeClosed = TO_BE_CLOSED.remove(); - toBeClosed.close(); + TO_BE_CLOSED.remove().close(); } while (!TO_BE_STOPPED.isEmpty()) { - Stoppable toBeStopped = TO_BE_STOPPED.remove(); - toBeStopped.stop(); + TO_BE_STOPPED.remove().stop(); } } - protected static T deferClose(T closeable) { - TO_BE_CLOSED.add(closeable); - return closeable; + protected ActorClient newActorClient() { + ActorClient client = new ActorClient(); + TO_BE_CLOSED.add(client); + return client; } } diff --git a/sdk-tests/src/test/java/io/dapr/it/DaprRun.java b/sdk-tests/src/test/java/io/dapr/it/DaprRun.java index cf0f3d219a..8939785aaa 100644 --- a/sdk-tests/src/test/java/io/dapr/it/DaprRun.java +++ b/sdk-tests/src/test/java/io/dapr/it/DaprRun.java @@ -5,6 +5,7 @@ package io.dapr.it; +import io.dapr.client.DaprApiProtocol; import io.dapr.config.Properties; import org.apache.commons.lang3.tuple.ImmutablePair; @@ -23,7 +24,7 @@ public class DaprRun implements Stoppable { // the arg in -Dexec.args is the app's port private static final String DAPR_COMMAND = - " -- mvn exec:java -D exec.mainClass=%s -D exec.classpathScope=test -D exec.args=\"%s\" -D dapr.grpc.enabled=%s"; + " -- mvn exec:java -D exec.mainClass=%s -D exec.classpathScope=test -D exec.args=\"%s\" -D %s=%s -D %s=%s"; private final DaprPorts ports; @@ -44,11 +45,11 @@ private DaprRun(String testName, String successMessage, Class serviceClass, int maxWaitMilliseconds, - boolean useGRPC) { + DaprApiProtocol protocol) { // The app name needs to be deterministic since we depend on it to kill previous runs. this.appName = serviceClass == null ? testName : String.format("%s_%s", testName, serviceClass.getSimpleName()); this.startCommand = - new Command(successMessage, buildDaprCommand(this.appName, serviceClass, ports, useGRPC)); + new Command(successMessage, buildDaprCommand(this.appName, serviceClass, ports, protocol)); this.listCommand = new Command( this.appName, "dapr list"); @@ -132,20 +133,24 @@ public void stop() throws InterruptedException, IOException { public void use() { if (this.ports.getHttpPort() != null) { - System.getProperties().setProperty("dapr.http.port", String.valueOf(this.ports.getHttpPort())); + System.getProperties().setProperty(Properties.HTTP_PORT.getName(), String.valueOf(this.ports.getHttpPort())); } if (this.ports.getGrpcPort() != null) { - System.getProperties().setProperty("dapr.grpc.port", String.valueOf(this.ports.getGrpcPort())); + System.getProperties().setProperty(Properties.GRPC_PORT.getName(), String.valueOf(this.ports.getGrpcPort())); } - System.getProperties().setProperty("dapr.grpc.enabled", Boolean.TRUE.toString()); + System.getProperties().setProperty(Properties.API_PROTOCOL.getName(), DaprApiProtocol.GRPC.name()); } public void switchToGRPC() { - System.getProperties().setProperty("dapr.grpc.enabled", Boolean.TRUE.toString()); + System.getProperties().setProperty(Properties.API_PROTOCOL.getName(), DaprApiProtocol.GRPC.name()); } public void switchToHTTP() { - System.getProperties().setProperty("dapr.grpc.enabled", Boolean.FALSE.toString()); + System.getProperties().setProperty(Properties.API_PROTOCOL.getName(), DaprApiProtocol.HTTP.name()); + } + + public void switchToProtocol(DaprApiProtocol protocol) { + System.getProperties().setProperty(Properties.API_PROTOCOL.getName(), protocol.name()); } public int getGrpcPort() { @@ -164,14 +169,17 @@ public String getAppName() { return appName; } - private static String buildDaprCommand(String appName, Class serviceClass, DaprPorts ports, boolean useGRPC) { + private static String buildDaprCommand( + String appName, Class serviceClass, DaprPorts ports, DaprApiProtocol protocol) { StringBuilder stringBuilder = new StringBuilder(String.format(DAPR_RUN, appName)) .append(ports.getAppPort() != null ? " --app-port " + ports.getAppPort() : "") .append(ports.getHttpPort() != null ? " --dapr-http-port " + ports.getHttpPort() : "") .append(ports.getGrpcPort() != null ? " --dapr-grpc-port " + ports.getGrpcPort() : "") .append(serviceClass == null ? "" : String.format(DAPR_COMMAND, serviceClass.getCanonicalName(), - ports.getAppPort() != null ? ports.getAppPort().toString() : "", useGRPC)); + ports.getAppPort() != null ? ports.getAppPort().toString() : "", + Properties.API_PROTOCOL.getName(), protocol, + Properties.API_METHOD_INVOCATION_PROTOCOL.getName(), protocol)); return stringBuilder.toString(); } @@ -200,19 +208,19 @@ static class Builder { private Class serviceClass; - private boolean useGRPC; + private DaprApiProtocol protocol; Builder( String testName, Supplier portsSupplier, String successMessage, int maxWaitMilliseconds, - boolean useGRPC) { + DaprApiProtocol protocol) { this.testName = testName; this.portsSupplier = portsSupplier; this.successMessage = successMessage; this.maxWaitMilliseconds = maxWaitMilliseconds; - this.useGRPC = useGRPC; + this.protocol = protocol; } public Builder withServiceClass(Class serviceClass) { @@ -227,7 +235,7 @@ DaprRun build() { this.successMessage, this.serviceClass, this.maxWaitMilliseconds, - this.useGRPC); + this.protocol); } /** @@ -241,7 +249,7 @@ ImmutablePair splitBuild() { this.successMessage, this.serviceClass, this.maxWaitMilliseconds, - this.useGRPC); + this.protocol); DaprRun daprRun = new DaprRun( this.testName, @@ -249,7 +257,7 @@ ImmutablePair splitBuild() { DAPR_SUCCESS_MESSAGE, null, this.maxWaitMilliseconds, - this.useGRPC); + this.protocol); return new ImmutablePair<>(appRun, daprRun); } diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActivationDeactivationIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActivationDeactivationIT.java index 2641672bc7..8c7b84a98c 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActivationDeactivationIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActivationDeactivationIT.java @@ -38,7 +38,7 @@ public void activateInvokeDeactivate() throws Exception { final AtomicInteger atomicInteger = new AtomicInteger(1); logger.debug("Creating proxy builder"); - ActorProxyBuilder proxyBuilder = deferClose(new ActorProxyBuilder(DemoActor.class)); + ActorProxyBuilder proxyBuilder = new ActorProxyBuilder(DemoActor.class, newActorClient()); logger.debug("Creating actorId"); ActorId actorId1 = new ActorId(Integer.toString(atomicInteger.getAndIncrement())); logger.debug("Building proxy"); diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActorMethodNameIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActorMethodNameIT.java new file mode 100644 index 0000000000..ef1de2e431 --- /dev/null +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActorMethodNameIT.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.it.actors; + +import io.dapr.actors.ActorId; +import io.dapr.actors.client.ActorProxy; +import io.dapr.actors.client.ActorProxyBuilder; +import io.dapr.it.BaseIT; +import io.dapr.it.actors.app.MyActor; +import io.dapr.it.actors.app.MyActorService; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static io.dapr.it.Retry.callWithRetry; +import static org.junit.Assert.assertTrue; + +public class ActorMethodNameIT extends BaseIT { + + private static Logger logger = LoggerFactory.getLogger(ActorMethodNameIT.class); + + @Test + public void actorMethodNameChange() throws Exception { + // The call below will fail if service cannot start successfully. + startDaprApp( + ActorMethodNameIT.class.getSimpleName(), + MyActorService.SUCCESS_MESSAGE, + MyActorService.class, + true, + 60000); + + logger.debug("Creating proxy builder"); + ActorProxyBuilder proxyBuilder = + new ActorProxyBuilder("MyActorTest", MyActor.class, newActorClient()); + logger.debug("Creating actorId"); + ActorId actorId1 = new ActorId("1"); + logger.debug("Building proxy"); + MyActor proxy = proxyBuilder.build(actorId1); + + callWithRetry(() -> { + logger.debug("Invoking dotNetMethod from Proxy"); + boolean response = proxy.dotNetMethod(); + logger.debug("asserting true response: [" + response + "]"); + assertTrue(response); + }, 60000); + + logger.debug("Creating proxy builder 2"); + ActorProxyBuilder proxyBuilder2 = + new ActorProxyBuilder("MyActorTest", ActorProxy.class, newActorClient()); + logger.debug("Building proxy 2"); + ActorProxy proxy2 = proxyBuilder2.build(actorId1); + + callWithRetry(() -> { + logger.debug("Invoking DotNetMethodAsync from Proxy 2"); + boolean response = proxy2.invokeMethod("DotNetMethodAsync", boolean.class).block(); + logger.debug("asserting true response 2: [" + response + "]"); + assertTrue(response); + }, 60000); + + } +} diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActorReminderFailoverIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActorReminderFailoverIT.java index 4cd0b1199e..42be26431c 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActorReminderFailoverIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActorReminderFailoverIT.java @@ -20,7 +20,9 @@ import java.util.List; import java.util.UUID; -import static io.dapr.it.actors.MyActorTestUtils.*; +import static io.dapr.it.actors.MyActorTestUtils.countMethodCalls; +import static io.dapr.it.actors.MyActorTestUtils.fetchMethodCallLogs; +import static io.dapr.it.actors.MyActorTestUtils.validateMethodCalls; import static org.junit.Assert.assertNotEquals; public class ActorReminderFailoverIT extends BaseIT { @@ -61,7 +63,8 @@ public void init() throws Exception { String actorType="MyActorTest"; logger.debug("Creating proxy builder"); - ActorProxyBuilder proxyBuilder = deferClose(new ActorProxyBuilder(actorType, ActorProxy.class)); + ActorProxyBuilder proxyBuilder = + new ActorProxyBuilder(actorType, ActorProxy.class, newActorClient()); logger.debug("Creating actorId"); logger.debug("Building proxy"); proxy = proxyBuilder.build(actorId); @@ -71,7 +74,7 @@ public void init() throws Exception { public void tearDown() { // call unregister logger.debug("Calling actor method 'stopReminder' to unregister reminder"); - proxy.invokeActorMethod("stopReminder", "myReminder").block(); + proxy.invokeMethod("stopReminder", "myReminder").block(); } /** @@ -83,7 +86,7 @@ public void reminderRecoveryTest() throws Exception { clientAppRun.use(); logger.debug("Invoking actor method 'startReminder' which will register a reminder"); - proxy.invokeActorMethod("startReminder", "myReminder").block(); + proxy.invokeMethod("startReminder", "myReminder").block(); logger.debug("Pausing 7 seconds to allow reminder to fire"); Thread.sleep(7000); @@ -92,7 +95,7 @@ public void reminderRecoveryTest() throws Exception { validateMethodCalls(logs, METHOD_NAME, 3); int originalActorHostIdentifier = Integer.parseInt( - proxy.invokeActorMethod("getIdentifier", String.class).block()); + proxy.invokeMethod("getIdentifier", String.class).block()); if (originalActorHostIdentifier == firstAppRun.getHttpPort()) { firstAppRun.stop(); } @@ -110,7 +113,7 @@ public void reminderRecoveryTest() throws Exception { validateMethodCalls(newLogs2, METHOD_NAME, countMethodCalls(newLogs, METHOD_NAME) + 4); int newActorHostIdentifier = Integer.parseInt( - proxy.invokeActorMethod("getIdentifier", String.class).block()); + proxy.invokeMethod("getIdentifier", String.class).block()); assertNotEquals(originalActorHostIdentifier, newActorHostIdentifier); } diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActorReminderRecoveryIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActorReminderRecoveryIT.java index f33c575340..504b6876ec 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActorReminderRecoveryIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActorReminderRecoveryIT.java @@ -22,7 +22,9 @@ import java.util.List; import java.util.UUID; -import static io.dapr.it.actors.MyActorTestUtils.*; +import static io.dapr.it.actors.MyActorTestUtils.countMethodCalls; +import static io.dapr.it.actors.MyActorTestUtils.fetchMethodCallLogs; +import static io.dapr.it.actors.MyActorTestUtils.validateMethodCalls; public class ActorReminderRecoveryIT extends BaseIT { @@ -49,7 +51,8 @@ public void init() throws Exception { String actorType="MyActorTest"; logger.debug("Creating proxy builder"); - ActorProxyBuilder proxyBuilder = deferClose(new ActorProxyBuilder(actorType, ActorProxy.class)); + ActorProxyBuilder proxyBuilder = + new ActorProxyBuilder(actorType, ActorProxy.class, newActorClient()); logger.debug("Creating actorId"); logger.debug("Building proxy"); proxy = proxyBuilder.build(actorId); @@ -59,7 +62,7 @@ public void init() throws Exception { public void tearDown() { // call unregister logger.debug("Calling actor method 'stopReminder' to unregister reminder"); - proxy.invokeActorMethod("stopReminder", "myReminder").block(); + proxy.invokeMethod("stopReminder", "myReminder").block(); } /** @@ -69,7 +72,7 @@ public void tearDown() { @Test public void reminderRecoveryTest() throws Exception { logger.debug("Invoking actor method 'startReminder' which will register a reminder"); - proxy.invokeActorMethod("startReminder", "myReminder").block(); + proxy.invokeMethod("startReminder", "myReminder").block(); logger.debug("Pausing 7 seconds to allow reminder to fire"); Thread.sleep(7000); diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActorStateIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActorStateIT.java index a715ac8fd0..5d152fe325 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActorStateIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActorStateIT.java @@ -8,6 +8,7 @@ import io.dapr.actors.ActorId; import io.dapr.actors.client.ActorProxy; import io.dapr.actors.client.ActorProxyBuilder; +import io.dapr.client.DaprApiProtocol; import io.dapr.it.BaseIT; import io.dapr.it.DaprRun; import io.dapr.it.actors.services.springboot.StatefulActor; @@ -22,7 +23,9 @@ import java.util.Collection; import static io.dapr.it.Retry.callWithRetry; -import static org.junit.Assert.*; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; @RunWith(Parameterized.class) public class ActorStateIT extends BaseIT { @@ -36,14 +39,19 @@ public class ActorStateIT extends BaseIT { */ @Parameterized.Parameters public static Collection data() { - return Arrays.asList(new Object[][] { { false, false }, { false, true }, { true, false }, { true, true } }); + return Arrays.asList(new Object[][] { + { DaprApiProtocol.HTTP, DaprApiProtocol.HTTP }, + { DaprApiProtocol.HTTP, DaprApiProtocol.GRPC }, + { DaprApiProtocol.GRPC, DaprApiProtocol.HTTP }, + { DaprApiProtocol.GRPC, DaprApiProtocol.GRPC }, + }); } @Parameterized.Parameter(0) - public boolean useGrpc; + public DaprApiProtocol daprClientProtocol; @Parameterized.Parameter(1) - public boolean useGrpcInService; + public DaprApiProtocol serviceAppProtocol; @Test public void writeReadState() throws Exception { @@ -55,39 +63,36 @@ public void writeReadState() throws Exception { StatefulActorService.class, true, 60000, - useGrpcInService); + serviceAppProtocol); - if (this.useGrpc) { - runtime.switchToGRPC(); - } else { - runtime.switchToHTTP(); - } + runtime.switchToProtocol(this.daprClientProtocol); String message = "This is a message to be saved and retrieved."; String name = "Jon Doe"; byte[] bytes = new byte[] { 0x1 }; ActorId actorId = new ActorId( - String.format("%d-%b-%b", System.currentTimeMillis(), this.useGrpc, this.useGrpcInService)); + String.format("%d-%b-%b", System.currentTimeMillis(), this.daprClientProtocol, this.serviceAppProtocol)); String actorType = "StatefulActorTest"; logger.debug("Building proxy ..."); - ActorProxyBuilder proxyBuilder = deferClose(new ActorProxyBuilder(actorType, ActorProxy.class)); + ActorProxyBuilder proxyBuilder = + new ActorProxyBuilder(actorType, ActorProxy.class, newActorClient()); ActorProxy proxy = proxyBuilder.build(actorId); // Validate conditional read works. callWithRetry(() -> { logger.debug("Invoking readMessage where data is not present yet ... "); - String result = proxy.invokeActorMethod("readMessage", String.class).block(); + String result = proxy.invokeMethod("readMessage", String.class).block(); assertNull(result); }, 5000); callWithRetry(() -> { logger.debug("Invoking writeMessage ... "); - proxy.invokeActorMethod("writeMessage", message).block(); + proxy.invokeMethod("writeMessage", message).block(); }, 5000); callWithRetry(() -> { logger.debug("Invoking readMessage where data is probably still cached ... "); - String result = proxy.invokeActorMethod("readMessage", String.class).block(); + String result = proxy.invokeMethod("readMessage", String.class).block(); assertEquals(message, result); }, 5000); @@ -96,45 +101,45 @@ public void writeReadState() throws Exception { mydata.value = "My data value."; callWithRetry(() -> { logger.debug("Invoking writeData with object ... "); - proxy.invokeActorMethod("writeData", mydata).block(); + proxy.invokeMethod("writeData", mydata).block(); }, 5000); callWithRetry(() -> { logger.debug("Invoking readData where data is probably still cached ... "); - StatefulActor.MyData result = proxy.invokeActorMethod("readData", StatefulActor.MyData.class).block(); + StatefulActor.MyData result = proxy.invokeMethod("readData", StatefulActor.MyData.class).block(); assertEquals(mydata.value, result.value); }, 5000); callWithRetry(() -> { logger.debug("Invoking writeName ... "); - proxy.invokeActorMethod("writeName", name).block(); + proxy.invokeMethod("writeName", name).block(); }, 5000); callWithRetry(() -> { logger.debug("Invoking readName where data is probably still cached ... "); - String result = proxy.invokeActorMethod("readName", String.class).block(); + String result = proxy.invokeMethod("readName", String.class).block(); assertEquals(name, result); }, 5000); callWithRetry(() -> { logger.debug("Invoking writeName with empty content... "); - proxy.invokeActorMethod("writeName", "").block(); + proxy.invokeMethod("writeName", "").block(); }, 5000); callWithRetry(() -> { logger.debug("Invoking readName where empty content is probably still cached ... "); - String result = proxy.invokeActorMethod("readName", String.class).block(); + String result = proxy.invokeMethod("readName", String.class).block(); assertEquals("", result); }, 5000); callWithRetry(() -> { logger.debug("Invoking writeBytes ... "); - proxy.invokeActorMethod("writeBytes", bytes).block(); + proxy.invokeMethod("writeBytes", bytes).block(); }, 5000); callWithRetry(() -> { logger.debug("Invoking readBytes where data is probably still cached ... "); - byte[] result = proxy.invokeActorMethod("readBytes", byte[].class).block(); + byte[] result = proxy.invokeMethod("readBytes", byte[].class).block(); assertArrayEquals(bytes, result); }, 5000); @@ -151,40 +156,36 @@ public void writeReadState() throws Exception { StatefulActorService.class, true, 60000, - useGrpcInService); + serviceAppProtocol); - if (this.useGrpc) { - run2.switchToGRPC(); - } else { - run2.switchToHTTP(); - } + runtime.switchToProtocol(this.daprClientProtocol); // Need new proxy builder because the proxy builder holds the channel. - proxyBuilder = deferClose(new ActorProxyBuilder(actorType, ActorProxy.class)); + proxyBuilder = new ActorProxyBuilder(actorType, ActorProxy.class, newActorClient()); ActorProxy newProxy = proxyBuilder.build(actorId); callWithRetry(() -> { logger.debug("Invoking readMessage where data is not cached ... "); - String result = newProxy.invokeActorMethod("readMessage", String.class).block(); + String result = newProxy.invokeMethod("readMessage", String.class).block(); assertEquals(message, result); }, 5000); callWithRetry(() -> { logger.debug("Invoking readData where data is not cached ... "); - StatefulActor.MyData result = newProxy.invokeActorMethod("readData", StatefulActor.MyData.class).block(); + StatefulActor.MyData result = newProxy.invokeMethod("readData", StatefulActor.MyData.class).block(); assertEquals(mydata.value, result.value); }, 5000); logger.debug("Finished testing actor string state."); callWithRetry(() -> { logger.debug("Invoking readName where empty content is not cached ... "); - String result = newProxy.invokeActorMethod("readName", String.class).block(); + String result = newProxy.invokeMethod("readName", String.class).block(); assertEquals("", result); }, 5000); callWithRetry(() -> { logger.debug("Invoking readBytes where content is not cached ... "); - byte[] result = newProxy.invokeActorMethod("readBytes", byte[].class).block(); + byte[] result = newProxy.invokeMethod("readBytes", byte[].class).block(); assertArrayEquals(bytes, result); }, 5000); } diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActorTimerRecoveryIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActorTimerRecoveryIT.java index 99c4c44ba8..09f8ffea42 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActorTimerRecoveryIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActorTimerRecoveryIT.java @@ -47,14 +47,15 @@ public void timerRecoveryTest() throws Exception { String actorType="MyActorTest"; logger.debug("Creating proxy builder"); - ActorProxyBuilder proxyBuilder = deferClose(new ActorProxyBuilder(actorType, ActorProxy.class)); + ActorProxyBuilder proxyBuilder = + new ActorProxyBuilder(actorType, ActorProxy.class, newActorClient()); logger.debug("Creating actorId"); ActorId actorId = new ActorId(UUID.randomUUID().toString()); logger.debug("Building proxy"); ActorProxy proxy = proxyBuilder.build(actorId); logger.debug("Invoking actor method 'startTimer' which will register a timer"); - proxy.invokeActorMethod("startTimer", "myTimer").block(); + proxy.invokeMethod("startTimer", "myTimer").block(); logger.debug("Pausing 7 seconds to allow timer to fire"); Thread.sleep(7000); @@ -80,7 +81,7 @@ public void timerRecoveryTest() throws Exception { // call unregister logger.debug("Calling actor method 'stopTimer' to unregister timer"); - proxy.invokeActorMethod("stopTimer", "myTimer").block(); + proxy.invokeMethod("stopTimer", "myTimer").block(); } } diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActorTurnBasedConcurrencyIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActorTurnBasedConcurrencyIT.java index dd101ebf0f..7cb19d3d76 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActorTurnBasedConcurrencyIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActorTurnBasedConcurrencyIT.java @@ -80,7 +80,8 @@ public void actorTest1() throws Exception { String actorType="MyActorTest"; logger.debug("Creating proxy builder"); - ActorProxyBuilder proxyBuilder = deferClose(new ActorProxyBuilder(actorType, ActorProxy.class)); + ActorProxyBuilder proxyBuilder = + new ActorProxyBuilder(actorType, ActorProxy.class, newActorClient()); logger.debug("Creating actorId"); ActorId actorId1 = new ActorId(ACTOR_ID); logger.debug("Building proxy"); @@ -89,13 +90,13 @@ public void actorTest1() throws Exception { logger.debug("Invoking Say from Proxy"); callWithRetry(() -> { logger.debug("Invoking Say from Proxy"); - String sayResponse = proxy.invokeActorMethod("say", "message", String.class).block(); + String sayResponse = proxy.invokeMethod("say", "message", String.class).block(); logger.debug("asserting not null response: [" + sayResponse + "]"); assertNotNull(sayResponse); }, 60000); logger.debug("Invoking actor method 'startTimer' which will register a timer"); - proxy.invokeActorMethod("startTimer", "myTimer").block(); + proxy.invokeMethod("startTimer", "myTimer").block(); // invoke a bunch of calls in parallel to validate turn-based concurrency logger.debug("Invoking an actor method 'say' in parallel"); @@ -108,12 +109,12 @@ public void actorTest1() throws Exception { // the actor method called below should reverse the input String msg = "message" + i; String reversedString = new StringBuilder(msg).reverse().toString(); - String output = proxy.invokeActorMethod("say", "message" + i, String.class).block(); + String output = proxy.invokeMethod("say", "message" + i, String.class).block(); assertTrue(reversedString.equals(output)); }); logger.debug("Calling method to register reminder named " + REMINDER_NAME); - proxy.invokeActorMethod("startReminder", REMINDER_NAME).block(); + proxy.invokeMethod("startReminder", REMINDER_NAME).block(); logger.debug("Pausing 7 seconds to allow timer and reminders to fire"); Thread.sleep(7000); @@ -126,14 +127,14 @@ public void actorTest1() throws Exception { // call unregister logger.debug("Calling actor method 'stopTimer' to unregister timer"); - proxy.invokeActorMethod("stopTimer", "myTimer").block(); + proxy.invokeMethod("stopTimer", "myTimer").block(); logger.debug("Calling actor method 'stopReminder' to unregister reminder"); - proxy.invokeActorMethod("stopReminder", REMINDER_NAME).block(); + proxy.invokeMethod("stopReminder", REMINDER_NAME).block(); // make some more actor method calls and sleep a bit to see if the timer fires (it should not) sayMessages.parallelStream().forEach( i -> { - proxy.invokeActorMethod("say", "message" + i, String.class).block(); + proxy.invokeMethod("say", "message" + i, String.class).block(); }); logger.debug("Pausing 5 seconds to allow time for timer and reminders to fire if there is a bug. They should not since we have unregistered them."); diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/MyActorTestUtils.java b/sdk-tests/src/test/java/io/dapr/it/actors/MyActorTestUtils.java index fb58958107..a95fa4a51a 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/MyActorTestUtils.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/MyActorTestUtils.java @@ -54,7 +54,7 @@ static void validateMethodCalls(List logs, String methodName * @return List of call log. */ static List fetchMethodCallLogs(ActorProxy proxy) { - ArrayList logs = proxy.invokeActorMethod("getCallLog", ArrayList.class).block(); + ArrayList logs = proxy.invokeMethod("getCallLog", ArrayList.class).block(); ArrayList trackers = new ArrayList(); for(String t : logs) { String[] toks = t.split("\\|"); diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/app/MyActor.java b/sdk-tests/src/test/java/io/dapr/it/actors/app/MyActor.java index 00084b5dc0..4d082dd344 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/app/MyActor.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/app/MyActor.java @@ -5,6 +5,8 @@ package io.dapr.it.actors.app; +import io.dapr.actors.ActorMethod; + import java.util.ArrayList; import java.util.List; @@ -26,4 +28,7 @@ public interface MyActor { ArrayList getCallLog(); String getIdentifier(); + + @ActorMethod(name = "DotNetMethodAsync") + boolean dotNetMethod(); } \ No newline at end of file diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/app/MyActorImpl.java b/sdk-tests/src/test/java/io/dapr/it/actors/app/MyActorImpl.java index 89679711ae..35b731a85a 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/app/MyActorImpl.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/app/MyActorImpl.java @@ -199,6 +199,11 @@ public String getIdentifier() { return System.getenv("DAPR_HTTP_PORT"); } + @Override + public boolean dotNetMethod() { + return true; + } + private void formatAndLog(boolean isEnter, String methodName) { Calendar utcNow = Calendar.getInstance(TimeZone.getTimeZone("GMT")); diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/app/TestApplication.java b/sdk-tests/src/test/java/io/dapr/it/actors/app/TestApplication.java index 4a1089e95d..b774e9b697 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/app/TestApplication.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/app/TestApplication.java @@ -11,7 +11,7 @@ /** * Dapr's HTTP callback implementation via SpringBoot. */ -@SpringBootApplication(scanBasePackages = {"io.dapr.springboot", "io.dapr.it.actors.app"}) +@SpringBootApplication public class TestApplication { /** diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/services/springboot/DaprApplication.java b/sdk-tests/src/test/java/io/dapr/it/actors/services/springboot/DaprApplication.java index 520b2db573..a417cf7d35 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/services/springboot/DaprApplication.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/services/springboot/DaprApplication.java @@ -11,7 +11,7 @@ /** * Dapr's HTTP callback implementation via SpringBoot. */ -@SpringBootApplication(scanBasePackages = {"io.dapr.springboot", "io.dapr.it.actors.services.springboot"}) +@SpringBootApplication public class DaprApplication { /** diff --git a/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java b/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java index cb3b8c9413..2368e57836 100644 --- a/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java @@ -95,7 +95,7 @@ public void inputOutputBinding() throws Exception { callWithRetry(() -> { System.out.println("Checking results ..."); final List messages = - client.invokeService( + client.invokeMethod( daprRun.getAppName(), "messages", null, diff --git a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeController.java b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeController.java index 8f1a676ee5..cbc5319f8e 100644 --- a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeController.java +++ b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeController.java @@ -1,8 +1,18 @@ package io.dapr.it.methodinvoke.http; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; /** * SpringBoot Controller to handle input binding. @@ -69,4 +79,9 @@ public void deletePerson(@PathVariable Integer personId){ public List getPersons() { return persons; } + + @PostMapping(path = "/sleep") + public void sleep(@RequestBody int seconds) throws InterruptedException { + Thread.sleep(seconds * 1000); + } } diff --git a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeIT.java b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeIT.java index fd1f26dbf6..df273c2ad9 100644 --- a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeIT.java @@ -10,7 +10,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import java.io.IOException; +import java.time.Duration; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; @@ -19,6 +19,8 @@ import java.util.Map; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import static org.junit.runners.Parameterized.Parameter; import static org.junit.runners.Parameterized.Parameters; @@ -74,21 +76,21 @@ public void testInvoke() throws Exception { for (int i = 0; i < NUM_MESSAGES; i++) { String message = String.format("This is message #%d", i); //Publishing messages - client.invokeService(daprRun.getAppName(), "messages", message.getBytes(), HttpExtension.POST).block(); + client.invokeMethod(daprRun.getAppName(), "messages", message.getBytes(), HttpExtension.POST).block(); System.out.println("Invoke method messages : " + message); } - Map messages = client.invokeService(daprRun.getAppName(), "messages", null, + Map messages = client.invokeMethod(daprRun.getAppName(), "messages", null, HttpExtension.GET, Map.class).block(); assertEquals(10, messages.size()); - client.invokeService(daprRun.getAppName(), "messages/1", null, HttpExtension.DELETE).block(); + client.invokeMethod(daprRun.getAppName(), "messages/1", null, HttpExtension.DELETE).block(); - messages = client.invokeService(daprRun.getAppName(), "messages", null, HttpExtension.GET, Map.class).block(); + messages = client.invokeMethod(daprRun.getAppName(), "messages", null, HttpExtension.GET, Map.class).block(); assertEquals(9, messages.size()); - client.invokeService(daprRun.getAppName(), "messages/2", "updated message".getBytes(), HttpExtension.PUT).block(); - messages = client.invokeService(daprRun.getAppName(), "messages", null, HttpExtension.GET, Map.class).block(); + client.invokeMethod(daprRun.getAppName(), "messages/2", "updated message".getBytes(), HttpExtension.PUT).block(); + messages = client.invokeMethod(daprRun.getAppName(), "messages", null, HttpExtension.GET, Map.class).block(); assertEquals("updated message", messages.get("2")); } } @@ -102,16 +104,16 @@ public void testInvokeWithObjects() throws Exception { person.setLastName(String.format("Last Name %d", i)); person.setBirthDate(new Date()); //Publishing messages - client.invokeService(daprRun.getAppName(), "persons", person, HttpExtension.POST).block(); + client.invokeMethod(daprRun.getAppName(), "persons", person, HttpExtension.POST).block(); System.out.println("Invoke method persons with parameter : " + person); } - List persons = Arrays.asList(client.invokeService(daprRun.getAppName(), "persons", null, HttpExtension.GET, Person[].class).block()); + List persons = Arrays.asList(client.invokeMethod(daprRun.getAppName(), "persons", null, HttpExtension.GET, Person[].class).block()); assertEquals(10, persons.size()); - client.invokeService(daprRun.getAppName(), "persons/1", null, HttpExtension.DELETE).block(); + client.invokeMethod(daprRun.getAppName(), "persons/1", null, HttpExtension.DELETE).block(); - persons = Arrays.asList(client.invokeService(daprRun.getAppName(), "persons", null, HttpExtension.GET, Person[].class).block()); + persons = Arrays.asList(client.invokeMethod(daprRun.getAppName(), "persons", null, HttpExtension.GET, Person[].class).block()); assertEquals(9, persons.size()); Person person = new Person(); @@ -119,12 +121,26 @@ public void testInvokeWithObjects() throws Exception { person.setLastName("Smith"); person.setBirthDate(Calendar.getInstance().getTime()); - client.invokeService(daprRun.getAppName(), "persons/2", person, HttpExtension.PUT).block(); + client.invokeMethod(daprRun.getAppName(), "persons/2", person, HttpExtension.PUT).block(); - persons = Arrays.asList(client.invokeService(daprRun.getAppName(), "persons", null, HttpExtension.GET, Person[].class).block()); + persons = Arrays.asList(client.invokeMethod(daprRun.getAppName(), "persons", null, HttpExtension.GET, Person[].class).block()); Person resultPerson = persons.get(1); assertEquals("John", resultPerson.getName()); assertEquals("Smith", resultPerson.getLastName()); } } + + @Test + public void testInvokeTimeout() throws Exception { + try (DaprClient client = new DaprClientBuilder().build()) { + long started = System.currentTimeMillis(); + String message = assertThrows(IllegalStateException.class, () -> { + client.invokeMethod(daprRun.getAppName(), "sleep", 1, HttpExtension.POST) + .block(Duration.ofMillis(10)); + }).getMessage(); + long delay = System.currentTimeMillis() - started; + assertTrue(delay <= 200); // 200 ms is a reasonable delay if the request timed out. + assertEquals("Timeout on blocking read for 10 MILLISECONDS", message); + } + } } diff --git a/sdk-tests/src/test/java/io/dapr/it/pubsub/http/PubSubIT.java b/sdk-tests/src/test/java/io/dapr/it/pubsub/http/PubSubIT.java index f2c0aa9507..38123eb5e8 100644 --- a/sdk-tests/src/test/java/io/dapr/it/pubsub/http/PubSubIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/pubsub/http/PubSubIT.java @@ -7,20 +7,23 @@ import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; -import io.dapr.client.DaprHttp; import io.dapr.client.domain.HttpExtension; +import io.dapr.client.domain.Metadata; import io.dapr.it.BaseIT; import io.dapr.it.DaprRun; +import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import static io.dapr.it.Retry.callWithRetry; +import static io.dapr.it.TestUtils.assertThrowsDaprException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -34,6 +37,8 @@ public class PubSubIT extends BaseIT { //The title of the topic to be used for publishing private static final String TOPIC_NAME = "testingtopic"; private static final String ANOTHER_TOPIC_NAME = "anothertopic"; + // Topic used for TTL test + private static final String TTL_TOPIC_NAME = "ttltopic"; /** * Parameters for this test. @@ -49,16 +54,57 @@ public static Collection data() { @Parameterized.Parameter public boolean useGrpc; + private final List runs = new ArrayList<>(); + + private DaprRun closeLater(DaprRun run) { + this.runs.add(run); + return run; + } + + @After + public void tearDown() throws Exception { + for (DaprRun run : runs) { + run.stop(); + } + } + + @Test + public void publishPubSubNotFound() throws Exception { + DaprRun daprRun = closeLater(startDaprApp( + this.getClass().getSimpleName(), + 60000)); + if (this.useGrpc) { + daprRun.switchToGRPC(); + } else { + daprRun.switchToHTTP(); + } + + try (DaprClient client = new DaprClientBuilder().build()) { + + if (this.useGrpc) { + assertThrowsDaprException( + "INVALID_ARGUMENT", + "INVALID_ARGUMENT: pubsub unknown pubsub not found", + () -> client.publishEvent("unknown pubsub", "mytopic", "payload").block()); + } else { + assertThrowsDaprException( + "ERR_PUBSUB_NOT_FOUND", + "ERR_PUBSUB_NOT_FOUND: pubsub unknown pubsub not found", + () -> client.publishEvent("unknown pubsub", "mytopic", "payload").block()); + } + } + } + @Test public void testPubSub() throws Exception { System.out.println("Working Directory = " + System.getProperty("user.dir")); - final DaprRun daprRun = startDaprApp( + final DaprRun daprRun = closeLater(startDaprApp( this.getClass().getSimpleName(), SubscriberService.SUCCESS_MESSAGE, SubscriberService.class, true, - 60000); + 60000)); // At this point, it is guaranteed that the service above is running and all ports being listened to. if (this.useGrpc) { daprRun.switchToGRPC(); @@ -95,7 +141,7 @@ public void testPubSub() throws Exception { callWithRetry(() -> { System.out.println("Checking results for topic " + TOPIC_NAME); - final List messages = client.invokeService(daprRun.getAppName(), "messages/testingtopic", null, HttpExtension.GET, List.class).block(); + final List messages = client.invokeMethod(daprRun.getAppName(), "messages/testingtopic", null, HttpExtension.GET, List.class).block(); assertEquals(11, messages.size()); for (int i = 0; i < NUM_MESSAGES; i++) { assertTrue(messages.toString(), messages.contains(String.format("This is message #%d on topic %s", i, TOPIC_NAME))); @@ -113,7 +159,7 @@ public void testPubSub() throws Exception { callWithRetry(() -> { System.out.println("Checking results for topic " + ANOTHER_TOPIC_NAME); - final List messages = client.invokeService(daprRun.getAppName(), "messages/anothertopic", null, HttpExtension.GET, List.class).block(); + final List messages = client.invokeMethod(daprRun.getAppName(), "messages/anothertopic", null, HttpExtension.GET, List.class).block(); assertEquals(10, messages.size()); for (int i = 0; i < NUM_MESSAGES; i++) { @@ -123,4 +169,62 @@ public void testPubSub() throws Exception { } } + @Test + public void testPubSubTTLMetadata() throws Exception { + System.out.println("Working Directory = " + System.getProperty("user.dir")); + + DaprRun daprRun = closeLater(startDaprApp( + this.getClass().getSimpleName(), + 60000)); + if (this.useGrpc) { + daprRun.switchToGRPC(); + } else { + daprRun.switchToHTTP(); + } + + // Send a batch of messages on one topic, all to be expired in 1 second. + try (DaprClient client = new DaprClientBuilder().build()) { + for (int i = 0; i < NUM_MESSAGES; i++) { + String message = String.format("This is message #%d on topic %s", i, TTL_TOPIC_NAME); + //Publishing messages + client.publishEvent( + PUBSUB_NAME, + TTL_TOPIC_NAME, + message, + Collections.singletonMap(Metadata.TTL_IN_SECONDS, "1")).block(); + System.out.println(String.format("Published message: '%s' to topic '%s' pubsub_name '%s'", message, TOPIC_NAME, PUBSUB_NAME)); + } + } + + daprRun.stop(); + + // Sleeps for two seconds to let them expire. + Thread.sleep(2000); + + daprRun = closeLater(startDaprApp( + this.getClass().getSimpleName(), + SubscriberService.SUCCESS_MESSAGE, + SubscriberService.class, + true, + 60000)); + if (this.useGrpc) { + daprRun.switchToGRPC(); + } else { + daprRun.switchToHTTP(); + } + + // Sleeps for five seconds to give subscriber a chance to receive messages. + Thread.sleep(5000); + + final String appId = daprRun.getAppName(); + try (DaprClient client = new DaprClientBuilder().build()) { + callWithRetry(() -> { + System.out.println("Checking results for topic " + TTL_TOPIC_NAME); + final List messages = client.invokeMethod(appId, "messages/" + TTL_TOPIC_NAME, null, HttpExtension.GET, List.class).block(); + assertEquals(0, messages.size()); + }, 2000); + } + + daprRun.stop(); + } } diff --git a/sdk-tests/src/test/java/io/dapr/it/pubsub/http/SubscriberController.java b/sdk-tests/src/test/java/io/dapr/it/pubsub/http/SubscriberController.java index ed2fe08c7d..7b7f68fbcd 100644 --- a/sdk-tests/src/test/java/io/dapr/it/pubsub/http/SubscriberController.java +++ b/sdk-tests/src/test/java/io/dapr/it/pubsub/http/SubscriberController.java @@ -7,13 +7,14 @@ import io.dapr.Topic; import io.dapr.client.domain.CloudEvent; -import io.dapr.serializer.DefaultObjectSerializer; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; import java.util.ArrayList; import java.util.List; -import java.util.Map; /** * SpringBoot Controller to handle input binding. @@ -21,29 +22,31 @@ @RestController public class SubscriberController { - private static final List messagesReceivedTestingTopic = new ArrayList(); - private static final List messagesReceivedAnotherTopic = new ArrayList(); + private static final List messagesReceivedTestingTopic = new ArrayList(); + private static final List messagesReceivedAnotherTopic = new ArrayList(); + private static final List messagesReceivedTTLTopic = new ArrayList(); @GetMapping(path = "/messages/testingtopic") - public List getMessagesReceivedTestingTopic() { + public List getMessagesReceivedTestingTopic() { return messagesReceivedTestingTopic; } @GetMapping(path = "/messages/anothertopic") - public List getMessagesReceivedAnotherTopic() { + public List getMessagesReceivedAnotherTopic() { return messagesReceivedAnotherTopic; } + @GetMapping(path = "/messages/ttltopic") + public List getMessagesReceivedTTLTopic() { + return messagesReceivedTTLTopic; + } + @Topic(name = "testingtopic", pubsubName = "messagebus") @PostMapping(path = "/route1") - public Mono handleMessage(@RequestBody(required = false) byte[] body, - @RequestHeader Map headers) { + public Mono handleMessage(@RequestBody(required = false) CloudEvent envelope) { return Mono.fromRunnable(() -> { try { - // Dapr's event is compliant to CloudEvent. - CloudEvent envelope = CloudEvent.deserialize(body); - - String message = envelope.getData() == null ? "" : envelope.getData(); + String message = envelope.getData() == null ? "" : envelope.getData().toString(); System.out.println("Testing topic Subscriber got message: " + message); messagesReceivedTestingTopic.add(envelope.getData()); } catch (Exception e) { @@ -54,14 +57,10 @@ public Mono handleMessage(@RequestBody(required = false) byte[] body, @Topic(name = "anothertopic", pubsubName = "messagebus") @PostMapping(path = "/route2") - public Mono handleMessageAnotherTopic(@RequestBody(required = false) byte[] body, - @RequestHeader Map headers) { + public Mono handleMessageAnotherTopic(@RequestBody(required = false) CloudEvent envelope) { return Mono.fromRunnable(() -> { try { - // Dapr's event is compliant to CloudEvent. - CloudEvent envelope = CloudEvent.deserialize(body); - - String message = envelope.getData() == null ? "" : envelope.getData(); + String message = envelope.getData() == null ? "" : envelope.getData().toString(); System.out.println("Another topic Subscriber got message: " + message); messagesReceivedAnotherTopic.add(envelope.getData()); } catch (Exception e) { @@ -70,4 +69,18 @@ public Mono handleMessageAnotherTopic(@RequestBody(required = false) byte[ }); } + @Topic(name = "ttltopic", pubsubName = "messagebus") + @PostMapping(path = "/route3") + public Mono handleMessageTTLTopic(@RequestBody(required = false) CloudEvent envelope) { + return Mono.fromRunnable(() -> { + try { + String message = envelope.getData() == null ? "" : envelope.getData().toString(); + System.out.println("TTL topic Subscriber got message: " + message); + messagesReceivedTTLTopic.add(envelope.getData()); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } + } diff --git a/sdk-tests/src/test/java/io/dapr/it/pubsub/http/SubscriberService.java b/sdk-tests/src/test/java/io/dapr/it/pubsub/http/SubscriberService.java index 801ccac595..91c3fc5bba 100644 --- a/sdk-tests/src/test/java/io/dapr/it/pubsub/http/SubscriberService.java +++ b/sdk-tests/src/test/java/io/dapr/it/pubsub/http/SubscriberService.java @@ -12,7 +12,7 @@ /** * Service for subscriber. */ -@SpringBootApplication(scanBasePackages = {"io.dapr.springboot", "io.dapr.it.pubsub.http"}) +@SpringBootApplication public class SubscriberService { public static final String SUCCESS_MESSAGE = "Completed initialization in"; diff --git a/sdk-tests/src/test/java/io/dapr/it/secrets/SecretsClientIT.java b/sdk-tests/src/test/java/io/dapr/it/secrets/SecretsClientIT.java index d6fd45dcd1..45cea437c0 100644 --- a/sdk-tests/src/test/java/io/dapr/it/secrets/SecretsClientIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/secrets/SecretsClientIT.java @@ -9,8 +9,6 @@ import com.bettercloud.vault.VaultConfig; import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; -import io.dapr.client.DaprClientGrpc; -import io.dapr.client.DaprClientHttp; import io.dapr.it.BaseIT; import io.dapr.it.DaprRun; import org.junit.After; @@ -20,14 +18,15 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.UUID; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * Test Secrets Store APIs using Harshicorp's vault. @@ -80,7 +79,7 @@ public static void init() throws Exception { } @Before - public void setup() throws Exception { + public void setup() { if (this.useGrpc) { daprRun.switchToGRPC(); } else { @@ -88,11 +87,6 @@ public void setup() throws Exception { } this.daprClient = new DaprClientBuilder().build(); - if (this.useGrpc) { - assertEquals(DaprClientGrpc.class, this.daprClient.getClass()); - } else { - assertEquals(DaprClientHttp.class, this.daprClient.getClass()); - } } @After @@ -112,6 +106,26 @@ public void getSecret() throws Exception { assertEquals("The Metrics IV", data.get("title")); } + @Test + public void getBulkSecret() throws Exception { + String key1 = UUID.randomUUID().toString(); + writeSecret(key1, new HashMap<>() {{ + put("title", "The Metrics IV"); + put("year", "2020"); + }}); + String key2 = UUID.randomUUID().toString(); + writeSecret(key2, "name", "Jon Doe"); + + Map> data = daprClient.getBulkSecret(SECRETS_STORE_NAME).block(); + // There can be other keys from other runs or test cases, so we are good with at least two. + assertTrue(data.size() >= 2); + assertEquals(2, data.get(key1).size()); + assertEquals("The Metrics IV", data.get(key1).get("title")); + assertEquals("2020", data.get(key1).get("year")); + assertEquals(1, data.get(key2).size()); + assertEquals("Jon Doe", data.get(key2).get("name")); + } + @Test(expected = RuntimeException.class) public void getSecretKeyNotFound() { daprClient.getSecret(SECRETS_STORE_NAME, "unknownKey").block(); @@ -123,7 +137,10 @@ public void getSecretStoreNotFound() throws Exception { } private static void writeSecret(String secretName, String key, String value) throws Exception { - Map secrets = Collections.singletonMap(key, value); + writeSecret(secretName, Collections.singletonMap(key, value)); + } + + private static void writeSecret(String secretName, Map secrets) throws Exception { vault.logical().write("secret/" + PREFIX + "/" + secretName, secrets); } diff --git a/sdk-tests/src/test/java/io/dapr/it/state/AbstractStateClientIT.java b/sdk-tests/src/test/java/io/dapr/it/state/AbstractStateClientIT.java index eaf59c73b7..ea6f918406 100644 --- a/sdk-tests/src/test/java/io/dapr/it/state/AbstractStateClientIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/state/AbstractStateClientIT.java @@ -18,12 +18,9 @@ import java.util.Collections; import java.util.List; import java.util.UUID; -import java.util.concurrent.ExecutionException; -import static io.dapr.it.TestUtils.assertThrowsDaprException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; /** * Common test cases for Dapr client (GRPC and HTTP). @@ -74,13 +71,11 @@ public void getStateKeyNotFound() { Assert.assertNotNull(state); Assert.assertEquals("unknownKey", state.getKey()); Assert.assertNull(state.getValue()); - // gRPC returns empty eTag while HTTP returns null. - // TODO(artursouza): https://github.com/dapr/java-sdk/issues/405 - Assert.assertTrue(state.getEtag() == null || state.getEtag().isEmpty()); + Assert.assertNull(state.getEtag()); } @Test - public void saveAndGetBulkStates() { + public void saveAndGetBulkState() { final String stateKeyOne = UUID.randomUUID().toString(); final String stateKeyTwo = UUID.randomUUID().toString(); final String stateKeyThree = "NotFound"; @@ -97,7 +92,7 @@ public void saveAndGetBulkStates() { //retrieves states in bulk. Mono>> response = - daprClient.getStates(STATE_STORE_NAME, Arrays.asList(stateKeyOne, stateKeyTwo, stateKeyThree), MyData.class); + daprClient.getBulkState(STATE_STORE_NAME, Arrays.asList(stateKeyOne, stateKeyTwo, stateKeyThree), MyData.class); List> result = response.block(); //Assert that the response is the correct one @@ -114,8 +109,8 @@ public void saveAndGetBulkStates() { assertEquals(stateKeyThree, result.stream().skip(2).findFirst().get().getKey()); assertNull(result.stream().skip(2).findFirst().get().getValue()); - assertEquals("", result.stream().skip(2).findFirst().get().getEtag()); - assertNull("not found", result.stream().skip(2).findFirst().get().getError()); + assertNull(result.stream().skip(2).findFirst().get().getEtag()); + assertNull(result.stream().skip(2).findFirst().get().getError()); } @Test @@ -519,7 +514,7 @@ public void saveVerifyAndDeleteTransactionalStateString() { createState(stateKey, null, null, data)); //create of the deferred call to DAPR to execute the transaction - Mono saveResponse = daprClient.executeTransaction(STATE_STORE_NAME, Collections.singletonList(operation)); + Mono saveResponse = daprClient.executeStateTransaction(STATE_STORE_NAME, Collections.singletonList(operation)); //execute the save action saveResponse.block(); @@ -538,7 +533,7 @@ public void saveVerifyAndDeleteTransactionalStateString() { TransactionalStateOperation.OperationType.DELETE, createState(stateKey, null, null, data)); //create of the deferred call to DAPR to execute the transaction - Mono deleteResponse = daprClient.executeTransaction(STATE_STORE_NAME, Collections.singletonList(operation)); + Mono deleteResponse = daprClient.executeStateTransaction(STATE_STORE_NAME, Collections.singletonList(operation)); //execute the delete action deleteResponse.block(); @@ -568,7 +563,7 @@ public void saveVerifyAndDeleteTransactionalState() { Assert.assertNotNull(daprClient); //create of the deferred call to DAPR to execute the transaction - Mono saveResponse = daprClient.executeTransaction(STATE_STORE_NAME, Collections.singletonList(operation)); + Mono saveResponse = daprClient.executeStateTransaction(STATE_STORE_NAME, Collections.singletonList(operation)); //execute the save action saveResponse.block(); @@ -589,7 +584,7 @@ public void saveVerifyAndDeleteTransactionalState() { TransactionalStateOperation.OperationType.DELETE, createState(stateKey, null, null, data)); //create of the deferred call to DAPR to execute the transaction - Mono deleteResponse = daprClient.executeTransaction(STATE_STORE_NAME, Collections.singletonList(operation)); + Mono deleteResponse = daprClient.executeStateTransaction(STATE_STORE_NAME, Collections.singletonList(operation)); //execute the delete action deleteResponse.block(); diff --git a/sdk-tests/src/test/java/io/dapr/it/state/GRPCStateClientIT.java b/sdk-tests/src/test/java/io/dapr/it/state/GRPCStateClientIT.java index 40f12b4f62..51d2a2b7f8 100644 --- a/sdk-tests/src/test/java/io/dapr/it/state/GRPCStateClientIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/state/GRPCStateClientIT.java @@ -7,18 +7,15 @@ import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; -import io.dapr.client.DaprClientGrpc; import io.dapr.client.domain.State; import io.dapr.it.DaprRun; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import java.io.IOException; import java.util.Collections; import static io.dapr.it.TestUtils.assertThrowsDaprException; -import static org.junit.Assert.assertTrue; /** * Test State GRPC DAPR capabilities using a DAPR instance with an empty service running @@ -34,8 +31,6 @@ public static void init() throws Exception { daprRun = startDaprApp(GRPCStateClientIT.class.getSimpleName(), 5000); daprRun.switchToGRPC(); daprClient = new DaprClientBuilder().build(); - - assertTrue(daprClient instanceof DaprClientGrpc); } @AfterClass @@ -73,20 +68,10 @@ public void getStatesStoreNotFound() { assertThrowsDaprException( "INVALID_ARGUMENT", "INVALID_ARGUMENT: state store unknown state store is not found", - () -> daprClient.getStates( + () -> daprClient.getBulkState( "unknown state store", Collections.singletonList(stateKey), byte[].class).block()); } - @Test - public void publishPubSubNotFound() { - DaprClient daprClient = buildDaprClient(); - - // DaprException is guaranteed in the Dapr SDK but getCause() is null in HTTP while present in GRPC implementation. - assertThrowsDaprException( - "NOT_FOUND", - "NOT_FOUND: pubsub 'unknown pubsub' not found", - () -> daprClient.publishEvent("unknown pubsub", "mytopic", "payload").block()); - } } diff --git a/sdk-tests/src/test/java/io/dapr/it/state/HttpStateClientIT.java b/sdk-tests/src/test/java/io/dapr/it/state/HttpStateClientIT.java index 62f29aefb8..9ddf1e1ec5 100644 --- a/sdk-tests/src/test/java/io/dapr/it/state/HttpStateClientIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/state/HttpStateClientIT.java @@ -14,7 +14,6 @@ import org.junit.BeforeClass; import org.junit.Test; -import java.io.IOException; import java.util.Collections; import static io.dapr.it.TestUtils.assertThrowsDaprException; @@ -58,7 +57,7 @@ public void getStateStoreNotFound() { // DaprException is guaranteed in the Dapr SDK but getCause() is null in HTTP while present in GRPC implementation. assertThrowsDaprException( "ERR_STATE_STORE_NOT_FOUND", - "ERR_STATE_STORE_NOT_FOUND: state store unknown%20state%20store is not found", + "ERR_STATE_STORE_NOT_FOUND: state store unknown state store is not found", () -> daprClient.getState("unknown state store", new State(stateKey), byte[].class).block()); } @@ -71,8 +70,8 @@ public void getStatesStoreNotFound() { // DaprException is guaranteed in the Dapr SDK but getCause() is null in HTTP while present in GRPC implementation. assertThrowsDaprException( "ERR_STATE_STORE_NOT_FOUND", - "ERR_STATE_STORE_NOT_FOUND: state store unknown%20state%20store is not found", - () -> daprClient.getStates( + "ERR_STATE_STORE_NOT_FOUND: state store unknown state store is not found", + () -> daprClient.getBulkState( "unknown state store", Collections.singletonList(stateKey), byte[].class).block()); @@ -82,10 +81,6 @@ public void getStatesStoreNotFound() { public void publishPubSubNotFound() { DaprClient daprClient = buildDaprClient(); - // DaprException is guaranteed in the Dapr SDK but getCause() is null in HTTP while present in GRPC implementation. - assertThrowsDaprException( - "ERR_PUBSUB_NOT_FOUND", - "ERR_PUBSUB_NOT_FOUND: pubsub 'unknown%20pubsub' not found", - () -> daprClient.publishEvent("unknown pubsub", "mytopic", "payload").block()); + } } diff --git a/sdk/src/main/java/io/dapr/client/AbstractDaprClient.java b/sdk/src/main/java/io/dapr/client/AbstractDaprClient.java index 35128f63c4..f435d2e00d 100644 --- a/sdk/src/main/java/io/dapr/client/AbstractDaprClient.java +++ b/sdk/src/main/java/io/dapr/client/AbstractDaprClient.java @@ -9,16 +9,18 @@ import io.dapr.client.domain.DeleteStateRequestBuilder; import io.dapr.client.domain.ExecuteStateTransactionRequest; import io.dapr.client.domain.ExecuteStateTransactionRequestBuilder; +import io.dapr.client.domain.GetBulkSecretRequest; +import io.dapr.client.domain.GetBulkSecretRequestBuilder; +import io.dapr.client.domain.GetBulkStateRequestBuilder; import io.dapr.client.domain.GetSecretRequest; import io.dapr.client.domain.GetSecretRequestBuilder; import io.dapr.client.domain.GetStateRequest; import io.dapr.client.domain.GetStateRequestBuilder; -import io.dapr.client.domain.GetStatesRequestBuilder; import io.dapr.client.domain.HttpExtension; import io.dapr.client.domain.InvokeBindingRequest; import io.dapr.client.domain.InvokeBindingRequestBuilder; -import io.dapr.client.domain.InvokeServiceRequest; -import io.dapr.client.domain.InvokeServiceRequestBuilder; +import io.dapr.client.domain.InvokeMethodRequest; +import io.dapr.client.domain.InvokeMethodRequestBuilder; import io.dapr.client.domain.PublishEventRequest; import io.dapr.client.domain.PublishEventRequestBuilder; import io.dapr.client.domain.SaveStateRequest; @@ -72,155 +74,155 @@ abstract class AbstractDaprClient implements DaprClient { * {@inheritDoc} */ @Override - public Mono publishEvent(String pubsubName, String topic, Object data) { - return this.publishEvent(pubsubName, topic, data, null); + public Mono publishEvent(String pubsubName, String topicName, Object data) { + return this.publishEvent(pubsubName, topicName, data, null); } /** * {@inheritDoc} */ @Override - public Mono publishEvent(String pubsubName, String topic, Object data, Map metadata) { - PublishEventRequest req = new PublishEventRequestBuilder(pubsubName, topic, data).withMetadata(metadata).build(); + public Mono publishEvent(String pubsubName, String topicName, Object data, Map metadata) { + PublishEventRequest req = new PublishEventRequestBuilder(pubsubName, topicName, + data).withMetadata(metadata).build(); return this.publishEvent(req).then(); } /** * {@inheritDoc} */ - public Mono invokeService( + public Mono invokeMethod( String appId, - String method, - Object request, + String methodName, + Object data, HttpExtension httpExtension, Map metadata, TypeRef type) { - InvokeServiceRequestBuilder builder = new InvokeServiceRequestBuilder(appId, method); - InvokeServiceRequest req = builder - .withBody(request) + InvokeMethodRequestBuilder builder = new InvokeMethodRequestBuilder(appId, methodName); + InvokeMethodRequest req = builder + .withBody(data) .withHttpExtension(httpExtension) - .withMetadata(metadata) .withContentType(objectSerializer.getContentType()) .build(); - return this.invokeService(req, type).map(r -> r.getObject()); + return this.invokeMethod(req, type).map(r -> r.getObject()); } /** * {@inheritDoc} */ @Override - public Mono invokeService( + public Mono invokeMethod( String appId, - String method, + String methodName, Object request, HttpExtension httpExtension, Map metadata, Class clazz) { - return this.invokeService(appId, method, request, httpExtension, metadata, TypeRef.get(clazz)); + return this.invokeMethod(appId, methodName, request, httpExtension, metadata, TypeRef.get(clazz)); } /** * {@inheritDoc} */ @Override - public Mono invokeService( - String appId, String method, HttpExtension httpExtension, Map metadata, TypeRef type) { - return this.invokeService(appId, method, null, httpExtension, metadata, type); + public Mono invokeMethod( + String appId, String methodName, HttpExtension httpExtension, Map metadata, TypeRef type) { + return this.invokeMethod(appId, methodName, null, httpExtension, metadata, type); } /** * {@inheritDoc} */ @Override - public Mono invokeService( - String appId, String method, HttpExtension httpExtension, Map metadata, Class clazz) { - return this.invokeService(appId, method, null, httpExtension, metadata, TypeRef.get(clazz)); + public Mono invokeMethod( + String appId, String methodName, HttpExtension httpExtension, Map metadata, Class clazz) { + return this.invokeMethod(appId, methodName, null, httpExtension, metadata, TypeRef.get(clazz)); } /** * {@inheritDoc} */ @Override - public Mono invokeService(String appId, String method, Object request, HttpExtension httpExtension, - TypeRef type) { - return this.invokeService(appId, method, request, httpExtension, null, type); + public Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + TypeRef type) { + return this.invokeMethod(appId, methodName, request, httpExtension, null, type); } /** * {@inheritDoc} */ @Override - public Mono invokeService(String appId, String method, Object request, HttpExtension httpExtension, - Class clazz) { - return this.invokeService(appId, method, request, httpExtension, null, TypeRef.get(clazz)); + public Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + Class clazz) { + return this.invokeMethod(appId, methodName, request, httpExtension, null, TypeRef.get(clazz)); } /** * {@inheritDoc} */ @Override - public Mono invokeService(String appId, String method, Object request, HttpExtension httpExtension) { - return this.invokeService(appId, method, request, httpExtension, null, TypeRef.BYTE_ARRAY).then(); + public Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension) { + return this.invokeMethod(appId, methodName, request, httpExtension, null, TypeRef.BYTE_ARRAY).then(); } /** * {@inheritDoc} */ @Override - public Mono invokeService( - String appId, String method, Object request, HttpExtension httpExtension, Map metadata) { - return this.invokeService(appId, method, request, httpExtension, metadata, TypeRef.BYTE_ARRAY).then(); + public Mono invokeMethod( + String appId, String methodName, Object request, HttpExtension httpExtension, Map metadata) { + return this.invokeMethod(appId, methodName, request, httpExtension, metadata, TypeRef.BYTE_ARRAY).then(); } /** * {@inheritDoc} */ @Override - public Mono invokeService( - String appId, String method, HttpExtension httpExtension, Map metadata) { - return this.invokeService(appId, method, null, httpExtension, metadata, TypeRef.BYTE_ARRAY).then(); + public Mono invokeMethod( + String appId, String methodName, HttpExtension httpExtension, Map metadata) { + return this.invokeMethod(appId, methodName, null, httpExtension, metadata, TypeRef.BYTE_ARRAY).then(); } /** * {@inheritDoc} */ @Override - public Mono invokeService( - String appId, String method, byte[] request, HttpExtension httpExtension, Map metadata) { - return this.invokeService(appId, method, request, httpExtension, metadata, TypeRef.BYTE_ARRAY); + public Mono invokeMethod( + String appId, String methodName, byte[] request, HttpExtension httpExtension, Map metadata) { + return this.invokeMethod(appId, methodName, request, httpExtension, metadata, TypeRef.BYTE_ARRAY); } /** * {@inheritDoc} */ @Override - public Mono invokeBinding(String name, String operation, Object data) { - return this.invokeBinding(name, operation, data, null, TypeRef.BYTE_ARRAY).then(); + public Mono invokeBinding(String bindingName, String operation, Object data) { + return this.invokeBinding(bindingName, operation, data, null, TypeRef.BYTE_ARRAY).then(); } /** * {@inheritDoc} */ @Override - public Mono invokeBinding(String name, String operation, byte[] data, Map metadata) { - return this.invokeBinding(name, operation, data, metadata, TypeRef.BYTE_ARRAY); + public Mono invokeBinding(String bindingName, String operation, byte[] data, Map metadata) { + return this.invokeBinding(bindingName, operation, data, metadata, TypeRef.BYTE_ARRAY); } /** * {@inheritDoc} */ @Override - public Mono invokeBinding(String name, String operation, Object data, TypeRef type) { - return this.invokeBinding(name, operation, data, null, type); + public Mono invokeBinding(String bindingName, String operation, Object data, TypeRef type) { + return this.invokeBinding(bindingName, operation, data, null, type); } /** * {@inheritDoc} */ @Override - public Mono invokeBinding(String name, String operation, Object data, Class clazz) { - return this.invokeBinding(name, operation, data, null, TypeRef.get(clazz)); + public Mono invokeBinding(String bindingName, String operation, Object data, Class clazz) { + return this.invokeBinding(bindingName, operation, data, null, TypeRef.get(clazz)); } /** @@ -228,8 +230,8 @@ public Mono invokeBinding(String name, String operation, Object data, Cla */ @Override public Mono invokeBinding( - String name, String operation, Object data, Map metadata, TypeRef type) { - InvokeBindingRequest request = new InvokeBindingRequestBuilder(name, operation) + String bindingName, String operation, Object data, Map metadata, TypeRef type) { + InvokeBindingRequest request = new InvokeBindingRequestBuilder(bindingName, operation) .withData(data) .withMetadata(metadata) .build(); @@ -242,40 +244,40 @@ public Mono invokeBinding( */ @Override public Mono invokeBinding( - String name, String operation, Object data, Map metadata, Class clazz) { - return this.invokeBinding(name, operation, data, metadata, TypeRef.get(clazz)); + String bindingName, String operation, Object data, Map metadata, Class clazz) { + return this.invokeBinding(bindingName, operation, data, metadata, TypeRef.get(clazz)); } /** * {@inheritDoc} */ @Override - public Mono> getState(String stateStoreName, State state, TypeRef type) { - return this.getState(stateStoreName, state.getKey(), state.getEtag(), state.getOptions(), type); + public Mono> getState(String storeName, State state, TypeRef type) { + return this.getState(storeName, state.getKey(), state.getOptions(), type); } /** * {@inheritDoc} */ @Override - public Mono> getState(String stateStoreName, State state, Class clazz) { - return this.getState(stateStoreName, state.getKey(), state.getEtag(), state.getOptions(), TypeRef.get(clazz)); + public Mono> getState(String storeName, State state, Class clazz) { + return this.getState(storeName, state.getKey(), state.getOptions(), TypeRef.get(clazz)); } /** * {@inheritDoc} */ @Override - public Mono> getState(String stateStoreName, String key, TypeRef type) { - return this.getState(stateStoreName, key, null, null, type); + public Mono> getState(String storeName, String key, TypeRef type) { + return this.getState(storeName, key, null, type); } /** * {@inheritDoc} */ @Override - public Mono> getState(String stateStoreName, String key, Class clazz) { - return this.getState(stateStoreName, key, null, null, TypeRef.get(clazz)); + public Mono> getState(String storeName, String key, Class clazz) { + return this.getState(storeName, key, null, TypeRef.get(clazz)); } /** @@ -283,9 +285,8 @@ public Mono> getState(String stateStoreName, String key, Class c */ @Override public Mono> getState( - String stateStoreName, String key, String etag, StateOptions options, TypeRef type) { - GetStateRequest request = new GetStateRequestBuilder(stateStoreName, key) - .withEtag(etag) + String storeName, String key, StateOptions options, TypeRef type) { + GetStateRequest request = new GetStateRequestBuilder(storeName, key) .withStateOptions(options) .build(); return this.getState(request, type).map(r -> r.getObject()); @@ -297,80 +298,80 @@ public Mono> getState( */ @Override public Mono> getState( - String stateStoreName, String key, String etag, StateOptions options, Class clazz) { - return this.getState(stateStoreName, key, etag, options, TypeRef.get(clazz)); + String storeName, String key, StateOptions options, Class clazz) { + return this.getState(storeName, key, options, TypeRef.get(clazz)); } /** * {@inheritDoc} */ @Override - public Mono>> getStates(String stateStoreName, List keys, TypeRef type) { - return this.getStates(new GetStatesRequestBuilder(stateStoreName, keys).build(), type).map(r -> r.getObject()); + public Mono>> getBulkState(String storeName, List keys, TypeRef type) { + return this.getBulkState(new GetBulkStateRequestBuilder(storeName, keys).build(), type).map(r -> r.getObject()); } /** * {@inheritDoc} */ @Override - public Mono>> getStates(String stateStoreName, List keys, Class clazz) { - return this.getStates(stateStoreName, keys, TypeRef.get(clazz)); + public Mono>> getBulkState(String storeName, List keys, Class clazz) { + return this.getBulkState(storeName, keys, TypeRef.get(clazz)); } /** * {@inheritDoc} */ @Override - public Mono executeTransaction(String stateStoreName, - List> operations) { - ExecuteStateTransactionRequest request = new ExecuteStateTransactionRequestBuilder(stateStoreName) + public Mono executeStateTransaction(String storeName, + List> operations) { + ExecuteStateTransactionRequest request = new ExecuteStateTransactionRequestBuilder(storeName) .withTransactionalStates(operations) .build(); - return executeTransaction(request).then(); + return executeStateTransaction(request).then(); } /** * {@inheritDoc} */ @Override - public Mono saveStates(String stateStoreName, List> states) { - SaveStateRequest request = new SaveStateRequestBuilder(stateStoreName) + public Mono saveBulkState(String storeName, List> states) { + SaveStateRequest request = new SaveStateRequestBuilder(storeName) .withStates(states) .build(); - return this.saveStates(request).then(); + return this.saveBulkState(request).then(); } /** * {@inheritDoc} */ @Override - public Mono saveState(String stateStoreName, String key, Object value) { - return this.saveState(stateStoreName, key, null, value, null); + public Mono saveState(String storeName, String key, Object value) { + return this.saveState(storeName, key, null, value, null); } /** * {@inheritDoc} */ @Override - public Mono saveState(String stateStoreName, String key, String etag, Object value, StateOptions options) { + public Mono saveState(String storeName, String key, String etag, Object value, StateOptions options) { State state = new State<>(value, key, etag, options); - return this.saveStates(stateStoreName, Collections.singletonList(state)); + return this.saveBulkState(storeName, Collections.singletonList(state)); } /** * {@inheritDoc} */ @Override - public Mono deleteState(String stateStoreName, String key) { - return this.deleteState(stateStoreName, key, null, null); + public Mono deleteState(String storeName, String key) { + return this.deleteState(storeName, key, null, null); } /** * {@inheritDoc} */ @Override - public Mono deleteState(String stateStoreName, String key, String etag, StateOptions options) { - DeleteStateRequest request = new DeleteStateRequestBuilder(stateStoreName, key) + public Mono deleteState(String storeName, String key, String etag, StateOptions options) { + DeleteStateRequest request = new DeleteStateRequestBuilder(storeName, key) .withEtag(etag) .withStateOptions(options) .build(); @@ -381,8 +382,8 @@ public Mono deleteState(String stateStoreName, String key, String etag, St * {@inheritDoc} */ @Override - public Mono> getSecret(String secretStoreName, String key, Map metadata) { - GetSecretRequest request = new GetSecretRequestBuilder(secretStoreName, key) + public Mono> getSecret(String storeName, String key, Map metadata) { + GetSecretRequest request = new GetSecretRequestBuilder(storeName, key) .withMetadata(metadata) .build(); return getSecret(request).map(r -> r.getObject() == null ? new HashMap<>() : r.getObject()); @@ -392,8 +393,27 @@ public Mono> getSecret(String secretStoreName, String key, M * {@inheritDoc} */ @Override - public Mono> getSecret(String secretStoreName, String secretName) { - return this.getSecret(secretStoreName, secretName, null); + public Mono> getSecret(String storeName, String secretName) { + return this.getSecret(storeName, secretName, null); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono>> getBulkSecret(String storeName) { + return this.getBulkSecret(storeName, null); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono>> getBulkSecret(String storeName, Map metadata) { + GetBulkSecretRequest request = new GetBulkSecretRequestBuilder(storeName) + .withMetadata(metadata) + .build(); + return this.getBulkSecret(request).map(r -> r.getObject() == null ? Collections.EMPTY_MAP : r.getObject()); } } \ No newline at end of file diff --git a/sdk/src/main/java/io/dapr/client/DaprApiProtocol.java b/sdk/src/main/java/io/dapr/client/DaprApiProtocol.java new file mode 100644 index 0000000000..84eb1d77e6 --- /dev/null +++ b/sdk/src/main/java/io/dapr/client/DaprApiProtocol.java @@ -0,0 +1,16 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.client; + +/** + * Transport protocol for Dapr's API. + */ +public enum DaprApiProtocol { + + GRPC, + HTTP + +} diff --git a/sdk/src/main/java/io/dapr/client/DaprClient.java b/sdk/src/main/java/io/dapr/client/DaprClient.java index 81a4388459..12feb99c21 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClient.java +++ b/sdk/src/main/java/io/dapr/client/DaprClient.java @@ -7,12 +7,13 @@ import io.dapr.client.domain.DeleteStateRequest; import io.dapr.client.domain.ExecuteStateTransactionRequest; +import io.dapr.client.domain.GetBulkSecretRequest; +import io.dapr.client.domain.GetBulkStateRequest; import io.dapr.client.domain.GetSecretRequest; import io.dapr.client.domain.GetStateRequest; -import io.dapr.client.domain.GetStatesRequest; import io.dapr.client.domain.HttpExtension; import io.dapr.client.domain.InvokeBindingRequest; -import io.dapr.client.domain.InvokeServiceRequest; +import io.dapr.client.domain.InvokeMethodRequest; import io.dapr.client.domain.PublishEventRequest; import io.dapr.client.domain.Response; import io.dapr.client.domain.SaveStateRequest; @@ -22,7 +23,6 @@ import io.dapr.utils.TypeRef; import reactor.core.publisher.Mono; -import java.io.Closeable; import java.util.List; import java.util.Map; @@ -33,26 +33,33 @@ */ public interface DaprClient extends AutoCloseable { + /** + * Waits for the sidecar, giving up after timeout. + * @param timeoutInMilliseconds Timeout in milliseconds to wait for sidecar. + * @return a Mono plan of type Void. + */ + Mono waitForSidecar(int timeoutInMilliseconds); + /** * Publish an event. * * @param pubsubName the pubsub name we will publish the event to - * @param topic the topic where the event will be published. + * @param topicName the topicName where the event will be published. * @param data the event's data to be published, use byte[] for skipping serialization. * @return a Mono plan of type Void. */ - Mono publishEvent(String pubsubName, String topic, Object data); + Mono publishEvent(String pubsubName, String topicName, Object data); /** * Publish an event. * * @param pubsubName the pubsub name we will publish the event to - * @param topic the topic where the event will be published. + * @param topicName the topicName where the event will be published. * @param data the event's data to be published, use byte[] for skipping serialization. * @param metadata The metadata for the published event. * @return a Mono plan of type Void. */ - Mono publishEvent(String pubsubName, String topic, Object data, Map metadata); + Mono publishEvent(String pubsubName, String topicName, Object data, Map metadata); /** * Publish an event. @@ -66,23 +73,23 @@ public interface DaprClient extends AutoCloseable { * Invoke a service method, using serialization. * * @param appId The Application ID where the service is. - * @param method The actual Method to be call in the application. - * @param request The request to be sent to invoke the service, use byte[] to skip serialization. + * @param methodName The actual Method to be call in the application. + * @param data The data to be sent to invoke the service, use byte[] to skip serialization. * @param httpExtension Additional fields that are needed if the receiving app is listening on * HTTP, {@link io.dapr.client.domain.HttpExtension#NONE} otherwise. - * @param metadata Metadata (in GRPC) or headers (in HTTP) to be sent in request. + * @param metadata Metadata (in GRPC) or headers (in HTTP) to be sent in data. * @param type The Type needed as return for the call. * @param The Type of the return, use byte[] to skip serialization. * @return A Mono Plan of type T. */ - Mono invokeService(String appId, String method, Object request, HttpExtension httpExtension, - Map metadata, TypeRef type); + Mono invokeMethod(String appId, String methodName, Object data, HttpExtension httpExtension, + Map metadata, TypeRef type); /** * Invoke a service method, using serialization. * * @param appId The Application ID where the service is. - * @param method The actual Method to be call in the application. + * @param methodName The actual Method to be call in the application. * @param request The request to be sent to invoke the service, use byte[] to skip serialization. * @param httpExtension Additional fields that are needed if the receiving app is listening on * HTTP, {@link HttpExtension#NONE} otherwise. @@ -91,14 +98,14 @@ Mono invokeService(String appId, String method, Object request, HttpExten * @param The Type of the return, use byte[] to skip serialization. * @return A Mono Plan of type T. */ - Mono invokeService(String appId, String method, Object request, HttpExtension httpExtension, - Map metadata, Class clazz); + Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + Map metadata, Class clazz); /** * Invoke a service method, using serialization. * * @param appId The Application ID where the service is. - * @param method The actual Method to be call in the application. + * @param methodName The actual Method to be call in the application. * @param request The request to be sent to invoke the service, use byte[] to skip serialization. * @param httpExtension Additional fields that are needed if the receiving app is listening on * HTTP, {@link HttpExtension#NONE} otherwise. @@ -106,13 +113,14 @@ Mono invokeService(String appId, String method, Object request, HttpExten * @param The Type of the return, use byte[] to skip serialization. * @return A Mono Plan of type T. */ - Mono invokeService(String appId, String method, Object request, HttpExtension httpExtension, TypeRef type); + Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + TypeRef type); /** * Invoke a service method, using serialization. * * @param appId The Application ID where the service is. - * @param method The actual Method to be call in the application. + * @param methodName The actual Method to be call in the application. * @param request The request to be sent to invoke the service, use byte[] to skip serialization. * @param httpExtension Additional fields that are needed if the receiving app is listening on * HTTP, {@link HttpExtension#NONE} otherwise. @@ -120,13 +128,14 @@ Mono invokeService(String appId, String method, Object request, HttpExten * @param The Type of the return, use byte[] to skip serialization. * @return A Mono Plan of type T. */ - Mono invokeService(String appId, String method, Object request, HttpExtension httpExtension, Class clazz); + Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + Class clazz); /** * Invoke a service method, using serialization. * * @param appId The Application ID where the service is. - * @param method The actual Method to be call in the application. + * @param methodName The actual Method to be call in the application. * @param httpExtension Additional fields that are needed if the receiving app is listening on * HTTP, {@link HttpExtension#NONE} otherwise. * @param metadata Metadata (in GRPC) or headers (in HTTP) to be sent in request. @@ -134,14 +143,14 @@ Mono invokeService(String appId, String method, Object request, HttpExten * @param The Type of the return, use byte[] to skip serialization. * @return A Mono Plan of type T. */ - Mono invokeService(String appId, String method, HttpExtension httpExtension, Map metadata, - TypeRef type); + Mono invokeMethod(String appId, String methodName, HttpExtension httpExtension, Map metadata, + TypeRef type); /** * Invoke a service method, using serialization. * * @param appId The Application ID where the service is. - * @param method The actual Method to be call in the application. + * @param methodName The actual Method to be call in the application. * @param httpExtension Additional fields that are needed if the receiving app is listening on * HTTP, {@link HttpExtension#NONE} otherwise. * @param metadata Metadata (in GRPC) or headers (in HTTP) to be sent in request. @@ -149,120 +158,120 @@ Mono invokeService(String appId, String method, HttpExtension httpExtensi * @param The Type of the return, use byte[] to skip serialization. * @return A Mono Plan of type T. */ - Mono invokeService(String appId, String method, HttpExtension httpExtension, Map metadata, - Class clazz); + Mono invokeMethod(String appId, String methodName, HttpExtension httpExtension, Map metadata, + Class clazz); /** * Invoke a service method, using serialization. * * @param appId The Application ID where the service is. - * @param method The actual Method to be call in the application. + * @param methodName The actual Method to be call in the application. * @param request The request to be sent to invoke the service, use byte[] to skip serialization. * @param httpExtension Additional fields that are needed if the receiving app is listening on * HTTP, {@link HttpExtension#NONE} otherwise. * @param metadata Metadata (in GRPC) or headers (in HTTP) to be sent in request. * @return A Mono Plan of type Void. */ - Mono invokeService(String appId, String method, Object request, HttpExtension httpExtension, - Map metadata); + Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + Map metadata); /** * Invoke a service method, using serialization. * * @param appId The Application ID where the service is. - * @param method The actual Method to be call in the application. + * @param methodName The actual Method to be call in the application. * @param request The request to be sent to invoke the service, use byte[] to skip serialization. * @param httpExtension Additional fields that are needed if the receiving app is listening on * HTTP, {@link HttpExtension#NONE} otherwise. * @return A Mono Plan of type Void. */ - Mono invokeService(String appId, String method, Object request, HttpExtension httpExtension); + Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension); /** * Invoke a service method, using serialization. * * @param appId The Application ID where the service is. - * @param method The actual Method to be call in the application. + * @param methodName The actual Method to be call in the application. * @param httpExtension Additional fields that are needed if the receiving app is listening on * HTTP, {@link HttpExtension#NONE} otherwise. * @param metadata Metadata (in GRPC) or headers (in HTTP) to be sent in request. * @return A Mono Plan of type Void. */ - Mono invokeService(String appId, String method, HttpExtension httpExtension, Map metadata); + Mono invokeMethod(String appId, String methodName, HttpExtension httpExtension, Map metadata); /** * Invoke a service method, without using serialization. * * @param appId The Application ID where the service is. - * @param method The actual Method to be call in the application. + * @param methodName The actual Method to be call in the application. * @param request The request to be sent to invoke the service, use byte[] to skip serialization. * @param httpExtension Additional fields that are needed if the receiving app is listening on * HTTP, {@link HttpExtension#NONE} otherwise. * @param metadata Metadata (in GRPC) or headers (in HTTP) to be sent in request. * @return A Mono Plan of type byte[]. */ - Mono invokeService(String appId, String method, byte[] request, HttpExtension httpExtension, - Map metadata); + Mono invokeMethod(String appId, String methodName, byte[] request, HttpExtension httpExtension, + Map metadata); /** * Invoke a service method. * - * @param invokeServiceRequest Request object. + * @param invokeMethodRequest Request object. * @param type The Type needed as return for the call. * @param The Type of the return, use byte[] to skip serialization. * @return A Mono Plan of type T. */ - Mono> invokeService(InvokeServiceRequest invokeServiceRequest, TypeRef type); + Mono> invokeMethod(InvokeMethodRequest invokeMethodRequest, TypeRef type); /** * Invokes a Binding operation. * - * @param name The name of the biding to call. + * @param bindingName The bindingName of the biding to call. * @param operation The operation to be performed by the binding request processor. * @param data The data to be processed, use byte[] to skip serialization. * @return an empty Mono. */ - Mono invokeBinding(String name, String operation, Object data); + Mono invokeBinding(String bindingName, String operation, Object data); /** * Invokes a Binding operation, skipping serialization. * - * @param name The name of the biding to call. + * @param bindingName The name of the biding to call. * @param operation The operation to be performed by the binding request processor. * @param data The data to be processed, skipping serialization. * @param metadata The metadata map. * @return a Mono plan of type byte[]. */ - Mono invokeBinding(String name, String operation, byte[] data, Map metadata); + Mono invokeBinding(String bindingName, String operation, byte[] data, Map metadata); /** * Invokes a Binding operation. * - * @param name The name of the biding to call. + * @param bindingName The name of the biding to call. * @param operation The operation to be performed by the binding request processor. * @param data The data to be processed, use byte[] to skip serialization. * @param type The type being returned. * @param The type of the return * @return a Mono plan of type T. */ - Mono invokeBinding(String name, String operation, Object data, TypeRef type); + Mono invokeBinding(String bindingName, String operation, Object data, TypeRef type); /** * Invokes a Binding operation. * - * @param name The name of the biding to call. + * @param bindingName The name of the biding to call. * @param operation The operation to be performed by the binding request processor. * @param data The data to be processed, use byte[] to skip serialization. * @param clazz The type being returned. * @param The type of the return * @return a Mono plan of type T. */ - Mono invokeBinding(String name, String operation, Object data, Class clazz); + Mono invokeBinding(String bindingName, String operation, Object data, Class clazz); /** * Invokes a Binding operation. * - * @param name The name of the biding to call. + * @param bindingName The name of the biding to call. * @param operation The operation to be performed by the binding request processor. * @param data The data to be processed, use byte[] to skip serialization. * @param metadata The metadata map. @@ -270,12 +279,13 @@ Mono invokeService(String appId, String method, byte[] request, HttpExte * @param The type of the return * @return a Mono plan of type T. */ - Mono invokeBinding(String name, String operation, Object data, Map metadata, TypeRef type); + Mono invokeBinding(String bindingName, String operation, Object data, Map metadata, + TypeRef type); /** * Invokes a Binding operation. * - * @param name The name of the biding to call. + * @param bindingName The name of the biding to call. * @param operation The operation to be performed by the binding request processor. * @param data The data to be processed, use byte[] to skip serialization. * @param metadata The metadata map. @@ -283,7 +293,8 @@ Mono invokeService(String appId, String method, byte[] request, HttpExte * @param The type of the return * @return a Mono plan of type T. */ - Mono invokeBinding(String name, String operation, Object data, Map metadata, Class clazz); + Mono invokeBinding(String bindingName, String operation, Object data, Map metadata, + Class clazz); /** * Invokes a Binding operation. @@ -298,72 +309,70 @@ Mono invokeService(String appId, String method, byte[] request, HttpExte /** * Retrieve a State based on their key. * - * @param stateStoreName The name of the state store. + * @param storeName The name of the state store. * @param state State to be re-retrieved. * @param type The type of State needed as return. * @param The type of the return. * @return A Mono Plan for the requested State. */ - Mono> getState(String stateStoreName, State state, TypeRef type); + Mono> getState(String storeName, State state, TypeRef type); /** * Retrieve a State based on their key. * - * @param stateStoreName The name of the state store. + * @param storeName The name of the state store. * @param state State to be re-retrieved. * @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(String stateStoreName, State state, Class clazz); + Mono> getState(String storeName, State state, Class clazz); /** * Retrieve a State based on their key. * - * @param stateStoreName The name of the state store. + * @param storeName The name of the state store. * @param key The key of the State to be retrieved. * @param type The type of State needed as return. * @param The type of the return. * @return A Mono Plan for the requested State. */ - Mono> getState(String stateStoreName, String key, TypeRef type); + Mono> getState(String storeName, String key, TypeRef type); /** * Retrieve a State based on their key. * - * @param stateStoreName The name of the state store. + * @param storeName The name of the state store. * @param key The key of the State to be retrieved. * @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(String stateStoreName, String key, Class clazz); + Mono> getState(String storeName, String key, Class clazz); /** * Retrieve a State based on their key. * - * @param stateStoreName The name of the state store. + * @param storeName The name of the state store. * @param key The key of the State to be retrieved. - * @param etag Optional etag for conditional get * @param options Optional settings for retrieve operation. * @param type The Type of State needed as return. * @param The Type of the return. * @return A Mono Plan for the requested State. */ - Mono> getState(String stateStoreName, String key, String etag, StateOptions options, TypeRef type); + Mono> getState(String storeName, String key, StateOptions options, TypeRef type); /** * Retrieve a State based on their key. * - * @param stateStoreName The name of the state store. + * @param storeName The name of the state store. * @param key The key of the State to be retrieved. - * @param etag Optional etag for conditional get * @param options Optional settings for retrieve operation. * @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(String stateStoreName, String key, String etag, StateOptions options, Class clazz); + Mono> getState(String storeName, String key, StateOptions options, Class clazz); /** * Retrieve a State based on their key. @@ -378,24 +387,24 @@ Mono invokeService(String appId, String method, byte[] request, HttpExte /** * Retrieve bulk States based on their keys. * - * @param stateStoreName The name of the state store. + * @param storeName The name of the state store. * @param keys The keys of the State to be retrieved. * @param type The type of State needed as return. * @param The type of the return. * @return A Mono Plan for the requested State. */ - Mono>> getStates(String stateStoreName, List keys, TypeRef type); + Mono>> getBulkState(String storeName, List keys, TypeRef type); /** * Retrieve bulk States based on their keys. * - * @param stateStoreName The name of the state store. + * @param storeName The name of the state store. * @param keys The keys of the State to be retrieved. * @param clazz The type of State needed as return. * @param The type of the return. * @return A Mono Plan for the requested State. */ - Mono>> getStates(String stateStoreName, List keys, Class clazz); + Mono>> getBulkState(String storeName, List keys, Class clazz); /** * Retrieve bulk States based on their keys. @@ -405,16 +414,16 @@ Mono invokeService(String appId, String method, byte[] request, HttpExte * @param The Type of the return. * @return A Mono Plan for the requested State. */ - Mono>>> getStates(GetStatesRequest request, TypeRef type); + Mono>>> getBulkState(GetBulkStateRequest request, TypeRef type); /** Execute a transaction. * - * @param stateStoreName The name of the state store. + * @param storeName The name of the state store. * @param operations The operations to be performed. * @return a Mono plan of type Void */ - Mono executeTransaction(String stateStoreName, - List> operations); + Mono executeStateTransaction(String storeName, + List> operations); /** Execute a transaction. @@ -422,16 +431,16 @@ Mono executeTransaction(String stateStoreName, * @param request Request to execute transaction. * @return a Mono plan of type Response Void */ - Mono> executeTransaction(ExecuteStateTransactionRequest request); + Mono> executeStateTransaction(ExecuteStateTransactionRequest request); /** * Save/Update a list of states. * - * @param stateStoreName The name of the state store. + * @param storeName The name of the state store. * @param states The States to be saved. * @return a Mono plan of type Void. */ - Mono saveStates(String stateStoreName, List> states); + Mono saveBulkState(String storeName, List> states); /** * Save/Update a list of states. @@ -439,49 +448,49 @@ Mono executeTransaction(String stateStoreName, * @param request Request to save states. * @return a Mono plan of type Void. */ - Mono> saveStates(SaveStateRequest request); + Mono> saveBulkState(SaveStateRequest request); /** * Save/Update a state. * - * @param stateStoreName The name of the state store. + * @param storeName The name of the state store. * @param key The key of the state. * @param value The value of the state. * @return a Mono plan of type Void. */ - Mono saveState(String stateStoreName, String key, Object value); + Mono saveState(String storeName, String key, Object value); /** * Save/Update a state. * - * @param stateStoreName The name of the state store. + * @param storeName The name of the state store. * @param key The key of the state. * @param etag The etag to be used. * @param value The value of the state. * @param options The Options to use for each state. * @return a Mono plan of type Void. */ - Mono saveState(String stateStoreName, String key, String etag, Object value, StateOptions options); + Mono saveState(String storeName, String key, String etag, Object value, StateOptions options); /** * Delete a state. * - * @param stateStoreName The name of the state store. + * @param storeName The name of the state store. * @param key The key of the State to be removed. * @return a Mono plan of type Void. */ - Mono deleteState(String stateStoreName, String key); + Mono deleteState(String storeName, String key); /** * Delete a state. * - * @param stateStoreName The name of the state store. + * @param storeName The name of the state store. * @param key The key of the State to be removed. * @param etag Optional etag for conditional delete. * @param options Optional settings for state operation. * @return a Mono plan of type Void. */ - Mono deleteState(String stateStoreName, String key, String etag, StateOptions options); + Mono deleteState(String storeName, String key, String etag, StateOptions options); /** * Delete a state. @@ -494,21 +503,21 @@ Mono executeTransaction(String stateStoreName, /** * Fetches a secret from the configured vault. * - * @param secretStoreName Name of vault component in Dapr. + * @param storeName Name of vault component in Dapr. * @param secretName Secret to be fetched. * @param metadata Optional metadata. * @return Key-value pairs for the secret. */ - Mono> getSecret(String secretStoreName, String secretName, Map metadata); + Mono> getSecret(String storeName, String secretName, Map metadata); /** * Fetches a secret from the configured vault. * - * @param secretStoreName Name of vault component in Dapr. + * @param storeName Name of vault component in Dapr. * @param secretName Secret to be fetched. * @return Key-value pairs for the secret. */ - Mono> getSecret(String secretStoreName, String secretName); + Mono> getSecret(String storeName, String secretName); /** * Fetches a secret from the configured vault. @@ -517,4 +526,29 @@ Mono executeTransaction(String stateStoreName, * @return Key-value pairs for the secret. */ Mono>> getSecret(GetSecretRequest request); + + /** + * Fetches all secrets from the configured vault. + * + * @param storeName Name of vault component in Dapr. + * @return Key-value pairs for all the secrets in the state store. + */ + Mono>> getBulkSecret(String storeName); + + /** + * Fetches all secrets from the configured vault. + * + * @param storeName Name of vault component in Dapr. + * @param metadata Optional metadata. + * @return Key-value pairs for all the secrets in the state store. + */ + Mono>> getBulkSecret(String storeName, Map metadata); + + /** + * Fetches all secrets from the configured vault. + * + * @param request Request to fetch secret. + * @return Key-value pairs for the secret. + */ + Mono>>> getBulkSecret(GetBulkSecretRequest request); } \ No newline at end of file diff --git a/sdk/src/main/java/io/dapr/client/DaprClientBuilder.java b/sdk/src/main/java/io/dapr/client/DaprClientBuilder.java index 64f6593623..884e024ad0 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientBuilder.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientBuilder.java @@ -14,8 +14,6 @@ import java.io.Closeable; -import static io.dapr.exceptions.DaprException.throwIllegalArgumentException; - /** * A builder for the DaprClient, * Currently only and HTTP Client will be supported. @@ -26,7 +24,12 @@ public class DaprClientBuilder { /** * Determine if this builder will create GRPC clients instead of HTTP clients. */ - private final boolean useGrpc; + private final DaprApiProtocol apiProtocol; + + /** + * Determine if this builder will use HTTP client for service method invocation APIs. + */ + private final DaprApiProtocol methodInvocationApiProtocol; /** * Builder for Dapr's HTTP Client. @@ -52,7 +55,8 @@ public class DaprClientBuilder { public DaprClientBuilder() { this.objectSerializer = new DefaultObjectSerializer(); this.stateSerializer = new DefaultObjectSerializer(); - this.useGrpc = Properties.USE_GRPC.get(); + this.apiProtocol = Properties.API_PROTOCOL.get(); + this.methodInvocationApiProtocol = Properties.API_METHOD_INVOCATION_PROTOCOL.get(); this.daprHttpBuilder = new DaprHttpBuilder(); } @@ -65,11 +69,11 @@ public DaprClientBuilder() { */ public DaprClientBuilder withObjectSerializer(DaprObjectSerializer objectSerializer) { if (objectSerializer == null) { - throwIllegalArgumentException("Object serializer is required"); + throw new IllegalArgumentException("Object serializer is required"); } if (objectSerializer.getContentType() == null || objectSerializer.getContentType().isEmpty()) { - throwIllegalArgumentException("Content Type should not be null or empty"); + throw new IllegalArgumentException("Content Type should not be null or empty"); } this.objectSerializer = objectSerializer; @@ -85,7 +89,7 @@ public DaprClientBuilder withObjectSerializer(DaprObjectSerializer objectSeriali */ public DaprClientBuilder withStateSerializer(DaprObjectSerializer stateSerializer) { if (stateSerializer == null) { - throwIllegalArgumentException("State serializer is required"); + throw new IllegalArgumentException("State serializer is required"); } this.stateSerializer = stateSerializer; @@ -99,11 +103,30 @@ public DaprClientBuilder withStateSerializer(DaprObjectSerializer stateSerialize * @throws java.lang.IllegalStateException if any required field is missing */ public DaprClient build() { - if (this.useGrpc) { - return buildDaprClientGrpc(); + if (this.apiProtocol != this.methodInvocationApiProtocol) { + return new DaprClientProxy(buildDaprClient(this.apiProtocol), buildDaprClient(this.methodInvocationApiProtocol)); + } + + return buildDaprClient(this.apiProtocol); + } + + /** + * Creates an instance of a Dapr Client based on the chosen protocol. + * + * @param protocol Dapr API's protocol. + * @return the GRPC Client. + * @throws java.lang.IllegalStateException if either host is missing or if port is missing or a negative number. + */ + private DaprClient buildDaprClient(DaprApiProtocol protocol) { + if (protocol == null) { + throw new IllegalStateException("Protocol is required."); } - return buildDaprClientHttp(); + switch (protocol) { + case GRPC: return buildDaprClientGrpc(); + case HTTP: return buildDaprClientHttp(); + default: throw new IllegalStateException("Unsupported protocol: " + protocol.name()); + } } /** @@ -115,7 +138,7 @@ public DaprClient build() { private DaprClient buildDaprClientGrpc() { int port = Properties.GRPC_PORT.get(); if (port <= 0) { - throwIllegalArgumentException("Invalid port."); + throw new IllegalArgumentException("Invalid port."); } ManagedChannel channel = ManagedChannelBuilder.forAddress( Properties.SIDECAR_IP.get(), port).usePlaintext().build(); @@ -124,8 +147,8 @@ private DaprClient buildDaprClientGrpc() { channel.shutdown(); } }; - DaprGrpc.DaprFutureStub stub = DaprGrpc.newFutureStub(channel); - return new DaprClientGrpc(closeableChannel, stub, this.objectSerializer, this.stateSerializer); + DaprGrpc.DaprStub asyncStub = DaprGrpc.newStub(channel); + return new DaprClientGrpc(closeableChannel, asyncStub, this.objectSerializer, this.stateSerializer); } /** diff --git a/sdk/src/main/java/io/dapr/client/DaprClientGrpc.java b/sdk/src/main/java/io/dapr/client/DaprClientGrpc.java index 4bb010da3f..47176a4041 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientGrpc.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientGrpc.java @@ -6,17 +6,18 @@ package io.dapr.client; import com.google.common.base.Strings; -import com.google.common.util.concurrent.ListenableFuture; import com.google.protobuf.Any; import com.google.protobuf.ByteString; +import com.google.protobuf.Empty; import io.dapr.client.domain.DeleteStateRequest; import io.dapr.client.domain.ExecuteStateTransactionRequest; +import io.dapr.client.domain.GetBulkSecretRequest; +import io.dapr.client.domain.GetBulkStateRequest; import io.dapr.client.domain.GetSecretRequest; import io.dapr.client.domain.GetStateRequest; -import io.dapr.client.domain.GetStatesRequest; import io.dapr.client.domain.HttpExtension; import io.dapr.client.domain.InvokeBindingRequest; -import io.dapr.client.domain.InvokeServiceRequest; +import io.dapr.client.domain.InvokeMethodRequest; import io.dapr.client.domain.PublishEventRequest; import io.dapr.client.domain.Response; import io.dapr.client.domain.SaveStateRequest; @@ -26,6 +27,7 @@ import io.dapr.config.Properties; import io.dapr.exceptions.DaprException; import io.dapr.serializer.DaprObjectSerializer; +import io.dapr.utils.NetworkUtils; import io.dapr.utils.TypeRef; import io.dapr.v1.CommonProtos; import io.dapr.v1.DaprGrpc; @@ -38,6 +40,7 @@ import io.grpc.Metadata; import io.grpc.Metadata.Key; import io.grpc.MethodDescriptor; +import io.grpc.stub.StreamObserver; import io.opencensus.implcore.trace.propagation.PropagationComponentImpl; import io.opencensus.implcore.trace.propagation.TraceContextFormat; import io.opencensus.trace.SpanContext; @@ -49,13 +52,17 @@ import io.opentelemetry.context.propagation.TextMapPropagator; import org.jetbrains.annotations.Nullable; import reactor.core.publisher.Mono; +import reactor.core.publisher.MonoSink; import java.io.Closeable; import java.io.IOException; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.Callable; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.function.Consumer; import java.util.stream.Collectors; /** @@ -84,29 +91,28 @@ public class DaprClientGrpc extends AbstractDaprClient { private Closeable channel; /** - * The GRPC client to be used. - * - * @see io.dapr.v1.DaprGrpc.DaprFutureStub + * The async gRPC stub. */ - private DaprGrpc.DaprFutureStub client; + private DaprGrpc.DaprStub asyncStub; + /** * Default access level constructor, in order to create an instance of this class use io.dapr.client.DaprClientBuilder * * @param closeableChannel A closeable for a Managed GRPC channel - * @param futureClient GRPC client + * @param asyncStub async gRPC stub * @param objectSerializer Serializer for transient request/response objects. * @param stateSerializer Serializer for state objects. * @see DaprClientBuilder */ DaprClientGrpc( Closeable closeableChannel, - DaprGrpc.DaprFutureStub futureClient, + DaprGrpc.DaprStub asyncStub, DaprObjectSerializer objectSerializer, DaprObjectSerializer stateSerializer) { super(objectSerializer, stateSerializer); this.channel = closeableChannel; - this.client = populateWithInterceptors(futureClient); + this.asyncStub = populateWithInterceptors(asyncStub); } private CommonProtos.StateOptions.StateConsistency getGrpcStateConsistency(StateOptions options) { @@ -131,6 +137,20 @@ private CommonProtos.StateOptions.StateConcurrency getGrpcStateConcurrency(State } } + /** + * {@inheritDoc} + */ + @Override + public Mono waitForSidecar(int timeoutInMilliseconds) { + return Mono.fromRunnable(() -> { + try { + NetworkUtils.waitForSocket(Properties.SIDECAR_IP.get(), Properties.GRPC_PORT.get(), timeoutInMilliseconds); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }); + } + /** * {@inheritDoc} */ @@ -140,18 +160,25 @@ public Mono> publishEvent(PublishEventRequest request) { String pubsubName = request.getPubsubName(); String topic = request.getTopic(); Object data = request.getData(); - // TODO(artursouza): handle metadata. - // Map metadata = request.getMetadata(); Context context = request.getContext(); - DaprProtos.PublishEventRequest envelope = DaprProtos.PublishEventRequest.newBuilder() + DaprProtos.PublishEventRequest.Builder envelopeBuilder = DaprProtos.PublishEventRequest.newBuilder() .setTopic(topic) .setPubsubName(pubsubName) - .setData(ByteString.copyFrom(objectSerializer.serialize(data))).build(); + .setData(ByteString.copyFrom(objectSerializer.serialize(data))); + envelopeBuilder.setDataContentType(objectSerializer.getContentType()); + Map metadata = request.getMetadata(); + if (metadata != null) { + envelopeBuilder.putAllMetadata(metadata); + String contentType = metadata.get(io.dapr.client.domain.Metadata.CONTENT_TYPE); + if (contentType != null) { + envelopeBuilder.setDataContentType(contentType); + } + } - return Mono.fromCallable(wrap(context, () -> { - get(client.publishEvent(envelope)); - return null; - })); + return this.createMono( + context, + it -> asyncStub.publishEvent(envelopeBuilder.build(), it) + ).thenReturn(new Response<>(context, null)); } catch (Exception ex) { return DaprException.wrapMono(ex); } @@ -161,24 +188,34 @@ public Mono> publishEvent(PublishEventRequest request) { * {@inheritDoc} */ @Override - public Mono> invokeService(InvokeServiceRequest invokeServiceRequest, TypeRef type) { + public Mono> invokeMethod(InvokeMethodRequest invokeMethodRequest, TypeRef type) { try { - String appId = invokeServiceRequest.getAppId(); - String method = invokeServiceRequest.getMethod(); - Object request = invokeServiceRequest.getBody(); - HttpExtension httpExtension = invokeServiceRequest.getHttpExtension(); - Context context = invokeServiceRequest.getContext(); + String appId = invokeMethodRequest.getAppId(); + String method = invokeMethodRequest.getMethod(); + Object body = invokeMethodRequest.getBody(); + HttpExtension httpExtension = invokeMethodRequest.getHttpExtension(); + Context context = invokeMethodRequest.getContext(); DaprProtos.InvokeServiceRequest envelope = buildInvokeServiceRequest( httpExtension, appId, method, - request); - return Mono.fromCallable(wrap(context, () -> { - ListenableFuture futureResponse = - client.invokeService(envelope); - - return objectSerializer.deserialize(get(futureResponse).getData().getValue().toByteArray(), type); - })).map(r -> new Response<>(context, r)); + body); + // Regarding missing metadata in method invocation for gRPC: + // gRPC to gRPC does not handle metadata in Dapr runtime proto. + // gRPC to HTTP does not map correctly in Dapr runtime as per https://github.com/dapr/dapr/issues/2342 + + return this.createMono( + context, + it -> asyncStub.invokeService(envelope, it) + ).flatMap( + it -> { + try { + return Mono.justOrEmpty(objectSerializer.deserialize(it.getData().getValue().toByteArray(), type)); + } catch (IOException e) { + throw DaprException.propagate(e); + } + } + ).map(r -> new Response<>(context, r)); } catch (Exception ex) { return DaprException.wrapMono(ex); } @@ -213,10 +250,19 @@ public Mono> invokeBinding(InvokeBindingRequest request, TypeRef builder.putAllMetadata(metadata); } DaprProtos.InvokeBindingRequest envelope = builder.build(); - return Mono.fromCallable(wrap(context, () -> { - ListenableFuture futureResponse = client.invokeBinding(envelope); - return objectSerializer.deserialize(get(futureResponse).getData().toByteArray(), type); - })).map(r -> new Response<>(context, r)); + + return this.createMono( + context, + it -> asyncStub.invokeBinding(envelope, it) + ).flatMap( + it -> { + try { + return Mono.justOrEmpty(objectSerializer.deserialize(it.getData().toByteArray(), type)); + } catch (IOException e) { + throw DaprException.propagate(e); + } + } + ).map(r -> new Response<>(context, r)); } catch (Exception ex) { return DaprException.wrapMono(ex); } @@ -228,11 +274,10 @@ public Mono> invokeBinding(InvokeBindingRequest request, TypeRef @Override public Mono>> getState(GetStateRequest request, TypeRef type) { try { - final String stateStoreName = request.getStateStoreName(); + final String stateStoreName = request.getStoreName(); final String key = request.getKey(); final StateOptions options = request.getStateOptions(); - // TODO(artursouza): handle etag once available in proto. - // String etag = request.getEtag(); + final Map metadata = request.getMetadata(); final Context context = request.getContext(); if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { @@ -243,17 +288,28 @@ public Mono>> getState(GetStateRequest request, TypeRef } DaprProtos.GetStateRequest.Builder builder = DaprProtos.GetStateRequest.newBuilder() .setStoreName(stateStoreName) - .setKey(key) - .putAllMetadata(request.getMetadata()); + .setKey(key); + if (metadata != null) { + builder.putAllMetadata(metadata); + } if (options != null && options.getConsistency() != null) { builder.setConsistency(getGrpcStateConsistency(options)); } DaprProtos.GetStateRequest envelope = builder.build(); - return Mono.fromCallable(wrap(context, () -> { - ListenableFuture futureResponse = client.getState(envelope); - return buildStateKeyValue(get(futureResponse), key, options, type); - })).map(s -> new Response<>(context, s)); + + return this.createMono( + context, + it -> asyncStub.getState(envelope, it) + ).map( + it -> { + try { + return buildStateKeyValue(it, key, options, type); + } catch (IOException ex) { + throw DaprException.propagate(ex); + } + } + ).map(s -> new Response<>(context, s)); } catch (Exception ex) { return DaprException.wrapMono(ex); } @@ -263,11 +319,12 @@ public Mono>> getState(GetStateRequest request, TypeRef * {@inheritDoc} */ @Override - public Mono>>> getStates(GetStatesRequest request, TypeRef type) { + public Mono>>> getBulkState(GetBulkStateRequest request, TypeRef type) { try { - final String stateStoreName = request.getStateStoreName(); + final String stateStoreName = request.getStoreName(); final List keys = request.getKeys(); final int parallelism = request.getParallelism(); + final Map metadata = request.getMetadata(); final Context context = request.getContext(); if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { throw new IllegalArgumentException("State store name cannot be null or empty."); @@ -283,25 +340,29 @@ public Mono>>> getStates(GetStatesRequest request, Ty .setStoreName(stateStoreName) .addAllKeys(keys) .setParallelism(parallelism); + if (metadata != null) { + builder.putAllMetadata(metadata); + } DaprProtos.GetBulkStateRequest envelope = builder.build(); - return Mono.fromCallable(wrap(context, () -> { - ListenableFuture futureResponse = client.getBulkState(envelope); - DaprProtos.GetBulkStateResponse response = get(futureResponse); - - return response - .getItemsList() - .stream() - .map(b -> { - try { - return buildStateKeyValue(b, type); - } catch (Exception e) { - DaprException.wrap(e); - return null; - } - }) - .collect(Collectors.toList()); - })).map(s -> new Response<>(context, s)); + + return this.createMono( + context, + it -> asyncStub.getBulkState(envelope, it) + ).map( + it -> + it + .getItemsList() + .stream() + .map(b -> { + try { + return buildStateKeyValue(b, type); + } catch (Exception e) { + throw DaprException.propagate(e); + } + }) + .collect(Collectors.toList()) + ).map(s -> new Response<>(context, s)); } catch (Exception ex) { return DaprException.wrapMono(ex); } @@ -320,6 +381,9 @@ private State buildStateKeyValue( byte[] data = payload == null ? null : payload.toByteArray(); T value = stateSerializer.deserialize(data, type); String etag = item.getEtag(); + if (etag.equals("")) { + etag = null; + } return new State<>(value, key, etag, item.getMetadataMap(), null); } @@ -332,6 +396,9 @@ private State buildStateKeyValue( byte[] data = payload == null ? null : payload.toByteArray(); T value = stateSerializer.deserialize(data, type); String etag = response.getEtag(); + if (etag.equals("")) { + etag = null; + } return new State<>(value, requestedKey, etag, response.getMetadataMap(), stateOptions); } @@ -339,7 +406,7 @@ private State buildStateKeyValue( * {@inheritDoc} */ @Override - public Mono> executeTransaction(ExecuteStateTransactionRequest request) { + public Mono> executeStateTransaction(ExecuteStateTransactionRequest request) { try { final String stateStoreName = request.getStateStoreName(); final List> operations = request.getOperations(); @@ -363,8 +430,10 @@ public Mono> executeTransaction(ExecuteStateTransactionRequest re } DaprProtos.ExecuteStateTransactionRequest req = builder.build(); - return Mono.fromCallable(wrap(context, () -> client.executeStateTransaction(req))).map(f -> get(f)) - .thenReturn(new Response<>(context, null)); + return this.createMono( + context, + it -> asyncStub.executeStateTransaction(req, it) + ).thenReturn(new Response<>(context, null)); } catch (Exception e) { return DaprException.wrapMono(e); } @@ -374,9 +443,9 @@ public Mono> executeTransaction(ExecuteStateTransactionRequest re * {@inheritDoc} */ @Override - public Mono> saveStates(SaveStateRequest request) { + public Mono> saveBulkState(SaveStateRequest request) { try { - final String stateStoreName = request.getStateStoreName(); + final String stateStoreName = request.getStoreName(); final List> states = request.getStates(); final Context context = request.getContext(); if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { @@ -389,8 +458,10 @@ public Mono> saveStates(SaveStateRequest request) { } DaprProtos.SaveStateRequest req = builder.build(); - return Mono.fromCallable(wrap(context, () -> client.saveState(req))).map(f -> get(f)) - .thenReturn(new Response<>(context, null)); + return this.createMono( + context, + it -> asyncStub.saveState(req, it) + ).thenReturn(new Response<>(context, null)); } catch (Exception ex) { return DaprException.wrapMono(ex); } @@ -401,7 +472,7 @@ private CommonProtos.StateItem.Builder buildStateRequest(State state) thr CommonProtos.StateItem.Builder stateBuilder = CommonProtos.StateItem.newBuilder(); if (state.getEtag() != null) { - stateBuilder.setEtag(state.getEtag()); + stateBuilder.setEtag(CommonProtos.Etag.newBuilder().setValue(state.getEtag()).build()); } if (state.getMetadata() != null) { stateBuilder.putAllMetadata(state.getMetadata()); @@ -437,6 +508,7 @@ public Mono> deleteState(DeleteStateRequest request) { final String key = request.getKey(); final StateOptions options = request.getStateOptions(); final String etag = request.getEtag(); + final Map metadata = request.getMetadata(); final Context context = request.getContext(); if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { @@ -458,10 +530,12 @@ public Mono> deleteState(DeleteStateRequest request) { } DaprProtos.DeleteStateRequest.Builder builder = DaprProtos.DeleteStateRequest.newBuilder() .setStoreName(stateStoreName) - .setKey(key) - .putAllMetadata(request.getMetadata()); + .setKey(key); + if (metadata != null) { + builder.putAllMetadata(metadata); + } if (etag != null) { - builder.setEtag(etag); + builder.setEtag(CommonProtos.Etag.newBuilder().setValue(etag).build()); } if (optionBuilder != null) { @@ -469,8 +543,11 @@ public Mono> deleteState(DeleteStateRequest request) { } DaprProtos.DeleteStateRequest req = builder.build(); - return Mono.fromCallable(wrap(context, () -> client.deleteState(req))).map(f -> get(f)) - .thenReturn(new Response<>(context, null)); + + return this.createMono( + context, + it -> asyncStub.deleteState(req, it) + ).thenReturn(new Response<>(context, null)); } catch (Exception ex) { return DaprException.wrapMono(ex); } @@ -482,7 +559,7 @@ public Mono> deleteState(DeleteStateRequest request) { * @param httpExtension Object for HttpExtension * @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 invocation + * @param body The body of the request to be send as part of the invocation * @param The Type of the Body * @return The object to be sent as part of the invocation. * @throws IOException If there's an issue serializing the request. @@ -491,14 +568,14 @@ private DaprProtos.InvokeServiceRequest buildInvokeServiceRequest( HttpExtension httpExtension, String appId, String method, - K request) throws IOException { + K body) throws IOException { if (httpExtension == null) { throw new IllegalArgumentException("HttpExtension cannot be null. Use HttpExtension.NONE instead."); } CommonProtos.InvokeRequest.Builder requestBuilder = CommonProtos.InvokeRequest.newBuilder(); requestBuilder.setMethod(method); - if (request != null) { - byte[] byteRequest = objectSerializer.serialize(request); + if (body != null) { + byte[] byteRequest = objectSerializer.serialize(body); Any data = Any.newBuilder().setValue(ByteString.copyFrom(byteRequest)).build(); requestBuilder.setData(data); } else { @@ -522,7 +599,7 @@ private DaprProtos.InvokeServiceRequest buildInvokeServiceRequest( */ @Override public Mono>> getSecret(GetSecretRequest request) { - String secretStoreName = request.getSecretStoreName(); + String secretStoreName = request.getStoreName(); String key = request.getKey(); Map metadata = request.getMetadata(); Context context = request.getContext(); @@ -544,11 +621,50 @@ public Mono>> getSecret(GetSecretRequest request) { if (metadata != null) { requestBuilder.putAllMetadata(metadata); } - return Mono.fromCallable(wrap(context, () -> { - DaprProtos.GetSecretRequest req = requestBuilder.build(); - ListenableFuture future = client.getSecret(req); - return get(future); - })).map(future -> new Response<>(context, future.getDataMap())); + DaprProtos.GetSecretRequest req = requestBuilder.build(); + + return this.createMono( + context, + it -> asyncStub.getSecret(req, it) + ).map(it -> new Response<>(context, it.getDataMap())); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono>>> getBulkSecret(GetBulkSecretRequest request) { + try { + final String storeName = request.getStoreName(); + final Map metadata = request.getMetadata(); + final Context context = request.getContext(); + if ((storeName == null) || (storeName.trim().isEmpty())) { + throw new IllegalArgumentException("Secret store name cannot be null or empty."); + } + + DaprProtos.GetBulkSecretRequest.Builder builder = DaprProtos.GetBulkSecretRequest.newBuilder() + .setStoreName(storeName); + if (metadata != null) { + builder.putAllMetadata(metadata); + } + + DaprProtos.GetBulkSecretRequest envelope = builder.build(); + + return this.createMono(context, it -> asyncStub.getBulkSecret(envelope, it)) + .map(it -> { + Map secretsMap = it.getDataMap(); + if (secretsMap == null) { + return Collections.EMPTY_MAP; + } + return secretsMap + .entrySet() + .stream() + .collect(Collectors.toMap(s -> s.getKey(), s -> s.getValue().getSecretsMap())); + }) + .map(s -> new Response<>(context, s)); + } catch (Exception ex) { + return DaprException.wrapMono(ex); + } } /** @@ -572,13 +688,13 @@ public void close() throws Exception { * @param client GRPC client for Dapr. * @return Client after adding interceptors. */ - private static DaprGrpc.DaprFutureStub populateWithInterceptors(DaprGrpc.DaprFutureStub client) { + private static DaprGrpc.DaprStub populateWithInterceptors(DaprGrpc.DaprStub client) { ClientInterceptor interceptor = new ClientInterceptor() { @Override public ClientCall interceptCall( - MethodDescriptor methodDescriptor, - CallOptions callOptions, - Channel channel) { + MethodDescriptor methodDescriptor, + CallOptions callOptions, + Channel channel) { ClientCall clientCall = channel.newCall(methodDescriptor, callOptions); return new ForwardingClientCall.SimpleForwardingClientCall(clientCall) { @Override @@ -636,21 +752,36 @@ public String get(Map map, String key) { } } - private static Callable wrap(Context context, Callable callable) { + private static Runnable wrap(Context context, Runnable runnable) { if (context == null) { - return DaprException.wrap(callable); + return DaprException.wrap(runnable); } - return DaprException.wrap(context.wrap(callable)); + return DaprException.wrap(context.wrap(runnable)); } - private static V get(ListenableFuture future) { - try { - return future.get(); - } catch (Exception e) { - DaprException.wrap(e); - } + private Mono createMono(Context context, Consumer> consumer) { + return Mono.create( + sink -> wrap(context, () -> consumer.accept(createStreamObserver(sink))).run() + ); + } - return null; + private StreamObserver createStreamObserver(MonoSink sink) { + return new StreamObserver() { + @Override + public void onNext(T value) { + sink.success(value); + } + + @Override + public void onError(Throwable t) { + sink.error(DaprException.propagate(new ExecutionException(t))); + } + + @Override + public void onCompleted() { + sink.success(); + } + }; } } diff --git a/sdk/src/main/java/io/dapr/client/DaprClientHttp.java b/sdk/src/main/java/io/dapr/client/DaprClientHttp.java index 18fd07fa9f..9e5a5b9d69 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientHttp.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientHttp.java @@ -9,12 +9,13 @@ import com.google.common.base.Strings; import io.dapr.client.domain.DeleteStateRequest; import io.dapr.client.domain.ExecuteStateTransactionRequest; +import io.dapr.client.domain.GetBulkSecretRequest; +import io.dapr.client.domain.GetBulkStateRequest; import io.dapr.client.domain.GetSecretRequest; import io.dapr.client.domain.GetStateRequest; -import io.dapr.client.domain.GetStatesRequest; import io.dapr.client.domain.HttpExtension; import io.dapr.client.domain.InvokeBindingRequest; -import io.dapr.client.domain.InvokeServiceRequest; +import io.dapr.client.domain.InvokeMethodRequest; import io.dapr.client.domain.PublishEventRequest; import io.dapr.client.domain.Response; import io.dapr.client.domain.SaveStateRequest; @@ -26,6 +27,7 @@ import io.dapr.exceptions.DaprException; import io.dapr.serializer.DaprObjectSerializer; import io.dapr.serializer.DefaultObjectSerializer; +import io.dapr.utils.NetworkUtils; import io.dapr.utils.TypeRef; import io.opentelemetry.context.Context; import reactor.core.publisher.Mono; @@ -38,6 +40,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; /** @@ -53,44 +56,14 @@ public class DaprClientHttp extends AbstractDaprClient { private static final String HEADER_HTTP_ETAG_ID = "If-Match"; /** - * Serializer for internal objects. - */ - private static final ObjectSerializer INTERNAL_SERIALIZER = new ObjectSerializer(); - - /** - * Base path to invoke methods. - */ - public static final String INVOKE_PATH = DaprHttp.API_VERSION + "/invoke"; - - /** - * Invoke Publish Path. - */ - public static final String PUBLISH_PATH = DaprHttp.API_VERSION + "/publish"; - - /** - * Invoke Binding Path. - */ - public static final String BINDING_PATH = DaprHttp.API_VERSION + "/bindings"; - - /** - * State Path. - */ - public static final String STATE_PATH = DaprHttp.API_VERSION + "/state"; - - /** - * String format for transaction API. - */ - private static final String TRANSACTION_URL_FORMAT = STATE_PATH + "/%s/transaction"; - - /** - * Secrets Path. + * Metadata prefix in query params. */ - public static final String SECRETS_PATH = DaprHttp.API_VERSION + "/secrets"; + private static final String METADATA_PREFIX = "metadata."; /** - * State Path format for bulk state API. + * Serializer for internal objects. */ - public static final String STATE_BULK_PATH_FORMAT = STATE_PATH + "/%s/bulk"; + private static final ObjectSerializer INTERNAL_SERIALIZER = new ObjectSerializer(); /** * The HTTP client to be used. @@ -136,6 +109,20 @@ public class DaprClientHttp extends AbstractDaprClient { this(client, new DefaultObjectSerializer(), new DefaultObjectSerializer()); } + /** + * {@inheritDoc} + */ + @Override + public Mono waitForSidecar(int timeoutInMilliseconds) { + return Mono.fromRunnable(() -> { + try { + NetworkUtils.waitForSocket(Properties.SIDECAR_IP.get(), Properties.HTTP_PORT.get(), timeoutInMilliseconds); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }); + } + /** * {@inheritDoc} */ @@ -152,12 +139,14 @@ public Mono> publishEvent(PublishEventRequest request) { throw new IllegalArgumentException("Topic name cannot be null or empty."); } - StringBuilder url = new StringBuilder(PUBLISH_PATH) - .append("/").append(pubsubName) - .append("/").append(topic); byte[] serializedEvent = objectSerializer.serialize(data); + Map headers = Collections.singletonMap("content-type", objectSerializer.getContentType()); + + String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "publish", pubsubName, topic }; + + Map queryArgs = metadataToQueryArgs(metadata); return this.client.invokeApi( - DaprHttp.HttpMethods.POST.name(), url.toString(), null, serializedEvent, metadata, context) + DaprHttp.HttpMethods.POST.name(), pathSegments, queryArgs, serializedEvent, headers, context) .thenReturn(new Response<>(context, null)); } catch (Exception ex) { return DaprException.wrapMono(ex); @@ -167,41 +156,50 @@ public Mono> publishEvent(PublishEventRequest request) { /** * {@inheritDoc} */ - public Mono> invokeService(InvokeServiceRequest invokeServiceRequest, TypeRef type) { + public Mono> invokeMethod(InvokeMethodRequest invokeMethodRequest, TypeRef type) { try { - final String appId = invokeServiceRequest.getAppId(); - final String method = invokeServiceRequest.getMethod(); - final Object request = invokeServiceRequest.getBody(); - final Map metadata = invokeServiceRequest.getMetadata(); - final HttpExtension httpExtension = invokeServiceRequest.getHttpExtension(); - final Context context = invokeServiceRequest.getContext(); + final String appId = invokeMethodRequest.getAppId(); + final String method = invokeMethodRequest.getMethod(); + final Object request = invokeMethodRequest.getBody(); + final HttpExtension httpExtension = invokeMethodRequest.getHttpExtension(); + final String contentType = invokeMethodRequest.getContentType(); + final Context context = invokeMethodRequest.getContext(); if (httpExtension == null) { throw new IllegalArgumentException("HttpExtension cannot be null. Use HttpExtension.NONE instead."); } // If the httpExtension is not null, then the method will not be null based on checks in constructor - String httMethod = httpExtension.getMethod().toString(); + final String httpMethod = httpExtension.getMethod().toString(); if (appId == null || appId.trim().isEmpty()) { throw new IllegalArgumentException("App Id cannot be null or empty."); } if (method == null || method.trim().isEmpty()) { throw new IllegalArgumentException("Method name cannot be null or empty."); } - String path = String.format("%s/%s/method/%s", INVOKE_PATH, appId, method); byte[] serializedRequestBody = objectSerializer.serialize(request); - Mono response = this.client.invokeApi(httMethod, path, - httpExtension.getQueryString(), serializedRequestBody, metadata, context); - return response.flatMap(r -> { - try { - T object = objectSerializer.deserialize(r.getBody(), type); - if (object == null) { - return Mono.empty(); - } - return Mono.just(object); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - }).map(r -> new Response<>(context, r)); + String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "invoke", appId, "method", method }; + + final Map headers = new HashMap<>(); + if (contentType != null && !contentType.isEmpty()) { + headers.put("content-type", contentType); + } + headers.putAll(httpExtension.getHeaders()); + Mono response = this.client.invokeApi(httpMethod, pathSegments, + httpExtension.getQueryString(), serializedRequestBody, headers, context); + return response.flatMap(r -> getMono(type, r)).map(r -> new Response<>(context, r)); + } catch (Exception ex) { + return DaprException.wrapMono(ex); + } + } + + private Mono getMono(TypeRef type, DaprHttp.Response r) { + try { + T object = objectSerializer.deserialize(r.getBody(), type); + if (object == null) { + return Mono.empty(); + } + + return Mono.just(object); } catch (Exception ex) { return DaprException.wrapMono(ex); } @@ -252,24 +250,14 @@ public Mono> invokeBinding(InvokeBindingRequest request, TypeRef } } - StringBuilder url = new StringBuilder(BINDING_PATH).append("/").append(name); - byte[] payload = INTERNAL_SERIALIZER.serialize(jsonMap); String httpMethod = DaprHttp.HttpMethods.POST.name(); - Mono response = this.client.invokeApi( - httpMethod, url.toString(), null, payload, null, context); - return response.flatMap(r -> { - try { - T object = objectSerializer.deserialize(r.getBody(), type); - if (object == null) { - return Mono.empty(); - } - return Mono.just(object); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - }).map(r -> new Response<>(context, r)); + String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "bindings", name }; + + Mono response = this.client.invokeApi( + httpMethod, pathSegments, null, payload, null, context); + return response.flatMap(r -> getMono(type, r)).map(r -> new Response<>(context, r)); } catch (Exception ex) { return DaprException.wrapMono(ex); } @@ -279,11 +267,12 @@ public Mono> invokeBinding(InvokeBindingRequest request, TypeRef * {@inheritDoc} */ @Override - public Mono>>> getStates(GetStatesRequest request, TypeRef type) { + public Mono>>> getBulkState(GetBulkStateRequest request, TypeRef type) { try { - final String stateStoreName = request.getStateStoreName(); + final String stateStoreName = request.getStoreName(); final List keys = request.getKeys(); final int parallelism = request.getParallelism(); + final Map metadata = request.getMetadata(); final Context context = request.getContext(); if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { throw new IllegalArgumentException("State store name cannot be null or empty."); @@ -296,14 +285,17 @@ public Mono>>> getStates(GetStatesRequest request, Ty throw new IllegalArgumentException("Parallelism cannot be negative."); } - String url = String.format(STATE_BULK_PATH_FORMAT, stateStoreName); Map jsonMap = new HashMap<>(); jsonMap.put("keys", keys); jsonMap.put("parallelism", parallelism); byte[] requestBody = INTERNAL_SERIALIZER.serialize(jsonMap); + + String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "state", stateStoreName, "bulk"}; + + Map queryArgs = metadataToQueryArgs(metadata); return this.client - .invokeApi(DaprHttp.HttpMethods.POST.name(), url, null, requestBody, null, context) + .invokeApi(DaprHttp.HttpMethods.POST.name(), pathSegments, queryArgs, requestBody, null, context) .flatMap(s -> { try { return Mono.just(buildStates(s, type)); @@ -325,10 +317,10 @@ public Mono>>> getStates(GetStatesRequest request, Ty @Override public Mono>> getState(GetStateRequest request, TypeRef type) { try { - final String stateStoreName = request.getStateStoreName(); + final String stateStoreName = request.getStoreName(); final String key = request.getKey(); final StateOptions options = request.getStateOptions(); - final String etag = request.getEtag(); + final Map metadata = request.getMetadata(); final Context context = request.getContext(); if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { @@ -337,24 +329,18 @@ public Mono>> getState(GetStateRequest request, TypeRef if ((key == null) || (key.trim().isEmpty())) { throw new IllegalArgumentException("Key cannot be null or empty."); } - Map headers = new HashMap<>(); - if (etag != null && !etag.trim().isEmpty()) { - headers.put(HEADER_HTTP_ETAG_ID, etag); - } - - StringBuilder url = new StringBuilder(STATE_PATH) - .append("/") - .append(stateStoreName) - .append("/") - .append(key); - Map urlParameters = Optional.ofNullable(options) + Map optionsMap = Optional.ofNullable(options) .map(o -> o.getStateOptionsAsMap()) - .orElse(new HashMap<>()); + .orElse(Collections.EMPTY_MAP); + + final Map queryParams = new HashMap<>(); + queryParams.putAll(metadataToQueryArgs(metadata)); + queryParams.putAll(optionsMap); - request.getMetadata().forEach(urlParameters::put); + String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "state", stateStoreName, key}; return this.client - .invokeApi(DaprHttp.HttpMethods.GET.name(), url.toString(), urlParameters, headers, context) + .invokeApi(DaprHttp.HttpMethods.GET.name(), pathSegments, queryParams, null, context) .flatMap(s -> { try { return Mono.just(buildState(s, key, options, type)); @@ -372,7 +358,7 @@ public Mono>> getState(GetStateRequest request, TypeRef * {@inheritDoc} */ @Override - public Mono> executeTransaction(ExecuteStateTransactionRequest request) { + public Mono> executeStateTransaction(ExecuteStateTransactionRequest request) { try { final String stateStoreName = request.getStateStoreName(); final List> operations = request.getOperations(); @@ -384,7 +370,7 @@ public Mono> executeTransaction(ExecuteStateTransactionRequest re if (operations == null || operations.isEmpty()) { return Mono.empty(); } - final String url = String.format(TRANSACTION_URL_FORMAT, stateStoreName); + List> internalOperationObjects = new ArrayList<>(operations.size()); for (TransactionalStateOperation operation : operations) { if (operation == null) { @@ -409,8 +395,11 @@ public Mono> executeTransaction(ExecuteStateTransactionRequest re } TransactionalStateRequest req = new TransactionalStateRequest<>(internalOperationObjects, metadata); byte[] serializedOperationBody = INTERNAL_SERIALIZER.serialize(req); + + String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "state", stateStoreName, "transaction"}; + return this.client.invokeApi( - DaprHttp.HttpMethods.POST.name(), url, null, serializedOperationBody, null, context) + DaprHttp.HttpMethods.POST.name(), pathSegments, null, serializedOperationBody, null, context) .thenReturn(new Response<>(context, null)); } catch (Exception e) { return DaprException.wrapMono(e); @@ -421,9 +410,9 @@ public Mono> executeTransaction(ExecuteStateTransactionRequest re * {@inheritDoc} */ @Override - public Mono> saveStates(SaveStateRequest request) { + public Mono> saveBulkState(SaveStateRequest request) { try { - final String stateStoreName = request.getStateStoreName(); + final String stateStoreName = request.getStoreName(); final List> states = request.getStates(); final Context context = request.getContext(); if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { @@ -432,7 +421,7 @@ public Mono> saveStates(SaveStateRequest request) { if (states == null || states.isEmpty()) { return Mono.empty(); } - final String url = STATE_PATH + "/" + stateStoreName; + List> internalStateObjects = new ArrayList<>(states.size()); for (State state : states) { if (state == null) { @@ -453,8 +442,11 @@ public Mono> saveStates(SaveStateRequest request) { state.getOptions())); } byte[] serializedStateBody = INTERNAL_SERIALIZER.serialize(internalStateObjects); + + String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "state", stateStoreName}; + return this.client.invokeApi( - DaprHttp.HttpMethods.POST.name(), url, null, serializedStateBody, null, context) + DaprHttp.HttpMethods.POST.name(), pathSegments, null, serializedStateBody, null, context) .thenReturn(new Response<>(context, null)); } catch (Exception ex) { return DaprException.wrapMono(ex); @@ -471,6 +463,7 @@ public Mono> deleteState(DeleteStateRequest request) { final String key = request.getKey(); final StateOptions options = request.getStateOptions(); final String etag = request.getEtag(); + final Map metadata = request.getMetadata(); final Context context = request.getContext(); if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { @@ -483,15 +476,19 @@ public Mono> deleteState(DeleteStateRequest request) { if (etag != null && !etag.trim().isEmpty()) { headers.put(HEADER_HTTP_ETAG_ID, etag); } - String url = STATE_PATH + "/" + stateStoreName + "/" + key; - Map urlParameters = Optional.ofNullable(options) + + Map optionsMap = Optional.ofNullable(options) .map(stateOptions -> stateOptions.getStateOptionsAsMap()) - .orElse(new HashMap<>()); + .orElse(Collections.EMPTY_MAP); + + final Map queryParams = new HashMap<>(); + queryParams.putAll(metadataToQueryArgs(metadata)); + queryParams.putAll(optionsMap); - request.getMetadata().forEach(urlParameters::put); + String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "state", stateStoreName, key}; return this.client.invokeApi( - DaprHttp.HttpMethods.DELETE.name(), url, urlParameters, headers, context) + DaprHttp.HttpMethods.DELETE.name(), pathSegments, queryParams, headers, context) .thenReturn(new Response<>(context, null)); } catch (Exception ex) { return DaprException.wrapMono(ex); @@ -542,6 +539,9 @@ private List> buildStates( } String etag = node.path("etag").asText(); + if (etag.equals("")) { + etag = null; + } // TODO(artursouza): JSON cannot differentiate if data returned is String or byte[], it is ambiguous. // This is not a high priority since GRPC is the default (and recommended) client implementation. byte[] data = node.path("data").toString().getBytes(Properties.STRING_CHARSET.get()); @@ -557,7 +557,7 @@ private List> buildStates( */ @Override public Mono>> getSecret(GetSecretRequest request) { - String secretStoreName = request.getSecretStoreName(); + String secretStoreName = request.getStoreName(); String key = request.getKey(); Map metadata = request.getMetadata(); Context context = request.getContext(); @@ -572,9 +572,10 @@ public Mono>> getSecret(GetSecretRequest request) { return DaprException.wrapMono(e); } - String url = SECRETS_PATH + "/" + secretStoreName + "/" + key; + Map queryArgs = metadataToQueryArgs(metadata); + String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "secrets", secretStoreName, key}; return this.client - .invokeApi(DaprHttp.HttpMethods.GET.name(), url, metadata, (String)null, null, context) + .invokeApi(DaprHttp.HttpMethods.GET.name(), pathSegments, queryArgs, (String)null, null, context) .flatMap(response -> { try { Map m = INTERNAL_SERIALIZER.deserialize(response.getBody(), Map.class); @@ -591,12 +592,64 @@ public Mono>> getSecret(GetSecretRequest request) { .map(m -> new Response<>(context, m)); } + /** + * {@inheritDoc} + */ @Override - public void close() { + public Mono>>> getBulkSecret(GetBulkSecretRequest request) { + String secretStoreName = request.getStoreName(); + Map metadata = request.getMetadata(); + Context context = request.getContext(); try { - client.close(); + if ((secretStoreName == null) || (secretStoreName.trim().isEmpty())) { + throw new IllegalArgumentException("Secret store name cannot be null or empty."); + } } catch (Exception e) { - DaprException.wrap(e); + return DaprException.wrapMono(e); + } + + Map queryArgs = metadataToQueryArgs(metadata); + String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "secrets", secretStoreName, "bulk"}; + return this.client + .invokeApi(DaprHttp.HttpMethods.GET.name(), pathSegments, queryArgs, (String)null, null, context) + .flatMap(response -> { + try { + Map m = INTERNAL_SERIALIZER.deserialize(response.getBody(), Map.class); + if (m == null) { + return Mono.just(Collections.EMPTY_MAP); + } + + return Mono.just(m); + } catch (IOException e) { + return DaprException.wrapMono(e); + } + }) + .map(m -> (Map>)m) + .map(m -> new Response<>(context, m)); + } + + /** + * {@inheritDoc} + */ + @Override + public void close() { + client.close(); + } + + /** + * Converts metadata map into HTTP headers. + * @param metadata metadata map + * @return HTTP headers + */ + private static Map metadataToQueryArgs(Map metadata) { + if (metadata == null) { + return Collections.EMPTY_MAP; } + + return metadata + .entrySet() + .stream() + .filter(e -> e.getKey() != null) + .collect(Collectors.toMap(e -> METADATA_PREFIX + e.getKey(), e -> e.getValue())); } } diff --git a/sdk/src/main/java/io/dapr/client/DaprClientProxy.java b/sdk/src/main/java/io/dapr/client/DaprClientProxy.java new file mode 100644 index 0000000000..5d1b701726 --- /dev/null +++ b/sdk/src/main/java/io/dapr/client/DaprClientProxy.java @@ -0,0 +1,503 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.client; + +import io.dapr.client.domain.DeleteStateRequest; +import io.dapr.client.domain.ExecuteStateTransactionRequest; +import io.dapr.client.domain.GetBulkSecretRequest; +import io.dapr.client.domain.GetBulkStateRequest; +import io.dapr.client.domain.GetSecretRequest; +import io.dapr.client.domain.GetStateRequest; +import io.dapr.client.domain.HttpExtension; +import io.dapr.client.domain.InvokeBindingRequest; +import io.dapr.client.domain.InvokeMethodRequest; +import io.dapr.client.domain.PublishEventRequest; +import io.dapr.client.domain.Response; +import io.dapr.client.domain.SaveStateRequest; +import io.dapr.client.domain.State; +import io.dapr.client.domain.StateOptions; +import io.dapr.client.domain.TransactionalStateOperation; +import io.dapr.utils.TypeRef; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.Map; + +/** + * Class that delegates to other implementations. + * + * @see DaprClient + * @see DaprClientGrpc + * @see DaprClientHttp + */ +class DaprClientProxy implements DaprClient { + + /** + * Client for all API invocations. + */ + private final DaprClient client; + + /** + * Client to override Dapr's service invocation APIs. + */ + private final DaprClient methodInvocationOverrideClient; + + /** + * Constructor with delegate client. + * + * @param client Client for all API invocations. + * @see DaprClientBuilder + */ + DaprClientProxy(DaprClient client) { + this(client, client); + } + + /** + * Constructor with delegate client and override client for Dapr's method invocation APIs. + * + * @param client Client for all API invocations, except override below. + * @param methodInvocationOverrideClient Client to override Dapr's service invocation APIs. + * @see DaprClientBuilder + */ + DaprClientProxy( + DaprClient client, + DaprClient methodInvocationOverrideClient) { + this.client = client; + this.methodInvocationOverrideClient = methodInvocationOverrideClient; + } + + /** + * {@inheritDoc} + */ + @Override + public Mono waitForSidecar(int timeoutInMilliseconds) { + return client.waitForSidecar(timeoutInMilliseconds); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono publishEvent(String pubsubName, String topicName, Object data) { + return client.publishEvent(pubsubName, topicName, data); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono publishEvent(String pubsubName, String topicName, Object data, Map metadata) { + return client.publishEvent(pubsubName, topicName, data, metadata); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> publishEvent(PublishEventRequest request) { + return client.publishEvent(request); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, + String methodName, + Object data, + HttpExtension httpExtension, + Map metadata, + TypeRef type) { + return methodInvocationOverrideClient.invokeMethod(appId, methodName, data, httpExtension, metadata, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, + String methodName, + Object request, + HttpExtension httpExtension, + Map metadata, + Class clazz) { + return methodInvocationOverrideClient.invokeMethod(appId, methodName, request, httpExtension, metadata, clazz); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, + String methodName, + Object request, + HttpExtension httpExtension, + TypeRef type) { + return methodInvocationOverrideClient.invokeMethod(appId, methodName, request, httpExtension, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, + String methodName, + Object request, + HttpExtension httpExtension, + Class clazz) { + return methodInvocationOverrideClient.invokeMethod(appId, methodName, request, httpExtension, clazz); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, + String methodName, + HttpExtension httpExtension, + Map metadata, + TypeRef type) { + return methodInvocationOverrideClient.invokeMethod(appId, methodName, httpExtension, metadata, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, + String methodName, + HttpExtension httpExtension, + Map metadata, + Class clazz) { + return methodInvocationOverrideClient.invokeMethod(appId, methodName, httpExtension, metadata, clazz); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, + String methodName, + Object request, + HttpExtension httpExtension, + Map metadata) { + return methodInvocationOverrideClient.invokeMethod(appId, methodName, request, httpExtension, metadata); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension) { + return methodInvocationOverrideClient.invokeMethod(appId, methodName, request, httpExtension); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, + String methodName, + HttpExtension httpExtension, + Map metadata) { + return methodInvocationOverrideClient.invokeMethod(appId, methodName, httpExtension, metadata); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, + String methodName, + byte[] request, + HttpExtension httpExtension, + Map metadata) { + return methodInvocationOverrideClient.invokeMethod(appId, methodName, request, httpExtension, metadata); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> invokeMethod(InvokeMethodRequest invokeMethodRequest, TypeRef type) { + return methodInvocationOverrideClient.invokeMethod(invokeMethodRequest, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeBinding(String bindingName, String operation, Object data) { + return client.invokeBinding(bindingName, operation, data); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeBinding(String bindingName, String operation, byte[] data, Map metadata) { + return client.invokeBinding(bindingName, operation, data, metadata); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeBinding(String bindingName, String operation, Object data, TypeRef type) { + return client.invokeBinding(bindingName, operation, data, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeBinding(String bindingName, String operation, Object data, Class clazz) { + return client.invokeBinding(bindingName, operation, data, clazz); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeBinding(String bindingName, + String operation, + Object data, + Map metadata, + TypeRef type) { + return client.invokeBinding(bindingName, operation, data, metadata, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeBinding(String bindingName, + String operation, + Object data, + Map metadata, + Class clazz) { + return client.invokeBinding(bindingName, operation, data, metadata, clazz); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> invokeBinding(InvokeBindingRequest request, TypeRef type) { + return client.invokeBinding(request, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> getState(String storeName, State state, TypeRef type) { + return client.getState(storeName, state, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> getState(String storeName, State state, Class clazz) { + return client.getState(storeName, state, clazz); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> getState(String storeName, String key, TypeRef type) { + return client.getState(storeName, key, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> getState(String storeName, String key, Class clazz) { + return client.getState(storeName, key, clazz); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> getState(String storeName, String key, StateOptions options, TypeRef type) { + return client.getState(storeName, key, options, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> getState(String storeName, String key, StateOptions options, Class clazz) { + return client.getState(storeName, key, options, clazz); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono>> getState(GetStateRequest request, TypeRef type) { + return client.getState(request, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono>> getBulkState(String storeName, List keys, TypeRef type) { + return client.getBulkState(storeName, keys, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono>> getBulkState(String storeName, List keys, Class clazz) { + return client.getBulkState(storeName, keys, clazz); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono>>> getBulkState(GetBulkStateRequest request, TypeRef type) { + return client.getBulkState(request, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono executeStateTransaction(String storeName, List> operations) { + return client.executeStateTransaction(storeName, operations); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> executeStateTransaction(ExecuteStateTransactionRequest request) { + return client.executeStateTransaction(request); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono saveBulkState(String storeName, List> states) { + return client.saveBulkState(storeName, states); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> saveBulkState(SaveStateRequest request) { + return client.saveBulkState(request); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono saveState(String storeName, String key, Object value) { + return client.saveState(storeName, key, value); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono saveState(String storeName, String key, String etag, Object value, StateOptions options) { + return client.saveState(storeName, key, etag, value, options); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono deleteState(String storeName, String key) { + return client.deleteState(storeName, key); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono deleteState(String storeName, String key, String etag, StateOptions options) { + return client.deleteState(storeName, key, etag, options); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> deleteState(DeleteStateRequest request) { + return client.deleteState(request); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> getSecret(String storeName, String secretName, Map metadata) { + return client.getSecret(storeName, secretName, metadata); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> getSecret(String storeName, String secretName) { + return client.getSecret(storeName, secretName); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono>> getSecret(GetSecretRequest request) { + return client.getSecret(request); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono>> getBulkSecret(String storeName) { + return client.getBulkSecret(storeName); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono>> getBulkSecret(String storeName, Map metadata) { + return client.getBulkSecret(storeName, metadata); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono>>> getBulkSecret(GetBulkSecretRequest request) { + return client.getBulkSecret(request); + } + + /** + * {@inheritDoc} + */ + @Override + public void close() throws Exception { + client.close(); + if (client != methodInvocationOverrideClient) { + methodInvocationOverrideClient.close(); + } + } +} \ No newline at end of file diff --git a/sdk/src/main/java/io/dapr/client/DaprHttp.java b/sdk/src/main/java/io/dapr/client/DaprHttp.java index 2e0205eeca..a5f532a5c7 100644 --- a/sdk/src/main/java/io/dapr/client/DaprHttp.java +++ b/sdk/src/main/java/io/dapr/client/DaprHttp.java @@ -5,13 +5,17 @@ package io.dapr.client; +import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.ObjectMapper; +import io.dapr.client.domain.Metadata; import io.dapr.config.Properties; import io.dapr.exceptions.DaprError; import io.dapr.exceptions.DaprException; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.propagation.HttpTraceContext; import io.opentelemetry.context.Context; +import okhttp3.Call; +import okhttp3.Callback; import okhttp3.HttpUrl; import okhttp3.MediaType; import okhttp3.OkHttpClient; @@ -29,6 +33,7 @@ import java.util.Map; import java.util.Optional; import java.util.UUID; +import java.util.concurrent.CompletableFuture; public class DaprHttp implements AutoCloseable { @@ -153,7 +158,7 @@ public int getStatusCode() { * Invokes an API asynchronously without payload that returns a text payload. * * @param method HTTP method. - * @param urlString url as String. + * @param pathSegments Array of path segments ("/a/b/c" maps to ["a", "b", "c"]). * @param urlParameters URL parameters * @param headers HTTP headers. * @param context OpenTelemetry's Context. @@ -161,18 +166,18 @@ public int getStatusCode() { */ public Mono invokeApi( String method, - String urlString, + String[] pathSegments, Map urlParameters, Map headers, Context context) { - return this.invokeApi(method, urlString, urlParameters, (byte[]) null, headers, context); + return this.invokeApi(method, pathSegments, urlParameters, (byte[]) null, headers, context); } /** * Invokes an API asynchronously that returns a text payload. * * @param method HTTP method. - * @param urlString url as String. + * @param pathSegments Array of path segments ("/a/b/c" maps to ["a", "b", "c"]). * @param urlParameters Parameters in the URL * @param content payload to be posted. * @param headers HTTP headers. @@ -181,14 +186,14 @@ public Mono invokeApi( */ public Mono invokeApi( String method, - String urlString, + String[] pathSegments, Map urlParameters, String content, Map headers, Context context) { return this.invokeApi( - method, urlString, urlParameters, content == null + method, pathSegments, urlParameters, content == null ? EMPTY_BYTES : content.getBytes(StandardCharsets.UTF_8), headers, context); } @@ -197,7 +202,7 @@ public Mono invokeApi( * Invokes an API asynchronously that returns a text payload. * * @param method HTTP method. - * @param urlString url as String. + * @param pathSegments Array of path segments ("/a/b/c" maps to ["a", "b", "c"]). * @param urlParameters Parameters in the URL * @param content payload to be posted. * @param headers HTTP headers. @@ -206,12 +211,14 @@ public Mono invokeApi( */ public Mono invokeApi( String method, - String urlString, + String[] pathSegments, Map urlParameters, byte[] content, Map headers, Context context) { - return Mono.fromCallable(() -> doInvokeApi(method, urlString, urlParameters, content, headers, context)); + // fromCallable() is needed so the invocation does not happen early, causing a hot mono. + return Mono.fromCallable(() -> doInvokeApi(method, pathSegments, urlParameters, content, headers, context)) + .flatMap(f -> Mono.fromFuture(f)); } /** @@ -227,23 +234,22 @@ public void close() { * Invokes an API that returns a text payload. * * @param method HTTP method. - * @param urlString url as String. + * @param pathSegments Array of path segments (/a/b/c -> ["a", "b", "c"]). * @param urlParameters Parameters in the URL * @param content payload to be posted. * @param headers HTTP headers. * @param context OpenTelemetry's Context. - * @return Response + * @return CompletableFuture for Response. */ - @NotNull - private Response doInvokeApi(String method, - String urlString, + private CompletableFuture doInvokeApi(String method, + String[] pathSegments, Map urlParameters, byte[] content, Map headers, - Context context) throws IOException { + Context context) { final String requestId = UUID.randomUUID().toString(); RequestBody body; - String contentType = headers != null ? headers.get("content-type") : null; + String contentType = headers != null ? headers.get(Metadata.CONTENT_TYPE) : null; MediaType mediaType = contentType == null ? MEDIA_TYPE_APPLICATION_JSON : MediaType.get(contentType); if (content == null) { body = mediaType.equals(MEDIA_TYPE_APPLICATION_JSON) @@ -255,8 +261,10 @@ private Response doInvokeApi(String method, HttpUrl.Builder urlBuilder = new HttpUrl.Builder(); urlBuilder.scheme(DEFAULT_HTTP_SCHEME) .host(this.hostname) - .port(this.port) - .addPathSegments(urlString); + .port(this.port); + for (String pathSegment : pathSegments) { + urlBuilder.addPathSegment(pathSegment); + } Optional.ofNullable(urlParameters).orElse(Collections.emptyMap()).entrySet().stream() .forEach(urlParameter -> urlBuilder.addQueryParameter(urlParameter.getKey(), urlParameter.getValue())); @@ -288,23 +296,10 @@ private Response doInvokeApi(String method, Request request = requestBuilder.build(); - try (okhttp3.Response response = this.httpClient.newCall(request).execute()) { - if (!response.isSuccessful()) { - DaprError error = parseDaprError(getBodyBytesOrEmptyArray(response)); - if ((error != null) && (error.getErrorCode() != null) && (error.getMessage() != null)) { - throw new DaprException(error); - } - - throw new DaprException("UNKNOWN", "HTTP status code: " + response.code()); - } - Map mapHeaders = new HashMap<>(); - byte[] result = getBodyBytesOrEmptyArray(response); - response.headers().forEach(pair -> { - mapHeaders.put(pair.getFirst(), pair.getSecond()); - }); - return new Response(result, mapHeaders, response.code()); - } + CompletableFuture future = new CompletableFuture<>(); + this.httpClient.newCall(request).enqueue(new ResponseFutureCallback(future)); + return future; } /** @@ -317,7 +312,12 @@ private static DaprError parseDaprError(byte[] json) throws IOException { if ((json == null) || (json.length == 0)) { return null; } - return OBJECT_MAPPER.readValue(json, DaprError.class); + + try { + return OBJECT_MAPPER.readValue(json, DaprError.class); + } catch (JsonParseException e) { + throw new DaprException("UNKNOWN", new String(json, StandardCharsets.UTF_8)); + } } private static byte[] getBodyBytesOrEmptyArray(okhttp3.Response response) throws IOException { @@ -329,4 +329,41 @@ private static byte[] getBodyBytesOrEmptyArray(okhttp3.Response response) throws return EMPTY_BYTES; } + /** + * Converts the okhttp3 response into the response object expected internally by the SDK. + */ + private static class ResponseFutureCallback implements Callback { + private final CompletableFuture future; + + public ResponseFutureCallback(CompletableFuture future) { + this.future = future; + } + + @Override + public void onFailure(Call call, IOException e) { + future.completeExceptionally(e); + } + + @Override + public void onResponse(@NotNull Call call, @NotNull okhttp3.Response response) throws IOException { + if (!response.isSuccessful()) { + DaprError error = parseDaprError(getBodyBytesOrEmptyArray(response)); + if ((error != null) && (error.getErrorCode() != null) && (error.getMessage() != null)) { + future.completeExceptionally(new DaprException(error)); + return; + } + + future.completeExceptionally(new DaprException("UNKNOWN", "HTTP status code: " + response.code())); + return; + } + + Map mapHeaders = new HashMap<>(); + byte[] result = getBodyBytesOrEmptyArray(response); + response.headers().forEach(pair -> { + mapHeaders.put(pair.getFirst(), pair.getSecond()); + }); + future.complete(new Response(result, mapHeaders, response.code())); + } + } + } \ No newline at end of file diff --git a/sdk/src/main/java/io/dapr/client/DaprHttpBuilder.java b/sdk/src/main/java/io/dapr/client/DaprHttpBuilder.java index 498f5522e1..8d53490607 100644 --- a/sdk/src/main/java/io/dapr/client/DaprHttpBuilder.java +++ b/sdk/src/main/java/io/dapr/client/DaprHttpBuilder.java @@ -26,26 +26,6 @@ public class DaprHttpBuilder { */ private static final Object LOCK = new Object(); - /** - * Read timeout used to build object. - */ - private Duration readTimeout = Duration.ofSeconds(Properties.HTTP_CLIENT_READTIMEOUTSECONDS.get()); - - /** - * Sets the read timeout duration for the instance to be built. - * - *

Instead, set environment variable "DAPR_HTTP_CLIENT_READTIMEOUTSECONDS", - * or system property "dapr.http.client.readtimeoutseconds". - * - * @param duration Read timeout duration. - * @return Same builder instance. - */ - @Deprecated - public DaprHttpBuilder withReadTimeout(Duration duration) { - this.readTimeout = duration; - return this; - } - /** * Build an instance of the Http client based on the provided setup. * @@ -57,7 +37,7 @@ public DaprHttp build() { } /** - * Creates and instance of the HTTP Client. + * Creates an instance of the HTTP Client. * * @return Instance of {@link DaprHttp} */ @@ -66,7 +46,8 @@ private DaprHttp buildDaprHttp() { synchronized (LOCK) { if (OK_HTTP_CLIENT.get() == null) { OkHttpClient.Builder builder = new OkHttpClient.Builder(); - builder.readTimeout(this.readTimeout); + Duration readTimeout = Duration.ofSeconds(Properties.HTTP_CLIENT_READ_TIMEOUT_SECONDS.get()); + builder.readTimeout(readTimeout); OkHttpClient okHttpClient = builder.build(); OK_HTTP_CLIENT.set(okHttpClient); } diff --git a/sdk/src/main/java/io/dapr/client/domain/CloudEvent.java b/sdk/src/main/java/io/dapr/client/domain/CloudEvent.java index 756404d42e..d57b325ff5 100644 --- a/sdk/src/main/java/io/dapr/client/domain/CloudEvent.java +++ b/sdk/src/main/java/io/dapr/client/domain/CloudEvent.java @@ -7,7 +7,6 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; @@ -28,36 +27,41 @@ public final class CloudEvent { /** * Identifier of the message being processed. */ - private final String id; + private String id; /** * Event's source. */ - private final String source; + private String source; /** * Envelope type. */ - private final String type; + private String type; /** * Version of the specification. */ - private final String specversion; + private String specversion; /** * Type of the data's content. */ - private final String datacontenttype; + private String datacontenttype; /** * Cloud event specs says data can be a JSON object or string. */ - private final String data; + private Object data; /** - * Instantiates a new input request. - * + * Instantiates a CloudEvent. + */ + public CloudEvent() { + } + + /** + * Instantiates a CloudEvent. * @param id Identifier of the message being processed. * @param source Source for this event. * @param type Type of event. @@ -71,7 +75,7 @@ public CloudEvent( String type, String specversion, String datacontenttype, - String data) { + Object data) { this.id = id; this.source = source; this.type = type; @@ -80,9 +84,24 @@ public CloudEvent( this.data = data; } + /** - * Gets the identifier of the message being processed. + * Deserialize a message topic from Dapr. * + * @param payload Payload sent from Dapr. + * @return Message (can be null if input is null) + * @throws IOException If cannot parse. + */ + public static CloudEvent deserialize(byte[] payload) throws IOException { + if (payload == null) { + return null; + } + + return OBJECT_MAPPER.readValue(payload, CloudEvent.class); + } + + /** + * Gets the identifier of the message being processed. * @return Identifier of the message being processed. */ public String getId() { @@ -90,60 +109,104 @@ public String getId() { } /** - * Gets the source for this event. - * - * @return Source for this event. + * Sets the identifier of the message being processed. + * @param id Identifier of the message being processed. + */ + public void setId(String id) { + this.id = id; + } + + /** + * Gets the event's source. + * @return Event's source. */ public String getSource() { return source; } /** - * Gets the type of event. - * - * @return Type of event. + * Sets the event's source. + * @param source Event's source. + */ + public void setSource(String source) { + this.source = source; + } + + /** + * Gets the envelope type. + * @return Envelope type. */ public String getType() { return type; } /** - * Gets the version of the event spec. - * - * @return Version of the event spec. + * Sets the envelope type. + * @param type Envelope type. + */ + public void setType(String type) { + this.type = type; + } + + /** + * Gets the version of the specification. + * @return Version of the specification. */ public String getSpecversion() { return specversion; } /** - * Gets the type of the payload. - * - * @return Type of the payload. + * Sets the version of the specification. + * @param specversion Version of the specification. + */ + public void setSpecversion(String specversion) { + this.specversion = specversion; + } + + /** + * Gets the type of the data's content. + * @return Type of the data's content. */ public String getDatacontenttype() { return datacontenttype; } /** - * Gets the payload. - * - * @return Payload + * Sets the type of the data's content. + * @param datacontenttype Type of the data's content. */ - public String getData() { + public void setDatacontenttype(String datacontenttype) { + this.datacontenttype = datacontenttype; + } + + /** + * Gets the cloud event data. + * @return Cloud event's data. As per specs, data can be a JSON object or string. + */ + public Object getData() { return data; } + /** + * Sets the cloud event data. As per specs, data can be a JSON object or string. + * @param data Cloud event's data. As per specs, data can be a JSON object or string. + */ + public void setData(Object data) { + this.data = data; + } + + /** + * {@inheritDoc} + */ @Override public boolean equals(Object o) { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { return false; } - CloudEvent that = (CloudEvent) o; return Objects.equals(id, that.id) && Objects.equals(source, that.source) @@ -153,64 +216,11 @@ public boolean equals(Object o) { && Objects.equals(data, that.data); } + /** + * {@inheritDoc} + */ @Override public int hashCode() { return Objects.hash(id, source, type, specversion, datacontenttype, data); } - - /** - * Deserialized a message topic from Dapr. - * - * @param payload Payload sent from Dapr. - * @return Message (can be null if input is null) - * @throws IOException If cannot parse. - */ - public static CloudEvent deserialize(byte[] payload) throws IOException { - if (payload == null) { - return null; - } - - JsonNode node = OBJECT_MAPPER.readTree(payload); - - if (node == null) { - return null; - } - - String id = null; - if (node.has("id") && !node.get("id").isNull()) { - id = node.get("id").asText(); - } - - String source = null; - if (node.has("source") && !node.get("source").isNull()) { - source = node.get("source").asText(); - } - - String type = null; - if (node.has("type") && !node.get("type").isNull()) { - type = node.get("type").asText(); - } - - String specversion = null; - if (node.has("specversion") && !node.get("specversion").isNull()) { - specversion = node.get("specversion").asText(); - } - - String datacontenttype = null; - if (node.has("datacontenttype") && !node.get("datacontenttype").isNull()) { - datacontenttype = node.get("datacontenttype").asText(); - } - - String data = null; - if (node.has("data") && !node.get("data").isNull()) { - JsonNode dataNode = node.get("data"); - if (dataNode.isTextual()) { - data = dataNode.textValue(); - } else { - data = node.get("data").toString(); - } - } - - return new CloudEvent(id, source, type, specversion, datacontenttype, data); - } } diff --git a/sdk/src/main/java/io/dapr/client/domain/DeleteStateRequestBuilder.java b/sdk/src/main/java/io/dapr/client/domain/DeleteStateRequestBuilder.java index 819e4b4b0a..803da827c2 100644 --- a/sdk/src/main/java/io/dapr/client/domain/DeleteStateRequestBuilder.java +++ b/sdk/src/main/java/io/dapr/client/domain/DeleteStateRequestBuilder.java @@ -6,6 +6,7 @@ package io.dapr.client.domain; import io.opentelemetry.context.Context; + import java.util.Collections; import java.util.Map; diff --git a/sdk/src/main/java/io/dapr/client/domain/GetBulkSecretRequest.java b/sdk/src/main/java/io/dapr/client/domain/GetBulkSecretRequest.java new file mode 100644 index 0000000000..addd28b7df --- /dev/null +++ b/sdk/src/main/java/io/dapr/client/domain/GetBulkSecretRequest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.client.domain; + +import io.opentelemetry.context.Context; + +import java.util.Map; + +/** + * A request to get a secret by key. + */ +public class GetBulkSecretRequest { + + private String storeName; + + private Map metadata; + + private Context context; + + public String getStoreName() { + return storeName; + } + + void setStoreName(String storeName) { + this.storeName = storeName; + } + + public Map getMetadata() { + return metadata; + } + + void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public Context getContext() { + return context; + } + + void setContext(Context context) { + this.context = context; + } +} diff --git a/sdk/src/main/java/io/dapr/client/domain/GetBulkSecretRequestBuilder.java b/sdk/src/main/java/io/dapr/client/domain/GetBulkSecretRequestBuilder.java new file mode 100644 index 0000000000..320d9cc725 --- /dev/null +++ b/sdk/src/main/java/io/dapr/client/domain/GetBulkSecretRequestBuilder.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.client.domain; + +import io.opentelemetry.context.Context; + +import java.util.Collections; +import java.util.Map; + +/** + * Builds a request to fetch all secrets of a secret store. + */ +public class GetBulkSecretRequestBuilder { + + private final String storeName; + + private Map metadata; + + private Context context; + + public GetBulkSecretRequestBuilder(String storeName) { + this.storeName = storeName; + } + + public GetBulkSecretRequestBuilder withMetadata(Map metadata) { + this.metadata = metadata == null ? null : Collections.unmodifiableMap(metadata); + return this; + } + + public GetBulkSecretRequestBuilder withContext(Context context) { + this.context = context; + return this; + } + + /** + * Builds a request object. + * @return Request object. + */ + public GetBulkSecretRequest build() { + GetBulkSecretRequest request = new GetBulkSecretRequest(); + request.setStoreName(this.storeName); + request.setMetadata(this.metadata); + request.setContext(this.context); + return request; + } + +} diff --git a/sdk/src/main/java/io/dapr/client/domain/GetStatesRequest.java b/sdk/src/main/java/io/dapr/client/domain/GetBulkStateRequest.java similarity index 63% rename from sdk/src/main/java/io/dapr/client/domain/GetStatesRequest.java rename to sdk/src/main/java/io/dapr/client/domain/GetBulkStateRequest.java index e7a2eec2cc..e7acefd1a1 100644 --- a/sdk/src/main/java/io/dapr/client/domain/GetStatesRequest.java +++ b/sdk/src/main/java/io/dapr/client/domain/GetBulkStateRequest.java @@ -1,56 +1,67 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - */ - -package io.dapr.client.domain; - -import io.opentelemetry.context.Context; - -import java.util.List; - -/** - * A request to get bulk state by keys. - */ -public class GetStatesRequest { - - private String stateStoreName; - - private List keys; - - private int parallelism; - - private Context context; - - public String getStateStoreName() { - return stateStoreName; - } - - void setStateStoreName(String stateStoreName) { - this.stateStoreName = stateStoreName; - } - - public List getKeys() { - return keys; - } - - void setKeys(List keys) { - this.keys = keys; - } - - public int getParallelism() { - return parallelism; - } - - void setParallelism(int parallelism) { - this.parallelism = parallelism; - } - - public Context getContext() { - return context; - } - - void setContext(Context context) { - this.context = context; - } -} +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.client.domain; + +import io.opentelemetry.context.Context; + +import java.util.List; +import java.util.Map; + +/** + * A request to get bulk state by keys. + */ +public class GetBulkStateRequest { + + private String storeName; + + private List keys; + + private Map metadata; + + private int parallelism; + + private Context context; + + public String getStoreName() { + return storeName; + } + + void setStoreName(String storeName) { + this.storeName = storeName; + } + + public List getKeys() { + return keys; + } + + void setKeys(List keys) { + this.keys = keys; + } + + public int getParallelism() { + return parallelism; + } + + void setParallelism(int parallelism) { + this.parallelism = parallelism; + } + + public Context getContext() { + return context; + } + + void setContext(Context context) { + this.context = context; + } + + public Map getMetadata() { + return metadata; + } + + void setMetadata(Map metadata) { + this.metadata = metadata; + } +} diff --git a/sdk/src/main/java/io/dapr/client/domain/GetStatesRequestBuilder.java b/sdk/src/main/java/io/dapr/client/domain/GetBulkStateRequestBuilder.java similarity index 50% rename from sdk/src/main/java/io/dapr/client/domain/GetStatesRequestBuilder.java rename to sdk/src/main/java/io/dapr/client/domain/GetBulkStateRequestBuilder.java index f74eb177c5..28b5100d7e 100644 --- a/sdk/src/main/java/io/dapr/client/domain/GetStatesRequestBuilder.java +++ b/sdk/src/main/java/io/dapr/client/domain/GetBulkStateRequestBuilder.java @@ -1,60 +1,69 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - */ - -package io.dapr.client.domain; - -import io.opentelemetry.context.Context; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * Builds a request to request states. - */ -public class GetStatesRequestBuilder { - - private final String stateStoreName; - - private final List keys; - - private int parallelism = 1; - - private Context context; - - public GetStatesRequestBuilder(String stateStoreName, List keys) { - this.stateStoreName = stateStoreName; - this.keys = keys == null ? null : Collections.unmodifiableList(keys); - } - - public GetStatesRequestBuilder(String stateStoreName, String... keys) { - this.stateStoreName = stateStoreName; - this.keys = keys == null ? null : Collections.unmodifiableList(Arrays.asList(keys)); - } - - public GetStatesRequestBuilder withParallelism(int parallelism) { - this.parallelism = parallelism; - return this; - } - - public GetStatesRequestBuilder withContext(Context context) { - this.context = context; - return this; - } - - /** - * Builds a request object. - * @return Request object. - */ - public GetStatesRequest build() { - GetStatesRequest request = new GetStatesRequest(); - request.setStateStoreName(this.stateStoreName); - request.setKeys(this.keys); - request.setParallelism(this.parallelism); - request.setContext(this.context); - return request; - } - -} +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.client.domain; + +import io.opentelemetry.context.Context; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * Builds a request to request states. + */ +public class GetBulkStateRequestBuilder { + + private final String storeName; + + private final List keys; + + private Map metadata; + + private int parallelism = 1; + + private Context context; + + public GetBulkStateRequestBuilder(String storeName, List keys) { + this.storeName = storeName; + this.keys = keys == null ? null : Collections.unmodifiableList(keys); + } + + public GetBulkStateRequestBuilder(String storeName, String... keys) { + this.storeName = storeName; + this.keys = keys == null ? null : Collections.unmodifiableList(Arrays.asList(keys)); + } + + public GetBulkStateRequestBuilder withMetadata(Map metadata) { + this.metadata = metadata == null ? null : Collections.unmodifiableMap(metadata); + return this; + } + + public GetBulkStateRequestBuilder withParallelism(int parallelism) { + this.parallelism = parallelism; + return this; + } + + public GetBulkStateRequestBuilder withContext(Context context) { + this.context = context; + return this; + } + + /** + * Builds a request object. + * @return Request object. + */ + public GetBulkStateRequest build() { + GetBulkStateRequest request = new GetBulkStateRequest(); + request.setStoreName(this.storeName); + request.setKeys(this.keys); + request.setMetadata(this.metadata); + request.setParallelism(this.parallelism); + request.setContext(this.context); + return request; + } + +} diff --git a/sdk/src/main/java/io/dapr/client/domain/GetSecretRequest.java b/sdk/src/main/java/io/dapr/client/domain/GetSecretRequest.java index c1c0d5a78f..dff7586b15 100644 --- a/sdk/src/main/java/io/dapr/client/domain/GetSecretRequest.java +++ b/sdk/src/main/java/io/dapr/client/domain/GetSecretRequest.java @@ -14,7 +14,7 @@ */ public class GetSecretRequest { - private String secretStoreName; + private String storeName; private String key; @@ -22,12 +22,12 @@ public class GetSecretRequest { private Context context; - public String getSecretStoreName() { - return secretStoreName; + public String getStoreName() { + return storeName; } - void setSecretStoreName(String secretStoreName) { - this.secretStoreName = secretStoreName; + void setStoreName(String storeName) { + this.storeName = storeName; } public String getKey() { diff --git a/sdk/src/main/java/io/dapr/client/domain/GetSecretRequestBuilder.java b/sdk/src/main/java/io/dapr/client/domain/GetSecretRequestBuilder.java index 47cbbbc045..b7dd11f159 100644 --- a/sdk/src/main/java/io/dapr/client/domain/GetSecretRequestBuilder.java +++ b/sdk/src/main/java/io/dapr/client/domain/GetSecretRequestBuilder.java @@ -15,7 +15,7 @@ */ public class GetSecretRequestBuilder { - private final String secretStoreName; + private final String storeName; private final String key; @@ -23,8 +23,8 @@ public class GetSecretRequestBuilder { private Context context; - public GetSecretRequestBuilder(String secretStoreName, String key) { - this.secretStoreName = secretStoreName; + public GetSecretRequestBuilder(String storeName, String key) { + this.storeName = storeName; this.key = key; } @@ -44,7 +44,7 @@ public GetSecretRequestBuilder withContext(Context context) { */ public GetSecretRequest build() { GetSecretRequest request = new GetSecretRequest(); - request.setSecretStoreName(this.secretStoreName); + request.setStoreName(this.storeName); request.setKey(this.key); request.setMetadata(this.metadata); request.setContext(this.context); diff --git a/sdk/src/main/java/io/dapr/client/domain/GetStateRequest.java b/sdk/src/main/java/io/dapr/client/domain/GetStateRequest.java index 6cf0cccf9f..ea8e70fd61 100644 --- a/sdk/src/main/java/io/dapr/client/domain/GetStateRequest.java +++ b/sdk/src/main/java/io/dapr/client/domain/GetStateRequest.java @@ -15,24 +15,22 @@ */ public class GetStateRequest { - private String stateStoreName; + private String storeName; private String key; private Map metadata; - private String etag; - private StateOptions stateOptions; private Context context; - public String getStateStoreName() { - return stateStoreName; + public String getStoreName() { + return storeName; } - void setStateStoreName(String stateStoreName) { - this.stateStoreName = stateStoreName; + void setStoreName(String storeName) { + this.storeName = storeName; } public String getKey() { @@ -43,14 +41,6 @@ void setKey(String key) { this.key = key; } - public String getEtag() { - return etag; - } - - void setEtag(String etag) { - this.etag = etag; - } - public StateOptions getStateOptions() { return stateOptions; } diff --git a/sdk/src/main/java/io/dapr/client/domain/GetStateRequestBuilder.java b/sdk/src/main/java/io/dapr/client/domain/GetStateRequestBuilder.java index f6248857a2..f9363c4e4a 100644 --- a/sdk/src/main/java/io/dapr/client/domain/GetStateRequestBuilder.java +++ b/sdk/src/main/java/io/dapr/client/domain/GetStateRequestBuilder.java @@ -6,6 +6,7 @@ package io.dapr.client.domain; import io.opentelemetry.context.Context; + import java.util.Collections; import java.util.Map; @@ -14,20 +15,18 @@ */ public class GetStateRequestBuilder { - private final String stateStoreName; + private final String storeName; private final String key; private Map metadata; - private String etag; - private StateOptions stateOptions; private Context context; - public GetStateRequestBuilder(String stateStoreName, String key) { - this.stateStoreName = stateStoreName; + public GetStateRequestBuilder(String storeName, String key) { + this.storeName = storeName; this.key = key; } @@ -36,11 +35,6 @@ public GetStateRequestBuilder withMetadata(Map metadata) { return this; } - public GetStateRequestBuilder withEtag(String etag) { - this.etag = etag; - return this; - } - public GetStateRequestBuilder withStateOptions(StateOptions stateOptions) { this.stateOptions = stateOptions; return this; @@ -57,10 +51,9 @@ public GetStateRequestBuilder withContext(Context context) { */ public GetStateRequest build() { GetStateRequest request = new GetStateRequest(); - request.setStateStoreName(this.stateStoreName); + request.setStoreName(this.storeName); request.setKey(this.key); request.setMetadata(this.metadata); - request.setEtag(this.etag); request.setStateOptions(this.stateOptions); request.setContext(this.context); return request; diff --git a/sdk/src/main/java/io/dapr/client/domain/HttpExtension.java b/sdk/src/main/java/io/dapr/client/domain/HttpExtension.java index ebba85632d..a7e2ddacb9 100644 --- a/sdk/src/main/java/io/dapr/client/domain/HttpExtension.java +++ b/sdk/src/main/java/io/dapr/client/domain/HttpExtension.java @@ -6,10 +6,8 @@ package io.dapr.client.domain; import io.dapr.client.DaprHttp; -import io.dapr.exceptions.DaprException; import java.util.Collections; -import java.util.HashMap; import java.util.Map; /** @@ -22,39 +20,39 @@ public final class HttpExtension { /** * Convenience HttpExtension object for {@link io.dapr.client.DaprHttp.HttpMethods#NONE} with empty queryString. */ - public static final HttpExtension NONE = new HttpExtension(DaprHttp.HttpMethods.NONE, new HashMap<>()); + public static final HttpExtension NONE = new HttpExtension(DaprHttp.HttpMethods.NONE); /** * Convenience HttpExtension object for the {@link DaprHttp.HttpMethods#GET} Verb with empty queryString. */ - public static final HttpExtension GET = new HttpExtension(DaprHttp.HttpMethods.GET, new HashMap<>()); + public static final HttpExtension GET = new HttpExtension(DaprHttp.HttpMethods.GET); /** * Convenience HttpExtension object for the {@link DaprHttp.HttpMethods#PUT} Verb with empty queryString. */ - public static final HttpExtension PUT = new HttpExtension(DaprHttp.HttpMethods.PUT, new HashMap<>()); + public static final HttpExtension PUT = new HttpExtension(DaprHttp.HttpMethods.PUT); /** * Convenience HttpExtension object for the {@link DaprHttp.HttpMethods#POST} Verb with empty queryString. */ - public static final HttpExtension POST = new HttpExtension(DaprHttp.HttpMethods.POST, new HashMap<>()); + public static final HttpExtension POST = new HttpExtension(DaprHttp.HttpMethods.POST); /** * Convenience HttpExtension object for the {@link DaprHttp.HttpMethods#DELETE} Verb with empty queryString. */ - public static final HttpExtension DELETE = new HttpExtension(DaprHttp.HttpMethods.DELETE, new HashMap<>()); + public static final HttpExtension DELETE = new HttpExtension(DaprHttp.HttpMethods.DELETE); /** * Convenience HttpExtension object for the {@link DaprHttp.HttpMethods#HEAD} Verb with empty queryString. */ - public static final HttpExtension HEAD = new HttpExtension(DaprHttp.HttpMethods.HEAD, new HashMap<>()); + public static final HttpExtension HEAD = new HttpExtension(DaprHttp.HttpMethods.HEAD); /** * Convenience HttpExtension object for the {@link DaprHttp.HttpMethods#CONNECT} Verb with empty queryString. */ - public static final HttpExtension CONNECT = new HttpExtension(DaprHttp.HttpMethods.CONNECT, new HashMap<>()); + public static final HttpExtension CONNECT = new HttpExtension(DaprHttp.HttpMethods.CONNECT); /** * Convenience HttpExtension object for the {@link DaprHttp.HttpMethods#OPTIONS} Verb with empty queryString. */ - public static final HttpExtension OPTIONS = new HttpExtension(DaprHttp.HttpMethods.OPTIONS, new HashMap<>()); + public static final HttpExtension OPTIONS = new HttpExtension(DaprHttp.HttpMethods.OPTIONS); /** * Convenience HttpExtension object for the {@link DaprHttp.HttpMethods#TRACE} Verb with empty queryString. */ - public static final HttpExtension TRACE = new HttpExtension(DaprHttp.HttpMethods.TRACE, new HashMap<>()); + public static final HttpExtension TRACE = new HttpExtension(DaprHttp.HttpMethods.TRACE); /** * HTTP verb. @@ -66,26 +64,37 @@ public final class HttpExtension { */ private Map queryString; + /** + * HTTP headers. + */ + private Map headers; + /** * Construct a HttpExtension object. * @param method Required value denoting the HttpMethod. - * @param queryString Non-null map value for the queryString for a HTTP listener. + * @param queryString map for the queryString the HTTP call. + * @param headers map to set HTTP headers. * @see io.dapr.client.DaprHttp.HttpMethods for supported methods. * @throws IllegalArgumentException on null method or queryString. */ - public HttpExtension(DaprHttp.HttpMethods method, Map queryString) { - try { - if (method == null) { - throw new IllegalArgumentException("HttpExtension method cannot be null"); - } else if (queryString == null) { - throw new IllegalArgumentException("HttpExtension queryString map cannot be null"); - } - - this.method = method; - this.queryString = Collections.unmodifiableMap(queryString); - } catch (RuntimeException e) { - DaprException.wrap(e); + public HttpExtension(DaprHttp.HttpMethods method, Map queryString, Map headers) { + if (method == null) { + throw new IllegalArgumentException("HttpExtension method cannot be null"); } + + this.method = method; + this.queryString = Collections.unmodifiableMap(queryString == null ? Collections.EMPTY_MAP : queryString); + this.headers = Collections.unmodifiableMap(headers == null ? Collections.EMPTY_MAP : headers); + } + + /** + * Construct a HttpExtension object. + * @param method Required value denoting the HttpMethod. + * @see io.dapr.client.DaprHttp.HttpMethods for supported methods. + * @throws IllegalArgumentException on null method or queryString. + */ + public HttpExtension(DaprHttp.HttpMethods method) { + this(method, null, null); } public DaprHttp.HttpMethods getMethod() { @@ -95,4 +104,8 @@ public DaprHttp.HttpMethods getMethod() { public Map getQueryString() { return queryString; } + + public Map getHeaders() { + return headers; + } } diff --git a/sdk/src/main/java/io/dapr/client/domain/InvokeServiceRequest.java b/sdk/src/main/java/io/dapr/client/domain/InvokeMethodRequest.java similarity index 77% rename from sdk/src/main/java/io/dapr/client/domain/InvokeServiceRequest.java rename to sdk/src/main/java/io/dapr/client/domain/InvokeMethodRequest.java index 5b94421be2..3bd9a316e5 100644 --- a/sdk/src/main/java/io/dapr/client/domain/InvokeServiceRequest.java +++ b/sdk/src/main/java/io/dapr/client/domain/InvokeMethodRequest.java @@ -7,12 +7,10 @@ import io.opentelemetry.context.Context; -import java.util.Map; - /** * A request to invoke a service. */ -public class InvokeServiceRequest { +public class InvokeMethodRequest { private String appId; @@ -20,8 +18,6 @@ public class InvokeServiceRequest { private Object body; - private Map metadata; - private HttpExtension httpExtension; private Context context; @@ -52,14 +48,6 @@ void setBody(Object body) { this.body = body; } - public Map getMetadata() { - return metadata; - } - - void setMetadata(Map metadata) { - this.metadata = metadata; - } - public HttpExtension getHttpExtension() { return httpExtension; } diff --git a/sdk/src/main/java/io/dapr/client/domain/InvokeServiceRequestBuilder.java b/sdk/src/main/java/io/dapr/client/domain/InvokeMethodRequestBuilder.java similarity index 51% rename from sdk/src/main/java/io/dapr/client/domain/InvokeServiceRequestBuilder.java rename to sdk/src/main/java/io/dapr/client/domain/InvokeMethodRequestBuilder.java index 030301d6ff..e698b202fc 100644 --- a/sdk/src/main/java/io/dapr/client/domain/InvokeServiceRequestBuilder.java +++ b/sdk/src/main/java/io/dapr/client/domain/InvokeMethodRequestBuilder.java @@ -7,14 +7,10 @@ import io.opentelemetry.context.Context; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - /** * Builds a request to invoke a service. */ -public class InvokeServiceRequestBuilder { +public class InvokeMethodRequestBuilder { private final String appId; @@ -24,38 +20,31 @@ public class InvokeServiceRequestBuilder { private Object body; - private Map metadata = new HashMap<>(); - private HttpExtension httpExtension = HttpExtension.NONE; private Context context; - public InvokeServiceRequestBuilder(String appId, String method) { + public InvokeMethodRequestBuilder(String appId, String method) { this.appId = appId; this.method = method; } - public InvokeServiceRequestBuilder withContentType(String contentType) { + public InvokeMethodRequestBuilder withContentType(String contentType) { this.contentType = contentType; return this; } - public InvokeServiceRequestBuilder withBody(Object body) { + public InvokeMethodRequestBuilder withBody(Object body) { this.body = body; return this; } - public InvokeServiceRequestBuilder withMetadata(Map metadata) { - this.metadata = metadata == null ? null : Collections.unmodifiableMap(metadata); - return this; - } - - public InvokeServiceRequestBuilder withHttpExtension(HttpExtension httpExtension) { + public InvokeMethodRequestBuilder withHttpExtension(HttpExtension httpExtension) { this.httpExtension = httpExtension; return this; } - public InvokeServiceRequestBuilder withContext(Context context) { + public InvokeMethodRequestBuilder withContext(Context context) { this.context = context; return this; } @@ -64,14 +53,13 @@ public InvokeServiceRequestBuilder withContext(Context context) { * Builds a request object. * @return Request object. */ - public InvokeServiceRequest build() { - InvokeServiceRequest request = new InvokeServiceRequest(); + public InvokeMethodRequest build() { + InvokeMethodRequest request = new InvokeMethodRequest(); request.setAppId(this.appId); request.setContentType(contentType); request.setMethod(this.method); request.setBody(this.body); request.setHttpExtension(this.httpExtension); - request.setMetadata(this.metadata); request.setContext(this.context); return request; } diff --git a/sdk/src/main/java/io/dapr/client/domain/Metadata.java b/sdk/src/main/java/io/dapr/client/domain/Metadata.java new file mode 100644 index 0000000000..1d4a1bddc0 --- /dev/null +++ b/sdk/src/main/java/io/dapr/client/domain/Metadata.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.client.domain; + +/** + * Enumerates commonly used metadata attributes. + */ +public final class Metadata { + + public static final String CONTENT_TYPE = "content-type"; + + public static final String TTL_IN_SECONDS = "ttlInSeconds"; + + private Metadata() { + } +} diff --git a/sdk/src/main/java/io/dapr/client/domain/SaveStateRequest.java b/sdk/src/main/java/io/dapr/client/domain/SaveStateRequest.java index e4c8260f36..95598589a2 100644 --- a/sdk/src/main/java/io/dapr/client/domain/SaveStateRequest.java +++ b/sdk/src/main/java/io/dapr/client/domain/SaveStateRequest.java @@ -14,18 +14,18 @@ */ public class SaveStateRequest { - private String stateStoreName; + private String storeName; private List> states; private Context context; - public String getStateStoreName() { - return stateStoreName; + public String getStoreName() { + return storeName; } - void setStateStoreName(String stateStoreName) { - this.stateStoreName = stateStoreName; + void setStoreName(String storeName) { + this.storeName = storeName; } public List> getStates() { diff --git a/sdk/src/main/java/io/dapr/client/domain/SaveStateRequestBuilder.java b/sdk/src/main/java/io/dapr/client/domain/SaveStateRequestBuilder.java index f19ea80227..3e47e4a9fd 100644 --- a/sdk/src/main/java/io/dapr/client/domain/SaveStateRequestBuilder.java +++ b/sdk/src/main/java/io/dapr/client/domain/SaveStateRequestBuilder.java @@ -17,14 +17,14 @@ */ public class SaveStateRequestBuilder { - private final String stateStoreName; + private final String storeName; private List> states = new ArrayList<>(); private Context context; - public SaveStateRequestBuilder(String stateStoreName) { - this.stateStoreName = stateStoreName; + public SaveStateRequestBuilder(String storeName) { + this.storeName = storeName; } public SaveStateRequestBuilder withStates(State... states) { @@ -48,7 +48,7 @@ public SaveStateRequestBuilder withContext(Context context) { */ public SaveStateRequest build() { SaveStateRequest request = new SaveStateRequest(); - request.setStateStoreName(this.stateStoreName); + request.setStoreName(this.storeName); request.setStates(this.states); request.setContext(this.context); return request; diff --git a/sdk/src/main/java/io/dapr/client/domain/State.java b/sdk/src/main/java/io/dapr/client/domain/State.java index 7938d8c44e..2f7d5083a5 100644 --- a/sdk/src/main/java/io/dapr/client/domain/State.java +++ b/sdk/src/main/java/io/dapr/client/domain/State.java @@ -26,7 +26,7 @@ public class State { /** * The ETag to be used - * Keep in mind that for some state stores (like reids) only numbers are supported. + * Keep in mind that for some state stores (like redis) only numbers are supported. */ private final String etag; diff --git a/sdk/src/main/java/io/dapr/config/Properties.java b/sdk/src/main/java/io/dapr/config/Properties.java index 79c58ea402..0cf16f16a4 100644 --- a/sdk/src/main/java/io/dapr/config/Properties.java +++ b/sdk/src/main/java/io/dapr/config/Properties.java @@ -5,6 +5,8 @@ package io.dapr.config; +import io.dapr.client.DaprApiProtocol; + import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -14,7 +16,7 @@ public class Properties { /** - * Dapr's default IP for HTTP and GRPC communication. + * Dapr's default IP for HTTP and gRPC communication. */ private static final String DEFAULT_SIDECAR_IP = "127.0.0.1"; @@ -24,14 +26,19 @@ public class Properties { private static final Integer DEFAULT_HTTP_PORT = 3500; /** - * Dapr's default GRPC port. + * Dapr's default gRPC port. */ private static final Integer DEFAULT_GRPC_PORT = 50001; /** - * Dapr's default GRPC port. + * Dapr's default use of gRPC or HTTP. + */ + private static final DaprApiProtocol DEFAULT_API_PROTOCOL = DaprApiProtocol.GRPC; + + /** + * Dapr's default use of gRPC or HTTP for Dapr's method invocation APIs. */ - private static final Boolean DEFAULT_GRPC_ENABLED = true; + private static final DaprApiProtocol DEFAULT_API_METHOD_INVOCATION_PROTOCOL = DaprApiProtocol.HTTP; /** * Dapr's default String encoding: UTF-8. @@ -68,12 +75,22 @@ public class Properties { DEFAULT_GRPC_PORT); /** - * Determines if Dapr client will use GRPC to talk to Dapr's side car. + * Determines if Dapr client will use gRPC or HTTP to talk to Dapr's side car. + */ + public static final Property API_PROTOCOL = new GenericProperty<>( + "dapr.api.protocol", + "DAPR_API_PROTOCOL", + DEFAULT_API_PROTOCOL, + (s) -> DaprApiProtocol.valueOf(s.toUpperCase())); + + /** + * Determines if Dapr client should use gRPC or HTTP for Dapr's service method invocation APIs. */ - public static final Property USE_GRPC = new BooleanProperty( - "dapr.grpc.enabled", - "DAPR_GRPC_ENABLED", - DEFAULT_GRPC_ENABLED); + public static final Property API_METHOD_INVOCATION_PROTOCOL = new GenericProperty<>( + "dapr.api.methodInvocation.protocol", + "DAPR_API_METHOD_INVOCATION_PROTOCOL", + DEFAULT_API_METHOD_INVOCATION_PROTOCOL, + (s) -> DaprApiProtocol.valueOf(s.toUpperCase())); /** * API token for authentication between App and Dapr's side car. @@ -95,8 +112,8 @@ public class Properties { /** * Dapr's timeout in seconds for HTTP client reads. */ - public static final Property HTTP_CLIENT_READTIMEOUTSECONDS = new IntegerProperty( - "dapr.http.client.readtimeoutseconds", - "DAPR_HTTP_CLIENT_READTIMEOUTSECONDS", + public static final Property HTTP_CLIENT_READ_TIMEOUT_SECONDS = new IntegerProperty( + "dapr.http.client.readTimeoutSeconds", + "DAPR_HTTP_CLIENT_READ_TIMEOUT_SECONDS", DEFAULT_HTTP_CLIENT_READTIMEOUTSECONDS); } diff --git a/sdk/src/main/java/io/dapr/exceptions/DaprException.java b/sdk/src/main/java/io/dapr/exceptions/DaprException.java index f9d25457b7..0996c75b58 100644 --- a/sdk/src/main/java/io/dapr/exceptions/DaprException.java +++ b/sdk/src/main/java/io/dapr/exceptions/DaprException.java @@ -6,11 +6,10 @@ package io.dapr.exceptions; import io.grpc.StatusRuntimeException; +import reactor.core.Exceptions; import reactor.core.publisher.Mono; -import java.lang.reflect.Executable; import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; /** * A Dapr's specific exception. @@ -39,7 +38,7 @@ public DaprException(DaprError daprError) { * permitted, and indicates that the cause is nonexistent or * unknown.) */ - public DaprException(DaprError daprError, Exception cause) { + public DaprException(DaprError daprError, Throwable cause) { this(daprError.getErrorCode(), daprError.getMessage(), cause); } @@ -47,7 +46,7 @@ public DaprException(DaprError daprError, Exception cause) { * Wraps an exception into a DaprException. * @param exception the exception to be wrapped. */ - public DaprException(Exception exception) { + public DaprException(Throwable exception) { this("UNKNOWN", exception.getMessage(), exception); } @@ -71,7 +70,7 @@ public DaprException(String errorCode, String message) { * permitted, and indicates that the cause is nonexistent or * unknown.) */ - public DaprException(String errorCode, String message, Exception cause) { + public DaprException(String errorCode, String message, Throwable cause) { super(String.format("%s: %s", errorCode, emptyIfNull(message)), cause); this.errorCode = errorCode; } @@ -85,47 +84,17 @@ public String getErrorCode() { return this.errorCode; } - /** - * Convenience to throw an wrapped IllegalArgumentException. - * @param message Message for exception. - */ - public static void throwIllegalArgumentException(String message) { - try { - throw new IllegalArgumentException(message); - } catch (Exception e) { - wrap(e); - } - } - /** * Wraps an exception into DaprException (if not already DaprException). * * @param exception Exception to be wrapped. - * @return DaprException. */ - public static DaprException wrap(Exception exception) { + public static void wrap(Throwable exception) { if (exception == null) { - return null; - } - - if (exception instanceof DaprException) { - throw (DaprException) exception; - } - - Throwable e = exception; - while (e != null) { - if (e instanceof StatusRuntimeException) { - StatusRuntimeException statusRuntimeException = (StatusRuntimeException) e; - throw new DaprException( - statusRuntimeException.getStatus().getCode().toString(), - statusRuntimeException.getStatus().getDescription(), - exception); - } - - e = e.getCause(); + return; } - throw new DaprException(exception); + throw propagate(exception); } /** @@ -139,7 +108,23 @@ public static Callable wrap(Callable callable) { try { return callable.call(); } catch (Exception e) { - return (T) wrap(e); + wrap(e); + return null; + } + }; + } + + /** + * Wraps a runnable with a try-catch to throw DaprException. + * @param runnable runnable to be invoked. + * @return object of type T. + */ + public static Runnable wrap(Runnable runnable) { + return () -> { + try { + runnable.run(); + } catch (Exception e) { + wrap(e); } }; } @@ -161,6 +146,39 @@ public static Mono wrapMono(Exception exception) { return Mono.empty(); } + /** + * Wraps an exception into DaprException (if not already DaprException). + * + * @param exception Exception to be wrapped. + * @return wrapped RuntimeException + */ + public static RuntimeException propagate(Throwable exception) { + Exceptions.throwIfFatal(exception); + + if (exception instanceof DaprException) { + return (DaprException) exception; + } + + Throwable e = exception; + while (e != null) { + if (e instanceof StatusRuntimeException) { + StatusRuntimeException statusRuntimeException = (StatusRuntimeException) e; + return new DaprException( + statusRuntimeException.getStatus().getCode().toString(), + statusRuntimeException.getStatus().getDescription(), + exception); + } + + e = e.getCause(); + } + + if (exception instanceof IllegalArgumentException) { + return (IllegalArgumentException) exception; + } + + return new DaprException(exception); + } + private static String emptyIfNull(String str) { if (str == null) { return ""; diff --git a/sdk/src/main/java/io/dapr/utils/NetworkUtils.java b/sdk/src/main/java/io/dapr/utils/NetworkUtils.java new file mode 100644 index 0000000000..b9fff405f5 --- /dev/null +++ b/sdk/src/main/java/io/dapr/utils/NetworkUtils.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.utils; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; + +/** + * Utility methods for network, internal to Dapr SDK. + */ +public final class NetworkUtils { + + private NetworkUtils() { + } + + /** + * Tries to connect to a socket, retrying every 1 second. + * @param host Host to connect to. + * @param port Port to connect to. + * @param timeoutInMilliseconds Timeout in milliseconds to give up trying. + * @throws InterruptedException If retry is interrupted. + */ + public static void waitForSocket(String host, int port, int timeoutInMilliseconds) throws InterruptedException { + long started = System.currentTimeMillis(); + Retry.callWithRetry(() -> { + try { + try (Socket socket = new Socket()) { + // timeout cannot be negative. + // zero timeout means infinite, so 1 is the practical minimum. + int remainingTimeout = (int) Math.max(1, timeoutInMilliseconds - (System.currentTimeMillis() - started)); + socket.connect(new InetSocketAddress(host, port), remainingTimeout); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + }, timeoutInMilliseconds); + } +} diff --git a/sdk/src/main/java/io/dapr/utils/Retry.java b/sdk/src/main/java/io/dapr/utils/Retry.java new file mode 100644 index 0000000000..09cc01c890 --- /dev/null +++ b/sdk/src/main/java/io/dapr/utils/Retry.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +package io.dapr.utils; + +class Retry { + + private static final long RETRY_WAIT_MILLISECONDS = 1000; + + private Retry() { + } + + static void callWithRetry(Runnable function, long retryTimeoutMilliseconds) throws InterruptedException { + long started = System.currentTimeMillis(); + while (true) { + Throwable exception; + try { + function.run(); + return; + } catch (Exception e) { + exception = e; + } catch (AssertionError e) { + exception = e; + } + + long elapsed = System.currentTimeMillis() - started; + if (elapsed >= retryTimeoutMilliseconds) { + if (exception instanceof RuntimeException) { + throw (RuntimeException)exception; + } + + throw new RuntimeException(exception); + } + + long remaining = retryTimeoutMilliseconds - elapsed; + Thread.sleep(Math.min(remaining, RETRY_WAIT_MILLISECONDS)); + } + } +} diff --git a/sdk/src/main/java/io/dapr/utils/TypeRef.java b/sdk/src/main/java/io/dapr/utils/TypeRef.java index a3f9c32fc5..aeb24b8e2d 100644 --- a/sdk/src/main/java/io/dapr/utils/TypeRef.java +++ b/sdk/src/main/java/io/dapr/utils/TypeRef.java @@ -57,10 +57,10 @@ public TypeRef() { /** * Constructor for reflection. * - * @param clazz Class type to be referenced. + * @param type Type to be referenced. */ - private TypeRef(Class clazz) { - this.type = clazz; + private TypeRef(Type type) { + this.type = type; } /** @@ -118,4 +118,19 @@ public static TypeRef get(Class clazz) { return new TypeRef(clazz) {}; } + + /** + * Creates a reference to a given class type. + * @param type Type to be referenced. + * @param Type to be referenced. + * @return Class type reference. + */ + public static TypeRef get(Type type) { + if (type instanceof Class) { + Class clazz = (Class) type; + return get(clazz); + } + + return new TypeRef(type) {}; + } } diff --git a/sdk/src/test/java/io/dapr/client/DaprClientBuilderTest.java b/sdk/src/test/java/io/dapr/client/DaprClientBuilderTest.java index d9db53aae1..b235e0799d 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientBuilderTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientBuilderTest.java @@ -5,7 +5,6 @@ package io.dapr.client; -import io.dapr.exceptions.DaprException; import io.dapr.serializer.DaprObjectSerializer; import org.junit.Test; @@ -27,17 +26,17 @@ public void build() { assertNotNull(daprClient); } - @Test(expected = DaprException.class) + @Test(expected = IllegalArgumentException.class) public void noObjectSerializer() { new DaprClientBuilder().withObjectSerializer(null); } - @Test(expected = DaprException.class) + @Test(expected = IllegalArgumentException.class) public void blankContentTypeInObjectSerializer() { new DaprClientBuilder().withObjectSerializer(mock(DaprObjectSerializer.class)); } - @Test(expected = DaprException.class) + @Test(expected = IllegalArgumentException.class) public void noStateSerializer() { new DaprClientBuilder().withStateSerializer(null); } diff --git a/sdk/src/test/java/io/dapr/client/DaprClientGrpcTest.java b/sdk/src/test/java/io/dapr/client/DaprClientGrpcTest.java index 42db5d3c26..0df44775bb 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientGrpcTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientGrpcTest.java @@ -5,8 +5,6 @@ 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; @@ -14,15 +12,16 @@ import io.dapr.client.domain.DeleteStateRequestBuilder; import io.dapr.client.domain.ExecuteStateTransactionRequest; import io.dapr.client.domain.ExecuteStateTransactionRequestBuilder; +import io.dapr.client.domain.GetBulkStateRequest; +import io.dapr.client.domain.GetBulkStateRequestBuilder; import io.dapr.client.domain.GetStateRequest; import io.dapr.client.domain.GetStateRequestBuilder; -import io.dapr.client.domain.GetStatesRequest; -import io.dapr.client.domain.GetStatesRequestBuilder; import io.dapr.client.domain.HttpExtension; import io.dapr.client.domain.Response; import io.dapr.client.domain.State; import io.dapr.client.domain.StateOptions; import io.dapr.client.domain.TransactionalStateOperation; +import io.dapr.config.Properties; import io.dapr.serializer.DaprObjectSerializer; import io.dapr.serializer.DefaultObjectSerializer; import io.dapr.utils.TypeRef; @@ -30,28 +29,33 @@ import io.dapr.v1.DaprGrpc; import io.dapr.v1.DaprProtos; import io.grpc.Status; -import io.grpc.StatusException; import io.grpc.StatusRuntimeException; -import org.checkerframework.checker.nullness.compatqual.NullableDecl; +import io.grpc.stub.StreamObserver; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; +import org.mockito.stubbing.Answer; import reactor.core.publisher.Mono; import java.io.Closeable; import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; -import static com.google.common.util.concurrent.Futures.addCallback; -import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static io.dapr.utils.TestUtils.assertThrowsDaprException; +import static io.dapr.utils.TestUtils.findFreePort; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -61,6 +65,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.argThat; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; @@ -75,49 +80,75 @@ public class DaprClientGrpcTest { private static final String SECRET_STORE_NAME = "MySecretStore"; private Closeable closeable; - private DaprGrpc.DaprFutureStub client; - private DaprClientGrpc adapter; + private DaprGrpc.DaprStub daprStub; + private DaprClient client; private ObjectSerializer serializer; @Before public void setup() throws IOException { closeable = mock(Closeable.class); - client = mock(DaprGrpc.DaprFutureStub.class); - when(client.withInterceptors(any())).thenReturn(client); - adapter = new DaprClientGrpc(closeable, client, new DefaultObjectSerializer(), new DefaultObjectSerializer()); + daprStub = mock(DaprGrpc.DaprStub.class); + when(daprStub.withInterceptors(any())).thenReturn(daprStub); + DaprClient grpcClient = new DaprClientGrpc( + closeable, daprStub, new DefaultObjectSerializer(), new DefaultObjectSerializer()); + client = new DaprClientProxy(grpcClient); serializer = new ObjectSerializer(); doNothing().when(closeable).close(); } @After public void tearDown() throws Exception { - adapter.close(); + client.close(); verify(closeable).close(); verifyNoMoreInteractions(closeable); } + @Test + public void waitForSidecarTimeout() throws Exception { + int port = findFreePort(); + System.setProperty(Properties.GRPC_PORT.getName(), Integer.toString(port)); + assertThrows(RuntimeException.class, () -> client.waitForSidecar(1).block()); + } + + @Test + public void waitForSidecarTimeoutOK() throws Exception { + try (ServerSocket serverSocket = new ServerSocket(0)) { + final int port = serverSocket.getLocalPort(); + System.setProperty(Properties.GRPC_PORT.getName(), Integer.toString(port)); + Thread t = new Thread(() -> { + try { + try (Socket socket = serverSocket.accept()) { + } + } catch (IOException e) { + } + }); + t.start(); + client.waitForSidecar(10000).block(); + } + } + @Test public void publishEventExceptionThrownTest() { - when(client.publishEvent(any(DaprProtos.PublishEventRequest.class))) - .thenThrow(newStatusRuntimeException("INVALID_ARGUMENT", "bad bad argument")); + doAnswer((Answer) invocation -> { + throw newStatusRuntimeException("INVALID_ARGUMENT", "bad bad argument"); + }).when(daprStub).publishEvent(any(DaprProtos.PublishEventRequest.class), any()); assertThrowsDaprException( - StatusRuntimeException.class, - "INVALID_ARGUMENT", - "INVALID_ARGUMENT: bad bad argument", - () -> adapter.publishEvent("pubsubname","topic", "object").block()); + StatusRuntimeException.class, + "INVALID_ARGUMENT", + "INVALID_ARGUMENT: bad bad argument", + () -> client.publishEvent("pubsubname","topic", "object").block()); } @Test public void publishEventCallbackExceptionThrownTest() { - SettableFuture settableFuture = SettableFuture.create(); - RuntimeException ex = newStatusRuntimeException("INVALID_ARGUMENT", "bad bad argument"); - MockCallback callback = new MockCallback<>(ex); - addCallback(settableFuture, callback, directExecutor()); - when(client.publishEvent(any(DaprProtos.PublishEventRequest.class))) - .thenReturn(settableFuture); - Mono result = adapter.publishEvent("pubsubname","topic", "object"); - settableFuture.setException(ex); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onError(newStatusRuntimeException("INVALID_ARGUMENT", "bad bad argument")); + return null; + }).when(daprStub).publishEvent(any(DaprProtos.PublishEventRequest.class), any()); + + Mono result = client.publishEvent("pubsubname","topic", "object"); assertThrowsDaprException( ExecutionException.class, @@ -129,12 +160,16 @@ public void publishEventCallbackExceptionThrownTest() { @Test public void publishEventSerializeException() throws IOException { DaprObjectSerializer mockSerializer = mock(DaprObjectSerializer.class); - adapter = new DaprClientGrpc(closeable, client, mockSerializer, new DefaultObjectSerializer()); - SettableFuture settableFuture = SettableFuture.create(); - when(client.publishEvent(any(DaprProtos.PublishEventRequest.class))) - .thenReturn(settableFuture); + client = new DaprClientGrpc(closeable, daprStub, mockSerializer, new DefaultObjectSerializer()); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).publishEvent(any(DaprProtos.PublishEventRequest.class), any()); + when(mockSerializer.serialize(any())).thenThrow(IOException.class); - Mono result = adapter.publishEvent("pubsubname","topic", "{invalid-json"); + Mono result = client.publishEvent("pubsubname","topic", "{invalid-json"); assertThrowsDaprException( IOException.class, @@ -145,75 +180,79 @@ public void publishEventSerializeException() throws IOException { @Test public void publishEventTest() { - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.publishEvent(any(DaprProtos.PublishEventRequest.class))) - .thenReturn(settableFuture); - Mono result = adapter.publishEvent("pubsubname","topic", "object"); - settableFuture.set(Empty.newBuilder().build()); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).publishEvent(any(DaprProtos.PublishEventRequest.class), any()); + + Mono result = client.publishEvent("pubsubname","topic", "object"); result.block(); - assertTrue(callback.wasCalled); } @Test public void publishEventNoHotMono() { - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.publishEvent(any(DaprProtos.PublishEventRequest.class))) - .thenAnswer(c -> { - settableFuture.set(Empty.newBuilder().build()); - return settableFuture; - }); - adapter.publishEvent("pubsubname", "topic", "object"); + AtomicBoolean called = new AtomicBoolean(false); + doAnswer((Answer) invocation -> { + called.set(true); + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).publishEvent(any(DaprProtos.PublishEventRequest.class), any()); + client.publishEvent("pubsubname", "topic", "object"); // Do not call block() on the mono above, so nothing should happen. - assertFalse(callback.wasCalled); + assertFalse(called.get()); } @Test public void publishEventObjectTest() { - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.publishEvent(any(DaprProtos.PublishEventRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).publishEvent(any(DaprProtos.PublishEventRequest.class), any()); + MyObject event = new MyObject(1, "Event"); - Mono result = adapter.publishEvent("pubsubname", "topic", event); - settableFuture.set(Empty.newBuilder().build()); + Mono result = client.publishEvent("pubsubname", "topic", event); result.block(); - assertTrue(callback.wasCalled); } @Test public void invokeBindingIllegalArgumentExceptionTest() { - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // empty binding name - adapter.invokeBinding("", "MyOperation", "request".getBytes(), Collections.EMPTY_MAP).block(); + client.invokeBinding("", "MyOperation", "request".getBytes(), Collections.EMPTY_MAP).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // null binding name - adapter.invokeBinding(null, "MyOperation", "request".getBytes(), Collections.EMPTY_MAP).block(); + client.invokeBinding(null, "MyOperation", "request".getBytes(), Collections.EMPTY_MAP).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // null binding operation - adapter.invokeBinding("BindingName", null, "request".getBytes(), Collections.EMPTY_MAP).block(); + client.invokeBinding("BindingName", null, "request".getBytes(), Collections.EMPTY_MAP).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // empty binding operation - adapter.invokeBinding("BindingName", "", "request".getBytes(), Collections.EMPTY_MAP).block(); + client.invokeBinding("BindingName", "", "request".getBytes(), Collections.EMPTY_MAP).block(); }); } @Test public void invokeBindingSerializeException() throws IOException { DaprObjectSerializer mockSerializer = mock(DaprObjectSerializer.class); - adapter = new DaprClientGrpc(closeable, client, mockSerializer, new DefaultObjectSerializer()); - SettableFuture settableFuture = SettableFuture.create(); - when(client.invokeBinding(any(DaprProtos.InvokeBindingRequest.class))) - .thenReturn(settableFuture); + client = new DaprClientGrpc(closeable, daprStub, mockSerializer, new DefaultObjectSerializer()); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeBinding(any(DaprProtos.InvokeBindingRequest.class), any()); + when(mockSerializer.serialize(any())).thenThrow(IOException.class); - Mono result = adapter.invokeBinding("BindingName", "MyOperation", "request".getBytes(), Collections.EMPTY_MAP); + Mono result = client.invokeBinding("BindingName", "MyOperation", "request".getBytes(), Collections.EMPTY_MAP); assertThrowsDaprException( IOException.class, @@ -224,9 +263,11 @@ public void invokeBindingSerializeException() throws IOException { @Test public void invokeBindingExceptionThrownTest() { - when(client.invokeBinding(any(DaprProtos.InvokeBindingRequest.class))) - .thenThrow(RuntimeException.class); - Mono result = adapter.invokeBinding("BindingName", "MyOperation", "request"); + doAnswer((Answer) invocation -> { + throw new RuntimeException(); + }).when(daprStub).invokeBinding(any(DaprProtos.InvokeBindingRequest.class), any()); + + Mono result = client.invokeBinding("BindingName", "MyOperation", "request"); assertThrowsDaprException( RuntimeException.class, @@ -237,15 +278,14 @@ public void invokeBindingExceptionThrownTest() { @Test 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.InvokeBindingRequest.class))) - .thenReturn(settableFuture); - Mono result = adapter.invokeBinding("BindingName", "MyOperation", "request"); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onError(ex); + return null; + }).when(daprStub).invokeBinding(any(DaprProtos.InvokeBindingRequest.class), any()); + + Mono result = client.invokeBinding("BindingName", "MyOperation", "request"); assertThrowsDaprException( ExecutionException.class, @@ -256,103 +296,111 @@ public void invokeBindingCallbackExceptionThrownTest() { @Test public void invokeBindingTest() throws IOException { - SettableFuture settableFuture = SettableFuture.create(); DaprProtos.InvokeBindingResponse.Builder responseBuilder = DaprProtos.InvokeBindingResponse.newBuilder().setData(serialize("OK")); - MockCallback callback = new MockCallback<>(responseBuilder.build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.invokeBinding(any(DaprProtos.InvokeBindingRequest.class))) - .thenReturn(settableFuture); - Mono result = adapter.invokeBinding("BindingName", "MyOperation", "request"); - settableFuture.set(responseBuilder.build()); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseBuilder.build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeBinding(any(DaprProtos.InvokeBindingRequest.class), any()); + + Mono result = client.invokeBinding("BindingName", "MyOperation", "request"); result.block(); - assertTrue(callback.wasCalled); } @Test - public void invokeBindingByteArrayTest() throws IOException { - SettableFuture settableFuture = SettableFuture.create(); + public void invokeBindingByteArrayTest() { DaprProtos.InvokeBindingResponse.Builder responseBuilder = DaprProtos.InvokeBindingResponse.newBuilder().setData(ByteString.copyFrom("OK".getBytes())); - MockCallback callback = new MockCallback<>(responseBuilder.build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.invokeBinding(any(DaprProtos.InvokeBindingRequest.class))) - .thenReturn(settableFuture); - Mono result = adapter.invokeBinding("BindingName", "MyOperation", "request".getBytes(), Collections.EMPTY_MAP); - settableFuture.set(responseBuilder.build()); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseBuilder.build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeBinding(any(DaprProtos.InvokeBindingRequest.class), any()); + + Mono result = client.invokeBinding("BindingName", "MyOperation", "request".getBytes(), Collections.EMPTY_MAP); + assertEquals("OK", new String(result.block(), StandardCharsets.UTF_8)); - assertTrue(callback.wasCalled); } @Test public void invokeBindingObjectTest() throws IOException { - SettableFuture settableFuture = SettableFuture.create(); DaprProtos.InvokeBindingResponse.Builder responseBuilder = DaprProtos.InvokeBindingResponse.newBuilder().setData(serialize("OK")); - MockCallback callback = new MockCallback<>(responseBuilder.build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.invokeBinding(any(DaprProtos.InvokeBindingRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseBuilder.build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeBinding(any(DaprProtos.InvokeBindingRequest.class), any()); + MyObject event = new MyObject(1, "Event"); - Mono result = adapter.invokeBinding("BindingName", "MyOperation", event); - settableFuture.set(responseBuilder.build()); + Mono result = client.invokeBinding("BindingName", "MyOperation", event); + result.block(); - assertTrue(callback.wasCalled); } @Test public void invokeBindingResponseObjectTest() throws IOException { - SettableFuture settableFuture = SettableFuture.create(); DaprProtos.InvokeBindingResponse.Builder responseBuilder = DaprProtos.InvokeBindingResponse.newBuilder().setData(serialize("OK")); - MockCallback callback = new MockCallback<>(responseBuilder.build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.invokeBinding(any(DaprProtos.InvokeBindingRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseBuilder.build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeBinding(any(DaprProtos.InvokeBindingRequest.class), any()); + MyObject event = new MyObject(1, "Event"); - Mono result = adapter.invokeBinding("BindingName", "MyOperation", event, String.class); - settableFuture.set(responseBuilder.build()); + Mono result = client.invokeBinding("BindingName", "MyOperation", event, String.class); + assertEquals("OK", result.block()); - assertTrue(callback.wasCalled); } @Test public void invokeBindingResponseObjectTypeRefTest() throws IOException { - SettableFuture settableFuture = SettableFuture.create(); DaprProtos.InvokeBindingResponse.Builder responseBuilder = - DaprProtos.InvokeBindingResponse.newBuilder().setData(serialize("OK")); - MockCallback callback = new MockCallback<>(responseBuilder.build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.invokeBinding(any(DaprProtos.InvokeBindingRequest.class))) - .thenReturn(settableFuture); + DaprProtos.InvokeBindingResponse.newBuilder().setData(serialize("OK")); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseBuilder.build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeBinding(any(DaprProtos.InvokeBindingRequest.class), any()); + MyObject event = new MyObject(1, "Event"); - Mono result = adapter.invokeBinding("BindingName", "MyOperation", event, TypeRef.get(String.class)); - settableFuture.set(responseBuilder.build()); + Mono result = client.invokeBinding("BindingName", "MyOperation", event, TypeRef.get(String.class)); + assertEquals("OK", result.block()); - assertTrue(callback.wasCalled); } @Test - public void invokeBindingObjectNoHotMono() { - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.invokeBinding(any(DaprProtos.InvokeBindingRequest.class))) - .thenAnswer(c -> { - settableFuture.set(Empty.newBuilder().build()); - return settableFuture; - }); + public void invokeBindingObjectNoHotMono() throws IOException { + AtomicBoolean called = new AtomicBoolean(false); + DaprProtos.InvokeBindingResponse.Builder responseBuilder = + DaprProtos.InvokeBindingResponse.newBuilder().setData(serialize("OK")); + doAnswer((Answer) invocation -> { + called.set(true); + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseBuilder.build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeBinding(any(DaprProtos.InvokeBindingRequest.class), any()); MyObject event = new MyObject(1, "Event"); - adapter.invokeBinding("BindingName", "MyOperation", event); + client.invokeBinding("BindingName", "MyOperation", event); // Do not call block() on mono above, so nothing should happen. - assertFalse(callback.wasCalled); + assertFalse(called.get()); } @Test public void invokeServiceVoidExceptionThrownTest() { - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenThrow(RuntimeException.class); - Mono result = adapter.invokeService("appId", "method", "request", HttpExtension.NONE); + doAnswer((Answer) invocation -> { + throw new RuntimeException(); + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + + Mono result = client.invokeMethod("appId", "method", "request", HttpExtension.NONE); assertThrowsDaprException( RuntimeException.class, @@ -363,24 +411,26 @@ public void invokeServiceVoidExceptionThrownTest() { @Test public void invokeServiceIllegalArgumentExceptionThrownTest() { - SettableFuture settableFuture = SettableFuture.create(); - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(CommonProtos.InvokeResponse.newBuilder().setData(getAny("Value")).build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + // HttpExtension cannot be null - Mono result = adapter.invokeService("appId", "method", "request", null); + Mono result = client.invokeMethod("appId", "method", "request", null); - assertThrowsDaprException( - IllegalArgumentException.class, - "UNKNOWN", - "UNKNOWN: HttpExtension cannot be null. Use HttpExtension.NONE instead.", - () -> result.block()); + assertThrows(IllegalArgumentException.class, () -> result.block()); } @Test public void invokeServiceEmptyRequestVoidExceptionThrownTest() { - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenThrow(RuntimeException.class); - Mono result = adapter.invokeService("appId", "method", HttpExtension.NONE, (Map)null); + doAnswer((Answer) invocation -> { + throw new RuntimeException(); + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + + Mono result = client.invokeMethod("appId", "method", HttpExtension.NONE, (Map)null); assertThrowsDaprException( RuntimeException.class, @@ -391,14 +441,14 @@ public void invokeServiceEmptyRequestVoidExceptionThrownTest() { @Test 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.InvokeServiceRequest.class))) - .thenReturn(settableFuture); - Mono result = adapter.invokeService("appId", "method", "request", HttpExtension.NONE); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onError(ex); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + + Mono result = client.invokeMethod("appId", "method", "request", HttpExtension.NONE); assertThrowsDaprException( ExecutionException.class, @@ -408,41 +458,39 @@ public void invokeServiceVoidCallbackExceptionThrownTest() { } @Test - public void invokeServiceVoidTest() throws Exception { - SettableFuture settableFuture = SettableFuture.create(); + public void invokeServiceVoidTest() { + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(CommonProtos.InvokeResponse.newBuilder().setData(getAny("Value")).build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); - MockCallback callback = new MockCallback<>(CommonProtos.InvokeResponse.newBuilder() - .setData(getAny("Value")).build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenReturn(settableFuture); - Mono result = adapter.invokeService("appId", "method", "request", HttpExtension.NONE); - settableFuture.set(CommonProtos.InvokeResponse.newBuilder().setData(getAny("Value")).build()); + Mono result = client.invokeMethod("appId", "method", "request", HttpExtension.NONE); result.block(); - assertTrue(callback.wasCalled); } @Test - public void invokeServiceVoidObjectTest() throws Exception { - SettableFuture settableFuture = SettableFuture.create(); + public void invokeServiceVoidObjectTest() { + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(CommonProtos.InvokeResponse.newBuilder().setData(getAny("Value")).build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); - MockCallback callback = new MockCallback<>(CommonProtos.InvokeResponse.newBuilder() - .setData(getAny("Value")).build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenReturn(settableFuture); MyObject request = new MyObject(1, "Event"); - Mono result = adapter.invokeService("appId", "method", request, HttpExtension.NONE); - settableFuture.set(CommonProtos.InvokeResponse.newBuilder().setData(getAny("Value")).build()); + Mono result = client.invokeMethod("appId", "method", request, HttpExtension.NONE); result.block(); - assertTrue(callback.wasCalled); } @Test public void invokeServiceExceptionThrownTest() { - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenThrow(RuntimeException.class); - Mono result = adapter.invokeService("appId", "method", "request", HttpExtension.NONE, null, String.class); + doAnswer((Answer) invocation -> { + throw new RuntimeException(); + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + + Mono result = client.invokeMethod("appId", "method", "request", HttpExtension.NONE, null, String.class); assertThrowsDaprException( RuntimeException.class, @@ -453,9 +501,11 @@ public void invokeServiceExceptionThrownTest() { @Test public void invokeServiceNoRequestClassExceptionThrownTest() { - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenThrow(RuntimeException.class); - Mono result = adapter.invokeService("appId", "method", HttpExtension.NONE, (Map)null, String.class); + doAnswer((Answer) invocation -> { + throw new RuntimeException(); + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + + Mono result = client.invokeMethod("appId", "method", HttpExtension.NONE, (Map)null, String.class); assertThrowsDaprException( RuntimeException.class, @@ -466,9 +516,11 @@ public void invokeServiceNoRequestClassExceptionThrownTest() { @Test public void invokeServiceNoRequestTypeRefExceptionThrownTest() { - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenThrow(RuntimeException.class); - Mono result = adapter.invokeService("appId", "method", HttpExtension.NONE, (Map)null, TypeRef.STRING); + doAnswer((Answer) invocation -> { + throw new RuntimeException(); + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + + Mono result = client.invokeMethod("appId", "method", HttpExtension.NONE, (Map)null, TypeRef.STRING); assertThrowsDaprException( RuntimeException.class, @@ -479,14 +531,14 @@ public void invokeServiceNoRequestTypeRefExceptionThrownTest() { @Test 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.InvokeServiceRequest.class))) - .thenReturn(settableFuture); - Mono result = adapter.invokeService("appId", "method", "request", HttpExtension.NONE, null, String.class); - settableFuture.setException(ex); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onError(ex); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + + Mono result = client.invokeMethod("appId", "method", "request", HttpExtension.NONE, null, String.class); assertThrowsDaprException( ExecutionException.class, @@ -497,9 +549,8 @@ public void invokeServiceCallbackExceptionThrownTest() { @Test public void invokeServiceWithHttpExtensionTest() throws IOException { - HttpExtension httpExtension = new HttpExtension(DaprHttp.HttpMethods.GET, new HashMap() {{ - put("test", "1"); - }}); + HttpExtension httpExtension = new HttpExtension( + DaprHttp.HttpMethods.GET, Collections.singletonMap("test", "1"), null); CommonProtos.InvokeRequest message = CommonProtos.InvokeRequest.newBuilder() .setMethod("method") .setData(getAny("request")) @@ -513,54 +564,59 @@ public void invokeServiceWithHttpExtensionTest() throws IOException { .setMessage(message) .build(); String expected = "Value"; - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(CommonProtos.InvokeResponse.newBuilder() - .setData(getAny(expected)).build()); - addCallback(settableFuture, callback, directExecutor()); - settableFuture.set(CommonProtos.InvokeResponse.newBuilder().setData(getAny(expected)).build()); - when(client.invokeService(eq(request))) - .thenReturn(settableFuture); - Mono result = adapter.invokeService("appId", "method", "request", httpExtension, null, String.class); + + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(CommonProtos.InvokeResponse.newBuilder().setData(getAny(expected)).build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeService(eq(request), any()); + + Mono result = client.invokeMethod("appId", "method", "request", httpExtension, null, String.class); String strOutput = result.block(); assertEquals(expected, strOutput); } @Test - public void invokeServiceTest() throws Exception { + public void invokeServiceTest() { String expected = "Value"; - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(CommonProtos.InvokeResponse.newBuilder() - .setData(getAny(expected)).build()); - addCallback(settableFuture, callback, directExecutor()); - settableFuture.set(CommonProtos.InvokeResponse.newBuilder().setData(getAny(expected)).build()); - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenReturn(settableFuture); - Mono result = adapter.invokeService("appId", "method", "request", HttpExtension.NONE, null, String.class); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(CommonProtos.InvokeResponse.newBuilder().setData(getAny(expected)).build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + + Mono result = client.invokeMethod("appId", "method", "request", HttpExtension.NONE, null, String.class); String strOutput = result.block(); + assertEquals(expected, strOutput); } @Test public void invokeServiceObjectTest() throws Exception { MyObject object = new MyObject(1, "Value"); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(CommonProtos.InvokeResponse.newBuilder() - .setData(getAny(object)).build()); - addCallback(settableFuture, callback, directExecutor()); - settableFuture.set(CommonProtos.InvokeResponse.newBuilder().setData(getAny(object)).build()); - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenReturn(settableFuture); - Mono result = adapter.invokeService("appId", "method", "request", HttpExtension.NONE, null, MyObject.class); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(CommonProtos.InvokeResponse.newBuilder().setData(getAny(object)).build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + + Mono result = client.invokeMethod("appId", "method", "request", HttpExtension.NONE, null, MyObject.class); MyObject resultObject = result.block(); + assertEquals(object.id, resultObject.id); assertEquals(object.value, resultObject.value); } @Test public void invokeServiceNoRequestBodyExceptionThrownTest() { - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenThrow(RuntimeException.class); - Mono result = adapter.invokeService("appId", "method", (Object)null, HttpExtension.NONE, String.class); + doAnswer((Answer) invocation -> { + throw new RuntimeException(); + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + + Mono result = client.invokeMethod("appId", "method", (Object)null, HttpExtension.NONE, String.class); assertThrowsDaprException( RuntimeException.class, @@ -571,14 +627,14 @@ public void invokeServiceNoRequestBodyExceptionThrownTest() { @Test 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.InvokeServiceRequest.class))) - .thenReturn(settableFuture); - Mono result = adapter.invokeService("appId", "method", (Object)null, HttpExtension.NONE, String.class); - settableFuture.setException(ex); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onError(ex); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + + Mono result = client.invokeMethod("appId", "method", (Object)null, HttpExtension.NONE, String.class); assertThrowsDaprException( ExecutionException.class, @@ -590,43 +646,45 @@ public void invokeServiceNoRequestCallbackExceptionThrownTest() { @Test public void invokeServiceNoRequestBodyTest() throws Exception { String expected = "Value"; - SettableFuture settableFuture = SettableFuture.create(); - - MockCallback callback = new MockCallback<>(CommonProtos.InvokeResponse.newBuilder() - .setData(getAny(expected)).build()); - addCallback(settableFuture, callback, directExecutor()); - settableFuture.set(CommonProtos.InvokeResponse.newBuilder().setData(getAny(expected)).build()); - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenReturn(settableFuture); - Mono result = adapter.invokeService("appId", "method", (Object)null, HttpExtension.NONE, String.class); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(CommonProtos.InvokeResponse.newBuilder().setData(getAny(expected)).build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + + Mono result = client.invokeMethod("appId", "method", (Object)null, HttpExtension.NONE, String.class); String strOutput = result.block(); + assertEquals(expected, strOutput); } @Test public void invokeServiceNoRequestBodyObjectTest() throws Exception { MyObject object = new MyObject(1, "Value"); - SettableFuture settableFuture = SettableFuture.create(); - - MockCallback callback = new MockCallback<>(CommonProtos.InvokeResponse.newBuilder() - .setData(getAny(object)).build()); - addCallback(settableFuture, callback, directExecutor()); - settableFuture.set(CommonProtos.InvokeResponse.newBuilder().setData(getAny(object)).build()); - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenReturn(settableFuture); - Mono result = adapter.invokeService("appId", "method", (Object)null, HttpExtension.NONE, MyObject.class); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(CommonProtos.InvokeResponse.newBuilder().setData(getAny(object)).build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + + Mono result = client.invokeMethod("appId", "method", (Object)null, HttpExtension.NONE, MyObject.class); MyObject resultObject = result.block(); + assertEquals(object.id, resultObject.id); assertEquals(object.value, resultObject.value); } @Test public void invokeServiceByteRequestExceptionThrownTest() throws IOException { - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenThrow(RuntimeException.class); + doAnswer((Answer) invocation -> { + throw new RuntimeException(); + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); String request = "Request"; byte[] byteRequest = serializer.serialize(request); - Mono result = adapter.invokeService("appId", "method", byteRequest, HttpExtension.NONE, byte[].class); + + Mono result = client.invokeMethod("appId", "method", byteRequest, HttpExtension.NONE, byte[].class); assertThrowsDaprException( RuntimeException.class, @@ -637,17 +695,17 @@ public void invokeServiceByteRequestExceptionThrownTest() throws IOException { @Test 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.InvokeServiceRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onError(ex); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); String request = "Request"; byte[] byteRequest = serializer.serialize(request); + Mono result = - adapter.invokeService("appId", "method", byteRequest, HttpExtension.NONE,(HashMap) null); - settableFuture.setException(ex); + client.invokeMethod("appId", "method", byteRequest, HttpExtension.NONE,(HashMap) null); assertThrowsDaprException( ExecutionException.class, @@ -659,18 +717,19 @@ public void invokeServiceByteRequestCallbackExceptionThrownTest() throws IOExcep @Test public void invokeByteRequestServiceTest() throws Exception { String expected = "Value"; - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(CommonProtos.InvokeResponse.newBuilder() - .setData(getAny(expected)).build()); - addCallback(settableFuture, callback, directExecutor()); - settableFuture.set(CommonProtos.InvokeResponse.newBuilder().setData(getAny(expected)).build()); - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(CommonProtos.InvokeResponse.newBuilder().setData(getAny(expected)).build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); String request = "Request"; byte[] byteRequest = serializer.serialize(request); - Mono result = adapter.invokeService( + + Mono result = client.invokeMethod( "appId", "method", byteRequest, HttpExtension.NONE, (HashMap) null); byte[] byteOutput = result.block(); + String strOutput = serializer.deserialize(byteOutput, String.class); assertEquals(expected, strOutput); } @@ -678,25 +737,27 @@ public void invokeByteRequestServiceTest() throws Exception { @Test public void invokeServiceByteRequestObjectTest() throws Exception { MyObject resultObj = new MyObject(1, "Value"); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(CommonProtos.InvokeResponse.newBuilder() - .setData(getAny(resultObj)).build()); - addCallback(settableFuture, callback, directExecutor()); - settableFuture.set(CommonProtos.InvokeResponse.newBuilder().setData(getAny(resultObj)).build()); - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(CommonProtos.InvokeResponse.newBuilder().setData(getAny(resultObj)).build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + String request = "Request"; byte[] byteRequest = serializer.serialize(request); - Mono result = adapter.invokeService("appId", "method", byteRequest, HttpExtension.NONE, byte[].class); + Mono result = client.invokeMethod("appId", "method", byteRequest, HttpExtension.NONE, byte[].class); byte[] byteOutput = result.block(); + assertEquals(resultObj, serializer.deserialize(byteOutput, MyObject.class)); } @Test public void invokeServiceNoRequestNoClassBodyExceptionThrownTest() { - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenThrow(RuntimeException.class); - Mono result = adapter.invokeService("appId", "method", (Object)null, HttpExtension.NONE); + doAnswer((Answer) invocation -> { + throw new RuntimeException(); + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + Mono result = client.invokeMethod("appId", "method", (Object)null, HttpExtension.NONE); assertThrowsDaprException( RuntimeException.class, @@ -707,14 +768,14 @@ public void invokeServiceNoRequestNoClassBodyExceptionThrownTest() { @Test 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.InvokeServiceRequest.class))) - .thenReturn(settableFuture); - Mono result = adapter.invokeService("appId", "method", (Object)null, HttpExtension.NONE); - settableFuture.setException(ex); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onError(ex); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + + Mono result = client.invokeMethod("appId", "method", (Object)null, HttpExtension.NONE); assertThrowsDaprException( ExecutionException.class, @@ -724,79 +785,78 @@ public void invokeServiceNoRequestNoClassCallbackExceptionThrownTest() { } @Test - public void invokeServiceNoRequestNoClassBodyTest() throws Exception { + public void invokeServiceNoRequestNoClassBodyTest() { String expected = "Value"; - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(CommonProtos.InvokeResponse.newBuilder() - .setData(getAny(expected)).build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenReturn(settableFuture); - Mono result = adapter.invokeService("appId", "method", (Object)null, HttpExtension.NONE); - settableFuture.set(CommonProtos.InvokeResponse.newBuilder().setData(getAny(expected)).build()); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(CommonProtos.InvokeResponse.newBuilder().setData(getAny(expected)).build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + + Mono result = client.invokeMethod("appId", "method", (Object)null, HttpExtension.NONE); result.block(); - assertTrue(callback.wasCalled); } @Test - public void invokeServiceNoRequestNoHotMono() throws Exception { + public void invokeServiceNoRequestNoHotMono() { + AtomicBoolean called = new AtomicBoolean(false); String expected = "Value"; - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(CommonProtos.InvokeResponse.newBuilder() - .setData(getAny(expected)).build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenAnswer(c -> { - settableFuture.set(CommonProtos.InvokeResponse.newBuilder().setData(getAny(expected)).build()); - return settableFuture; - }); - adapter.invokeService("appId", "method", (Object)null, HttpExtension.NONE); + doAnswer((Answer) invocation -> { + called.set(true); + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(CommonProtos.InvokeResponse.newBuilder().setData(getAny(expected)).build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + client.invokeMethod("appId", "method", (Object)null, HttpExtension.NONE); // Do not call block() on mono above, so nothing should happen. - assertFalse(callback.wasCalled); + assertFalse(called.get()); } @Test public void invokeServiceNoRequestNoClassBodyObjectTest() throws Exception { MyObject resultObj = new MyObject(1, "Value"); - SettableFuture settableFuture = SettableFuture.create(); - - MockCallback callback = new MockCallback<>(CommonProtos.InvokeResponse.newBuilder() - .setData(getAny(resultObj)).build()); - addCallback(settableFuture, callback, directExecutor()); - settableFuture.set(CommonProtos.InvokeResponse.newBuilder().setData(getAny(resultObj)).build()); - when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class))) - .thenReturn(settableFuture); - Mono result = adapter.invokeService("appId", "method", (Object)null, HttpExtension.NONE); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(CommonProtos.InvokeResponse.newBuilder().setData(getAny(resultObj)).build()); + observer.onCompleted(); + return null; + }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); + + Mono result = client.invokeMethod("appId", "method", (Object)null, HttpExtension.NONE); result.block(); - assertTrue(callback.wasCalled); } @Test public void getStateIllegalArgumentExceptionTest() { State key = buildStateKey(null, "Key1", "ETag1", null); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // empty state store name - adapter.getState("", key, String.class).block(); + client.getState("", key, String.class).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // null state store name - adapter.getState(null, key, String.class).block(); + client.getState(null, key, String.class).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // null key - adapter.getState(STATE_STORE_NAME, (String)null, String.class).block(); + client.getState(STATE_STORE_NAME, (String)null, String.class).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // empty key - adapter.getState(STATE_STORE_NAME, "", String.class).block(); + client.getState(STATE_STORE_NAME, "", String.class).block(); }); } @Test public void getStateExceptionThrownTest() { - when(client.getState(any(io.dapr.v1.DaprProtos.GetStateRequest.class))).thenThrow(RuntimeException.class); + doAnswer((Answer) invocation -> { + throw new RuntimeException(); + }).when(daprStub).getState(any(DaprProtos.GetStateRequest.class), any()); + State key = buildStateKey(null, "Key1", "ETag1", null); - Mono> result = adapter.getState(STATE_STORE_NAME, key, String.class); + Mono> result = client.getState(STATE_STORE_NAME, key, String.class); assertThrowsDaprException( RuntimeException.class, @@ -807,16 +867,15 @@ public void getStateExceptionThrownTest() { @Test 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.v1.DaprProtos.GetStateRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onError(ex); + return null; + }).when(daprStub).getState(any(DaprProtos.GetStateRequest.class), any()); + State key = buildStateKey(null, "Key1", "ETag1", null); - Mono> result = adapter.getState(STATE_STORE_NAME, key, String.class); - settableFuture.setException(ex); + Mono> result = client.getState(STATE_STORE_NAME, key, String.class); assertThrowsDaprException( ExecutionException.class, @@ -832,38 +891,40 @@ public void getStateStringValueNoOptionsTest() throws IOException { String expectedValue = "Expected state"; State expectedState = buildStateKey(expectedValue, key, etag, new HashMap<>(), null); DaprProtos.GetStateResponse responseEnvelope = buildGetStateResponse(expectedValue, etag); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(responseEnvelope); - addCallback(settableFuture, callback, directExecutor()); - when(client.getState(any(io.dapr.v1.DaprProtos.GetStateRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).getState(any(DaprProtos.GetStateRequest.class), any()); + State keyRequest = buildStateKey(null, key, etag, null); - Mono> result = adapter.getState(STATE_STORE_NAME, keyRequest, String.class); - settableFuture.set(responseEnvelope); + Mono> result = client.getState(STATE_STORE_NAME, keyRequest, String.class); State res = result.block(); + assertNotNull(res); assertEquals(expectedState, res); } @Test public void getStateStringValueNoHotMono() throws IOException { + AtomicBoolean called = new AtomicBoolean(false); String etag = "ETag1"; String key = "key1"; String expectedValue = "Expected state"; - State expectedState = buildStateKey(expectedValue, key, etag, null); DaprProtos.GetStateResponse responseEnvelope = buildGetStateResponse(expectedValue, etag); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(responseEnvelope); - addCallback(settableFuture, callback, directExecutor()); - when(client.getState(any(io.dapr.v1.DaprProtos.GetStateRequest.class))) - .thenAnswer(c -> { - settableFuture.set(responseEnvelope); - return settableFuture; - }); + doAnswer((Answer) invocation -> { + called.set(true); + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).getState(any(DaprProtos.GetStateRequest.class), any()); + State keyRequest = buildStateKey(null, key, etag, null); - adapter.getState(STATE_STORE_NAME, keyRequest, String.class); + client.getState(STATE_STORE_NAME, keyRequest, String.class); // block() on the mono above is not called, so nothing should happen. - assertFalse(callback.wasCalled); + assertFalse(called.get()); } @Test @@ -878,14 +939,16 @@ public void getStateObjectValueWithOptionsTest() throws IOException { .setEtag(etag) .build(); State keyRequest = buildStateKey(null, key, etag, new HashMap<>(), options); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(responseEnvelope); - addCallback(settableFuture, callback, directExecutor()); - when(client.getState(any(io.dapr.v1.DaprProtos.GetStateRequest.class))) - .thenReturn(settableFuture); - Mono> result = adapter.getState(STATE_STORE_NAME, keyRequest, MyObject.class); - settableFuture.set(responseEnvelope); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).getState(any(DaprProtos.GetStateRequest.class), any()); + + Mono> result = client.getState(STATE_STORE_NAME, keyRequest, MyObject.class); State res = result.block(); + assertNotNull(res); assertEquals(expectedState, res); } @@ -904,15 +967,16 @@ public void getStateObjectValueWithMetadataTest() throws IOException { .setEtag(etag) .build(); GetStateRequestBuilder builder = new GetStateRequestBuilder(STATE_STORE_NAME, key); - builder.withMetadata(metadata).withEtag(etag).withStateOptions(options); + builder.withMetadata(metadata).withStateOptions(options); GetStateRequest request = builder.build(); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(responseEnvelope); - addCallback(settableFuture, callback, directExecutor()); - when(client.getState(any(io.dapr.v1.DaprProtos.GetStateRequest.class))) - .thenReturn(settableFuture); - Mono>> result = adapter.getState(request, TypeRef.get(MyObject.class)); - settableFuture.set(responseEnvelope); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).getState(any(DaprProtos.GetStateRequest.class), any()); + + Mono>> result = client.getState(request, TypeRef.get(MyObject.class)); Response> res = result.block(); assertNotNull(res); assertEquals(expectedState, res.getObject()); @@ -930,49 +994,56 @@ public void getStateObjectValueWithOptionsNoConcurrencyTest() throws IOException .setEtag(etag) .build(); State keyRequest = buildStateKey(null, key, etag, new HashMap<>(), options); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(responseEnvelope); - addCallback(settableFuture, callback, directExecutor()); - when(client.getState(any(io.dapr.v1.DaprProtos.GetStateRequest.class))) - .thenReturn(settableFuture); - Mono> result = adapter.getState(STATE_STORE_NAME, keyRequest, MyObject.class); - settableFuture.set(responseEnvelope); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).getState(any(DaprProtos.GetStateRequest.class), any()); + + Mono> result = client.getState(STATE_STORE_NAME, keyRequest, MyObject.class); + assertEquals(expectedState, result.block()); } @Test public void getStatesIllegalArgumentExceptionTest() { State key = buildStateKey(null, "Key1", "ETag1", null); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // empty state store name - adapter.getStates("", Collections.singletonList("100"), String.class).block(); + client.getBulkState("", Collections.singletonList("100"), String.class).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // null state store name - adapter.getStates(null, Collections.singletonList("100"), String.class).block(); + client.getBulkState(null, Collections.singletonList("100"), String.class).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // null key // null pointer exception due to keys being converted to an unmodifiable list - adapter.getStates(STATE_STORE_NAME, null, String.class).block(); + client.getBulkState(STATE_STORE_NAME, null, String.class).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // empty key list - adapter.getStates(STATE_STORE_NAME, Collections.emptyList(), String.class).block(); + client.getBulkState(STATE_STORE_NAME, Collections.emptyList(), String.class).block(); }); // negative parallelism - GetStatesRequest req = new GetStatesRequestBuilder(STATE_STORE_NAME, Collections.singletonList("100")) + GetBulkStateRequest req = new GetBulkStateRequestBuilder(STATE_STORE_NAME, Collections.singletonList("100")) + .withMetadata(new HashMap<>()) .withParallelism(-1) .build(); - assertThrowsDaprException(IllegalArgumentException.class, () -> adapter.getStates(req, TypeRef.BOOLEAN).block()); + assertThrows(IllegalArgumentException.class, () -> client.getBulkState(req, TypeRef.BOOLEAN).block()); } @Test public void getStatesString() throws IOException { + Map metadata = new HashMap<>(); + metadata.put("meta1", "value1"); + metadata.put("meta2", "value2"); DaprProtos.GetBulkStateResponse responseEnvelope = DaprProtos.GetBulkStateResponse.newBuilder() .addItems(DaprProtos.BulkStateItem.newBuilder() .setData(serialize("hello world")) .setKey("100") + .putAllMetadata(metadata) .setEtag("1") .build()) .addItems(DaprProtos.BulkStateItem.newBuilder() @@ -980,20 +1051,19 @@ public void getStatesString() throws IOException { .setError("not found") .build()) .build(); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(responseEnvelope); - addCallback(settableFuture, callback, directExecutor()); - when(client.getBulkState(any(DaprProtos.GetBulkStateRequest.class))) - .thenAnswer(c -> { - settableFuture.set(responseEnvelope); - return settableFuture; - }); - List> result = adapter.getStates(STATE_STORE_NAME, Arrays.asList("100", "200"), String.class).block(); - assertTrue(callback.wasCalled); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).getBulkState(any(DaprProtos.GetBulkStateRequest.class), any()); + + List> result = client.getBulkState(STATE_STORE_NAME, Arrays.asList("100", "200"), String.class).block(); assertEquals(2, result.size()); assertEquals("100", result.stream().findFirst().get().getKey()); assertEquals("hello world", result.stream().findFirst().get().getValue()); + assertEquals(metadata, result.stream().findFirst().get().getMetadata()); assertEquals("1", result.stream().findFirst().get().getEtag()); assertNull(result.stream().findFirst().get().getError()); assertEquals("200", result.stream().skip(1).findFirst().get().getKey()); @@ -1004,10 +1074,13 @@ public void getStatesString() throws IOException { @Test public void getStatesInteger() throws IOException { + Map metadata = new HashMap<>(); + metadata.put("meta1", "value1"); DaprProtos.GetBulkStateResponse responseEnvelope = DaprProtos.GetBulkStateResponse.newBuilder() .addItems(DaprProtos.BulkStateItem.newBuilder() .setData(serialize(1234)) .setKey("100") + .putAllMetadata(metadata) .setEtag("1") .build()) .addItems(DaprProtos.BulkStateItem.newBuilder() @@ -1015,20 +1088,18 @@ public void getStatesInteger() throws IOException { .setError("not found") .build()) .build(); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(responseEnvelope); - addCallback(settableFuture, callback, directExecutor()); - when(client.getBulkState(any(DaprProtos.GetBulkStateRequest.class))) - .thenAnswer(c -> { - settableFuture.set(responseEnvelope); - return settableFuture; - }); - List> result = adapter.getStates(STATE_STORE_NAME, Arrays.asList("100", "200"), int.class).block(); - assertTrue(callback.wasCalled); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).getBulkState(any(DaprProtos.GetBulkStateRequest.class), any()); + List> result = client.getBulkState(STATE_STORE_NAME, Arrays.asList("100", "200"), int.class).block(); assertEquals(2, result.size()); assertEquals("100", result.stream().findFirst().get().getKey()); assertEquals(1234, (int)result.stream().findFirst().get().getValue()); + assertEquals(metadata, result.stream().findFirst().get().getMetadata()); assertEquals("1", result.stream().findFirst().get().getEtag()); assertNull(result.stream().findFirst().get().getError()); assertEquals("200", result.stream().skip(1).findFirst().get().getKey()); @@ -1039,10 +1110,13 @@ public void getStatesInteger() throws IOException { @Test public void getStatesBoolean() throws IOException { + Map metadata = new HashMap<>(); + metadata.put("meta1", "value1"); DaprProtos.GetBulkStateResponse responseEnvelope = DaprProtos.GetBulkStateResponse.newBuilder() .addItems(DaprProtos.BulkStateItem.newBuilder() .setData(serialize(true)) .setKey("100") + .putAllMetadata(metadata) .setEtag("1") .build()) .addItems(DaprProtos.BulkStateItem.newBuilder() @@ -1050,20 +1124,19 @@ public void getStatesBoolean() throws IOException { .setError("not found") .build()) .build(); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(responseEnvelope); - addCallback(settableFuture, callback, directExecutor()); - when(client.getBulkState(any(DaprProtos.GetBulkStateRequest.class))) - .thenAnswer(c -> { - settableFuture.set(responseEnvelope); - return settableFuture; - }); - List> result = adapter.getStates(STATE_STORE_NAME, Arrays.asList("100", "200"), boolean.class).block(); - assertTrue(callback.wasCalled); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).getBulkState(any(DaprProtos.GetBulkStateRequest.class), any()); + + List> result = client.getBulkState(STATE_STORE_NAME, Arrays.asList("100", "200"), boolean.class).block(); assertEquals(2, result.size()); assertEquals("100", result.stream().findFirst().get().getKey()); assertEquals(true, result.stream().findFirst().get().getValue()); + assertEquals(metadata, result.stream().findFirst().get().getMetadata()); assertEquals("1", result.stream().findFirst().get().getEtag()); assertNull(result.stream().findFirst().get().getError()); assertEquals("200", result.stream().skip(1).findFirst().get().getKey()); @@ -1074,10 +1147,12 @@ public void getStatesBoolean() throws IOException { @Test public void getStatesByteArray() throws IOException { + Map metadata = new HashMap<>(); DaprProtos.GetBulkStateResponse responseEnvelope = DaprProtos.GetBulkStateResponse.newBuilder() .addItems(DaprProtos.BulkStateItem.newBuilder() .setData(serialize(new byte[]{1, 2, 3})) .setKey("100") + .putAllMetadata(metadata) .setEtag("1") .build()) .addItems(DaprProtos.BulkStateItem.newBuilder() @@ -1085,20 +1160,19 @@ public void getStatesByteArray() throws IOException { .setError("not found") .build()) .build(); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(responseEnvelope); - addCallback(settableFuture, callback, directExecutor()); - when(client.getBulkState(any(DaprProtos.GetBulkStateRequest.class))) - .thenAnswer(c -> { - settableFuture.set(responseEnvelope); - return settableFuture; - }); - List> result = adapter.getStates(STATE_STORE_NAME, Arrays.asList("100", "200"), byte[].class).block(); - assertTrue(callback.wasCalled); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).getBulkState(any(DaprProtos.GetBulkStateRequest.class), any()); + + List> result = client.getBulkState(STATE_STORE_NAME, Arrays.asList("100", "200"), byte[].class).block(); assertEquals(2, result.size()); assertEquals("100", result.stream().findFirst().get().getKey()); assertArrayEquals(new byte[]{1, 2, 3}, result.stream().findFirst().get().getValue()); + assertEquals(0, result.stream().findFirst().get().getMetadata().size()); assertEquals("1", result.stream().findFirst().get().getEtag()); assertNull(result.stream().findFirst().get().getError()); assertEquals("200", result.stream().skip(1).findFirst().get().getKey()); @@ -1121,20 +1195,19 @@ public void getStatesObject() throws IOException { .setError("not found") .build()) .build(); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(responseEnvelope); - addCallback(settableFuture, callback, directExecutor()); - when(client.getBulkState(any(DaprProtos.GetBulkStateRequest.class))) - .thenAnswer(c -> { - settableFuture.set(responseEnvelope); - return settableFuture; - }); - List> result = adapter.getStates(STATE_STORE_NAME, Arrays.asList("100", "200"), MyObject.class).block(); - assertTrue(callback.wasCalled); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).getBulkState(any(DaprProtos.GetBulkStateRequest.class), any()); + + List> result = client.getBulkState(STATE_STORE_NAME, Arrays.asList("100", "200"), MyObject.class).block(); assertEquals(2, result.size()); assertEquals("100", result.stream().findFirst().get().getKey()); assertEquals(object, result.stream().findFirst().get().getValue()); + assertEquals(0, result.stream().findFirst().get().getMetadata().size()); assertEquals("1", result.stream().findFirst().get().getEtag()); assertNull(result.stream().findFirst().get().getError()); assertEquals("200", result.stream().skip(1).findFirst().get().getKey()); @@ -1145,9 +1218,12 @@ public void getStatesObject() throws IOException { @Test public void deleteStateExceptionThrowTest() { - when(client.deleteState(any(io.dapr.v1.DaprProtos.DeleteStateRequest.class))).thenThrow(RuntimeException.class); + doAnswer((Answer) invocation -> { + throw new RuntimeException(); + }).when(daprStub).deleteState(any(DaprProtos.DeleteStateRequest.class), any()); + State key = buildStateKey(null, "Key1", "ETag1", null); - Mono result = adapter.deleteState(STATE_STORE_NAME, key.getKey(), key.getEtag(), key.getOptions()); + Mono result = client.deleteState(STATE_STORE_NAME, key.getKey(), key.getEtag(), key.getOptions()); assertThrowsDaprException( RuntimeException.class, @@ -1159,35 +1235,35 @@ public void deleteStateExceptionThrowTest() { @Test public void deleteStateIllegalArgumentExceptionTest() { State key = buildStateKey(null, "Key1", "ETag1", null); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // empty state store name - adapter.deleteState("", key.getKey(), "etag", null).block(); + client.deleteState("", key.getKey(), "etag", null).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // null state store name - adapter.deleteState(null, key.getKey(), "etag", null).block(); + client.deleteState(null, key.getKey(), "etag", null).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // null state store name - adapter.deleteState(STATE_STORE_NAME, null, "etag", null).block(); + client.deleteState(STATE_STORE_NAME, null, "etag", null).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // null state store name - adapter.deleteState(STATE_STORE_NAME, "", "etag", null).block(); + client.deleteState(STATE_STORE_NAME, "", "etag", null).block(); }); } @Test public void deleteStateCallbackExcpetionThrownTest() { - SettableFuture settableFuture = SettableFuture.create(); RuntimeException ex = new RuntimeException("An Exception"); - MockCallback callback = new MockCallback<>(ex); - addCallback(settableFuture, callback, directExecutor()); - when(client.deleteState(any(io.dapr.v1.DaprProtos.DeleteStateRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onError(ex); + return null; + }).when(daprStub).deleteState(any(DaprProtos.DeleteStateRequest.class), any()); + State key = buildStateKey(null, "Key1", "ETag1", null); - Mono result = adapter.deleteState(STATE_STORE_NAME, key.getKey(), key.getEtag(), key.getOptions()); - settableFuture.setException(ex); + Mono result = client.deleteState(STATE_STORE_NAME, key.getKey(), key.getEtag(), key.getOptions()); assertThrowsDaprException( ExecutionException.class, @@ -1200,17 +1276,17 @@ public void deleteStateCallbackExcpetionThrownTest() { public void deleteStateNoOptionsTest() { String etag = "ETag1"; String key = "key1"; - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.deleteState(any(io.dapr.v1.DaprProtos.DeleteStateRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).deleteState(any(DaprProtos.DeleteStateRequest.class), any()); + State stateKey = buildStateKey(null, key, etag, null); - Mono result = adapter.deleteState(STATE_STORE_NAME, stateKey.getKey(), stateKey.getEtag(), + Mono result = client.deleteState(STATE_STORE_NAME, stateKey.getKey(), stateKey.getEtag(), stateKey.getOptions()); - settableFuture.set(Empty.newBuilder().build()); result.block(); - assertTrue(callback.wasCalled); } @Test @@ -1218,17 +1294,17 @@ public void deleteStateTest() { String etag = "ETag1"; String key = "key1"; StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, StateOptions.Concurrency.FIRST_WRITE); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.deleteState(any(io.dapr.v1.DaprProtos.DeleteStateRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).deleteState(any(DaprProtos.DeleteStateRequest.class), any()); + State stateKey = buildStateKey(null, key, etag, options); - Mono result = adapter.deleteState(STATE_STORE_NAME, stateKey.getKey(), stateKey.getEtag(), + Mono result = client.deleteState(STATE_STORE_NAME, stateKey.getKey(), stateKey.getEtag(), stateKey.getOptions()); - settableFuture.set(Empty.newBuilder().build()); result.block(); - assertTrue(callback.wasCalled); } @Test @@ -1238,38 +1314,39 @@ public void deleteStateWithMetadata() { StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, StateOptions.Concurrency.FIRST_WRITE); Map metadata = new HashMap<>(); metadata.put("key_1", "val_1"); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.deleteState(any(io.dapr.v1.DaprProtos.DeleteStateRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).deleteState(any(DaprProtos.DeleteStateRequest.class), any()); + DeleteStateRequestBuilder builder = new DeleteStateRequestBuilder(STATE_STORE_NAME, key); builder.withEtag(etag).withStateOptions(options).withMetadata(metadata); DeleteStateRequest request = builder.build(); - Mono> result = adapter.deleteState(request); - settableFuture.set(Empty.newBuilder().build()); + Mono> result = client.deleteState(request); result.block(); - assertTrue(callback.wasCalled); } @Test public void deleteStateTestNoHotMono() { + AtomicBoolean called = new AtomicBoolean(false); String etag = "ETag1"; String key = "key1"; - StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, StateOptions.Concurrency.FIRST_WRITE); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.deleteState(any(io.dapr.v1.DaprProtos.DeleteStateRequest.class))) - .thenAnswer(c -> { - settableFuture.set(Empty.newBuilder().build()); - return settableFuture; - }); + StateOptions options = buildStateOptions(null, StateOptions.Concurrency.FIRST_WRITE); + doAnswer((Answer) invocation -> { + called.set(true); + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).deleteState(any(DaprProtos.DeleteStateRequest.class), any()); + State stateKey = buildStateKey(null, key, etag, options); - Mono result = adapter.deleteState(STATE_STORE_NAME, stateKey.getKey(), stateKey.getEtag(), - stateKey.getOptions()); + client.deleteState(STATE_STORE_NAME, stateKey.getKey(), stateKey.getEtag(), + stateKey.getOptions()); // Do not call result.block(), so nothing should happen. - assertFalse(callback.wasCalled); + assertFalse(called.get()); } @Test @@ -1277,17 +1354,17 @@ public void deleteStateNoConsistencyTest() { String etag = "ETag1"; String key = "key1"; StateOptions options = buildStateOptions(null, StateOptions.Concurrency.FIRST_WRITE); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.deleteState(any(io.dapr.v1.DaprProtos.DeleteStateRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).deleteState(any(DaprProtos.DeleteStateRequest.class), any()); + State stateKey = buildStateKey(null, key, etag, options); - Mono result = adapter.deleteState(STATE_STORE_NAME, stateKey.getKey(), stateKey.getEtag(), + Mono result = client.deleteState(STATE_STORE_NAME, stateKey.getKey(), stateKey.getEtag(), stateKey.getOptions()); - settableFuture.set(Empty.newBuilder().build()); result.block(); - assertTrue(callback.wasCalled); } @Test @@ -1295,17 +1372,17 @@ public void deleteStateNoConcurrencyTest() { String etag = "ETag1"; String key = "key1"; StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, null); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.deleteState(any(io.dapr.v1.DaprProtos.DeleteStateRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).deleteState(any(DaprProtos.DeleteStateRequest.class), any()); + State stateKey = buildStateKey(null, key, etag, options); - Mono result = adapter.deleteState(STATE_STORE_NAME, stateKey.getKey(), stateKey.getEtag(), + Mono result = client.deleteState(STATE_STORE_NAME, stateKey.getKey(), stateKey.getEtag(), stateKey.getOptions()); - settableFuture.set(Empty.newBuilder().build()); result.block(); - assertTrue(callback.wasCalled); } @Test @@ -1314,27 +1391,32 @@ public void executeTransactionIllegalArgumentExceptionTest() { TransactionalStateOperation upsertOperation = new TransactionalStateOperation<>( TransactionalStateOperation.OperationType.UPSERT, key); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // empty state store name - adapter.executeTransaction("", Collections.singletonList(upsertOperation)).block(); + client.executeStateTransaction("", Collections.singletonList(upsertOperation)).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // null state store name - adapter.executeTransaction(null, Collections.singletonList(upsertOperation)).block(); + client.executeStateTransaction(null, Collections.singletonList(upsertOperation)).block(); }); } @Test public void executeTransactionSerializerExceptionTest() throws IOException { DaprObjectSerializer mockSerializer = mock(DaprObjectSerializer.class); - adapter = new DaprClientGrpc(closeable, client, mockSerializer, mockSerializer); + client = new DaprClientGrpc(closeable, daprStub, mockSerializer, mockSerializer); String etag = "ETag1"; String key = "key1"; String data = "my data"; StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, null); - SettableFuture settableFuture = SettableFuture.create(); - when(client.executeStateTransaction(any(DaprProtos.ExecuteStateTransactionRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).executeStateTransaction(any(DaprProtos.ExecuteStateTransactionRequest.class), any()); + + when(mockSerializer.serialize(any())).thenThrow(IOException.class); State stateKey = buildStateKey(data, key, etag, options); TransactionalStateOperation upsertOperation = new TransactionalStateOperation<>( @@ -1343,7 +1425,7 @@ public void executeTransactionSerializerExceptionTest() throws IOException { ExecuteStateTransactionRequest request = new ExecuteStateTransactionRequestBuilder(STATE_STORE_NAME) .withTransactionalStates(upsertOperation) .build(); - Mono> result = adapter.executeTransaction(request); + Mono> result = client.executeStateTransaction(request); assertThrowsDaprException( IOException.class, @@ -1358,11 +1440,13 @@ public void executeTransactionWithMetadataTest() { String key = "key1"; String data = "my data"; StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, null); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.executeStateTransaction(any(DaprProtos.ExecuteStateTransactionRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).executeStateTransaction(any(DaprProtos.ExecuteStateTransactionRequest.class), any()); + State stateKey = buildStateKey(data, key, etag, options); TransactionalStateOperation upsertOperation = new TransactionalStateOperation<>( TransactionalStateOperation.OperationType.UPSERT, @@ -1376,10 +1460,8 @@ public void executeTransactionWithMetadataTest() { .withTransactionalStates(upsertOperation, deleteOperation) .withMetadata(metadata) .build(); - Mono> result = adapter.executeTransaction(request); - settableFuture.set(Empty.newBuilder().build()); + Mono> result = client.executeStateTransaction(request); result.block(); - assertTrue(callback.wasCalled); } @Test @@ -1388,11 +1470,13 @@ public void executeTransactionTest() { String key = "key1"; String data = "my data"; StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, null); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.executeStateTransaction(any(DaprProtos.ExecuteStateTransactionRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).executeStateTransaction(any(DaprProtos.ExecuteStateTransactionRequest.class), any()); + State stateKey = buildStateKey(data, key, etag, options); TransactionalStateOperation upsertOperation = new TransactionalStateOperation<>( TransactionalStateOperation.OperationType.UPSERT, @@ -1401,10 +1485,8 @@ public void executeTransactionTest() { TransactionalStateOperation.OperationType.DELETE, new State<>("testKey") ); - Mono result = adapter.executeTransaction(STATE_STORE_NAME, Arrays.asList(upsertOperation, deleteOperation)); - settableFuture.set(Empty.newBuilder().build()); + Mono result = client.executeStateTransaction(STATE_STORE_NAME, Arrays.asList(upsertOperation, deleteOperation)); result.block(); - assertTrue(callback.wasCalled); } @Test @@ -1413,13 +1495,15 @@ public void executeTransactionExceptionThrownTest() { String key = "key1"; String data = "my data"; StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, null); - when(client.executeStateTransaction(any(DaprProtos.ExecuteStateTransactionRequest.class))) - .thenThrow(RuntimeException.class); + doAnswer((Answer) invocation -> { + throw new RuntimeException(); + }).when(daprStub).executeStateTransaction(any(DaprProtos.ExecuteStateTransactionRequest.class), any()); + State stateKey = buildStateKey(data, key, etag, options); TransactionalStateOperation operation = new TransactionalStateOperation<>( TransactionalStateOperation.OperationType.UPSERT, stateKey); - Mono result = adapter.executeTransaction(STATE_STORE_NAME, Collections.singletonList(operation)); + Mono result = client.executeStateTransaction(STATE_STORE_NAME, Collections.singletonList(operation)); assertThrowsDaprException( RuntimeException.class, @@ -1434,18 +1518,18 @@ public void executeTransactionCallbackExceptionTest() { String key = "key1"; String data = "my data"; StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, null); - SettableFuture settableFuture = SettableFuture.create(); RuntimeException ex = new RuntimeException("ex"); - MockCallback callback = new MockCallback<>(ex); - addCallback(settableFuture, callback, directExecutor()); - when(client.executeStateTransaction(any(DaprProtos.ExecuteStateTransactionRequest.class))) - .thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onError(ex); + return null; + }).when(daprStub).executeStateTransaction(any(DaprProtos.ExecuteStateTransactionRequest.class), any()); + State stateKey = buildStateKey(data, key, etag, options); TransactionalStateOperation operation = new TransactionalStateOperation<>( TransactionalStateOperation.OperationType.UPSERT, stateKey); - Mono result = adapter.executeTransaction(STATE_STORE_NAME, Collections.singletonList(operation)); - settableFuture.setException(ex); + Mono result = client.executeStateTransaction(STATE_STORE_NAME, Collections.singletonList(operation)); assertThrowsDaprException( ExecutionException.class, @@ -1456,23 +1540,49 @@ public void executeTransactionCallbackExceptionTest() { @Test public void saveStatesIllegalArgumentExceptionTest() { - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // empty state store name - adapter.saveStates("", Collections.emptyList()).block(); + client.saveBulkState("", Collections.emptyList()).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // empty state store name - adapter.saveStates(null, Collections.emptyList()).block(); + client.saveBulkState(null, Collections.emptyList()).block(); }); } + @Test + public void saveBulkStateTestNullEtag() { + List> states = new ArrayList>(); + states.add(new State("null_etag_value", "null_etag_key", null, (StateOptions)null)); + states.add(new State("empty_etag_value", "empty_etag_key", "", (StateOptions)null)); + + ArgumentCaptor argument = ArgumentCaptor.forClass(DaprProtos.SaveStateRequest.class); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).saveState(argument.capture(), any()); + + StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, StateOptions.Concurrency.FIRST_WRITE); + Mono result = client.saveBulkState(STATE_STORE_NAME, states); + + result.block(); + assertFalse(argument.getValue().getStates(0).hasEtag()); + assertTrue(argument.getValue().getStates(1).hasEtag()); + assertEquals("", argument.getValue().getStates(1).getEtag().getValue()); + } + @Test public void saveStateExceptionThrownTest() { String key = "key1"; String etag = "ETag1"; String value = "State value"; - when(client.saveState(any(io.dapr.v1.DaprProtos.SaveStateRequest.class))).thenThrow(RuntimeException.class); - Mono result = adapter.saveState(STATE_STORE_NAME, key, etag, value, null); + doAnswer((Answer) invocation -> { + throw new RuntimeException(); + }).when(daprStub).saveState(any(DaprProtos.SaveStateRequest.class), any()); + + Mono result = client.saveState(STATE_STORE_NAME, key, etag, value, null); assertThrowsDaprException( RuntimeException.class, @@ -1486,13 +1596,14 @@ public void saveStateCallbackExceptionThrownTest() { String key = "key1"; String etag = "ETag1"; String value = "State value"; - SettableFuture settableFuture = SettableFuture.create(); RuntimeException ex = new RuntimeException("An Exception"); - MockCallback callback = new MockCallback<>(ex); - addCallback(settableFuture, callback, directExecutor()); - when(client.saveState(any(io.dapr.v1.DaprProtos.SaveStateRequest.class))).thenReturn(settableFuture); - Mono result = adapter.saveState(STATE_STORE_NAME, key, etag, value, null); - settableFuture.setException(ex); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onError(ex); + return null; + }).when(daprStub).saveState(any(DaprProtos.SaveStateRequest.class), any()); + + Mono result = client.saveState(STATE_STORE_NAME, key, etag, value, null); assertThrowsDaprException( ExecutionException.class, @@ -1506,14 +1617,16 @@ public void saveStateNoOptionsTest() { String key = "key1"; String etag = "ETag1"; String value = "State value"; - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.saveState(any(io.dapr.v1.DaprProtos.SaveStateRequest.class))).thenReturn(settableFuture); - Mono result = adapter.saveState(STATE_STORE_NAME, key, etag, value, null); - settableFuture.set(Empty.newBuilder().build()); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).saveState(any(DaprProtos.SaveStateRequest.class), any()); + + + Mono result = client.saveState(STATE_STORE_NAME, key, etag, value, null); result.block(); - assertTrue(callback.wasCalled); } @Test @@ -1521,33 +1634,56 @@ public void saveStateTest() { String key = "key1"; String etag = "ETag1"; String value = "State value"; - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.saveState(any(io.dapr.v1.DaprProtos.SaveStateRequest.class))).thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).saveState(any(DaprProtos.SaveStateRequest.class), any()); + StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, StateOptions.Concurrency.FIRST_WRITE); - Mono result = adapter.saveState(STATE_STORE_NAME, key, etag, value, options); - settableFuture.set(Empty.newBuilder().build()); + Mono result = client.saveState(STATE_STORE_NAME, key, etag, value, options); result.block(); - assertTrue(callback.wasCalled); + } + + @Test + public void saveStateTestNullEtag() { + String key = "key1"; + String etag = null; + String value = "State value"; + ArgumentCaptor argument = ArgumentCaptor.forClass(DaprProtos.SaveStateRequest.class); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).saveState(argument.capture(), any()); + + StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, StateOptions.Concurrency.FIRST_WRITE); + Mono result = client.saveState(STATE_STORE_NAME, key, etag, value, options); + + result.block(); + assertFalse(argument.getValue().getStates(0).hasEtag()); } @Test public void saveStateTestNoHotMono() { + AtomicBoolean called = new AtomicBoolean(false); String key = "key1"; String etag = "ETag1"; String value = "State value"; - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.saveState(any(io.dapr.v1.DaprProtos.SaveStateRequest.class))).thenAnswer(c -> { - settableFuture.set(Empty.newBuilder().build()); - return settableFuture; - }); + doAnswer((Answer) invocation -> { + called.set(true); + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).saveState(any(DaprProtos.SaveStateRequest.class), any()); + StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, StateOptions.Concurrency.FIRST_WRITE); - Mono result = adapter.saveState(STATE_STORE_NAME, key, etag, value, options); + client.saveState(STATE_STORE_NAME, key, etag, value, options); // No call to result.block(), so nothing should happen. - assertFalse(callback.wasCalled); + assertFalse(called.get()); } @Test @@ -1555,15 +1691,16 @@ public void saveStateNoConsistencyTest() { String key = "key1"; String etag = "ETag1"; String value = "State value"; - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.saveState(any(io.dapr.v1.DaprProtos.SaveStateRequest.class))).thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).saveState(any(DaprProtos.SaveStateRequest.class), any()); + StateOptions options = buildStateOptions(null, StateOptions.Concurrency.FIRST_WRITE); - Mono result = adapter.saveState(STATE_STORE_NAME, key, etag, value, options); - settableFuture.set(Empty.newBuilder().build()); + Mono result = client.saveState(STATE_STORE_NAME, key, etag, value, options); result.block(); - assertTrue(callback.wasCalled); } @Test @@ -1571,15 +1708,16 @@ public void saveStateNoConcurrencyTest() { String key = "key1"; String etag = "ETag1"; String value = "State value"; - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.saveState(any(io.dapr.v1.DaprProtos.SaveStateRequest.class))).thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).saveState(any(DaprProtos.SaveStateRequest.class), any()); + StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, null); - Mono result = adapter.saveState(STATE_STORE_NAME, key, etag, value, options); - settableFuture.set(Empty.newBuilder().build()); + Mono result = client.saveState(STATE_STORE_NAME, key, etag, value, options); result.block(); - assertTrue(callback.wasCalled); } @Test @@ -1587,15 +1725,16 @@ public void saveStateNoRetryPolicyTest() { String key = "key1"; String etag = "ETag1"; String value = "State value"; - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.saveState(any(io.dapr.v1.DaprProtos.SaveStateRequest.class))).thenReturn(settableFuture); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).saveState(any(DaprProtos.SaveStateRequest.class), any()); + StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, StateOptions.Concurrency.FIRST_WRITE); - Mono result = adapter.saveState(STATE_STORE_NAME, key, etag, value, options); - settableFuture.set(Empty.newBuilder().build()); + Mono result = client.saveState(STATE_STORE_NAME, key, etag, value, options); result.block(); - assertTrue(callback.wasCalled); } private State buildStateKey(T value, String key, String etag, StateOptions options) { @@ -1635,28 +1774,115 @@ public void getStateThenDelete() throws Exception { String expectedValue2 = "Expected state 2"; State expectedState1 = buildStateKey(expectedValue1, key1, etag, new HashMap<>(), null); State expectedState2 = buildStateKey(expectedValue2, key2, etag, new HashMap<>(), null); - Map> futuresMap = new HashMap<>(); + Map futuresMap = new HashMap<>(); futuresMap.put(key1, buildFutureGetStateEnvelop(expectedValue1, etag)); futuresMap.put(key2, buildFutureGetStateEnvelop(expectedValue2, etag)); - when(client.getState(argThat(new GetStateRequestKeyMatcher(key1)))).thenReturn(futuresMap.get(key1)); - when(client.getState(argThat(new GetStateRequestKeyMatcher(key2)))).thenReturn(futuresMap.get(key2)); + + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(futuresMap.get(key1)); + observer.onCompleted(); + return null; + }).when(daprStub).getState(argThat(new GetStateRequestKeyMatcher(key1)), any()); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(futuresMap.get(key2)); + observer.onCompleted(); + return null; + }).when(daprStub).getState(argThat(new GetStateRequestKeyMatcher(key2)), any()); + State keyRequest1 = buildStateKey(null, key1, etag, null); - Mono> resultGet1 = adapter.getState(STATE_STORE_NAME, keyRequest1, String.class); + Mono> resultGet1 = client.getState(STATE_STORE_NAME, keyRequest1, String.class); assertEquals(expectedState1, resultGet1.block()); State keyRequest2 = buildStateKey(null, key2, etag, null); - Mono> resultGet2 = adapter.getState(STATE_STORE_NAME, keyRequest2, String.class); + Mono> resultGet2 = client.getState(STATE_STORE_NAME, keyRequest2, String.class); assertEquals(expectedState2, resultGet2.block()); - SettableFuture settableFutureDelete = SettableFuture.create(); - MockCallback callbackDelete = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFutureDelete, callbackDelete, directExecutor()); - when(client.deleteState(any(io.dapr.v1.DaprProtos.DeleteStateRequest.class))) - .thenReturn(settableFutureDelete); - Mono resultDelete = adapter.deleteState(STATE_STORE_NAME, keyRequest2.getKey(), keyRequest2.getEtag(), + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).deleteState(any(io.dapr.v1.DaprProtos.DeleteStateRequest.class), any()); + + Mono resultDelete = client.deleteState(STATE_STORE_NAME, keyRequest2.getKey(), keyRequest2.getEtag(), keyRequest2.getOptions()); - settableFutureDelete.set(Empty.newBuilder().build()); resultDelete.block(); - assertTrue(callbackDelete.wasCalled); + } + + @Test + public void deleteStateNullEtag() { + String key = "key1"; + String etag = null; + ArgumentCaptor argument = ArgumentCaptor.forClass(DaprProtos.DeleteStateRequest.class); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).deleteState(argument.capture(), any()); + + StateOptions options = buildStateOptions(StateOptions.Consistency.STRONG, StateOptions.Concurrency.FIRST_WRITE); + Mono result = client.deleteState(STATE_STORE_NAME, key, etag, options); + + result.block(); + assertFalse(argument.getValue().hasEtag()); + } + + @Test + public void getStateNullEtag() throws Exception { + String etag = null; + String key1 = "key1"; + String expectedValue1 = "Expected state 1"; + State expectedState1 = buildStateKey(expectedValue1, key1, etag, new HashMap<>(), null); + Map futuresMap = new HashMap<>(); + DaprProtos.GetStateResponse envelope = DaprProtos.GetStateResponse.newBuilder() + .setData(serialize(expectedValue1)) + .build(); + futuresMap.put(key1, envelope); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(futuresMap.get(key1)); + observer.onCompleted(); + return null; + }).when(daprStub).getState(argThat(new GetStateRequestKeyMatcher(key1)), any()); + + State keyRequest1 = buildStateKey(null, key1, null, null); + Mono> resultGet1 = client.getState(STATE_STORE_NAME, keyRequest1, String.class); + assertEquals(expectedState1, resultGet1.block()); + } + + @Test + public void getBulkStateNullEtag() throws Exception { + DaprProtos.GetBulkStateResponse responseEnvelope = DaprProtos.GetBulkStateResponse.newBuilder() + .addItems(DaprProtos.BulkStateItem.newBuilder() + .setData(serialize("hello world")) + .setKey("100") + .build()) + .addItems(DaprProtos.BulkStateItem.newBuilder() + .setKey("200") + .setEtag("") + .setError("not found") + .build()) + .build(); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).getBulkState(any(DaprProtos.GetBulkStateRequest.class), any()); + + List> result = client.getBulkState(STATE_STORE_NAME, Arrays.asList("100", "200"), String.class).block(); + + assertEquals(2, result.size()); + assertEquals("100", result.stream().findFirst().get().getKey()); + assertEquals("hello world", result.stream().findFirst().get().getValue()); + assertNull(result.stream().findFirst().get().getEtag()); + assertNull(result.stream().findFirst().get().getError()); + assertEquals("200", result.stream().skip(1).findFirst().get().getKey()); + assertNull(result.stream().skip(1).findFirst().get().getValue()); + assertNull(result.stream().skip(1).findFirst().get().getEtag()); + assertEquals("not found", result.stream().skip(1).findFirst().get().getError()); } @Test @@ -1664,21 +1890,20 @@ public void getSecrets() { String expectedKey = "attributeKey"; String expectedValue = "Expected secret value"; DaprProtos.GetSecretResponse responseEnvelope = buildGetSecretResponse(expectedKey, expectedValue); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(responseEnvelope); - addCallback(settableFuture, callback, directExecutor()); - settableFuture.set(responseEnvelope); - - when(client.getSecret(any(io.dapr.v1.DaprProtos.GetSecretRequest.class))) - .thenAnswer(context -> { - io.dapr.v1.DaprProtos.GetSecretRequest req = context.getArgument(0); - assertEquals("key", req.getKey()); - assertEquals(SECRET_STORE_NAME, req.getStoreName()); - assertEquals(0, req.getMetadataCount()); - return settableFuture; - }); - Map result = adapter.getSecret(SECRET_STORE_NAME, "key").block(); + doAnswer((Answer) invocation -> { + DaprProtos.GetSecretRequest req = invocation.getArgument(0); + assertEquals("key", req.getKey()); + assertEquals(SECRET_STORE_NAME, req.getStoreName()); + assertEquals(0, req.getMetadataCount()); + + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).getSecret(any(DaprProtos.GetSecretRequest.class), any()); + + Map result = client.getSecret(SECRET_STORE_NAME, "key").block(); assertEquals(1, result.size()); assertEquals(expectedValue, result.get(expectedKey)); @@ -1687,61 +1912,57 @@ public void getSecrets() { @Test public void getSecretsEmptyResponse() { DaprProtos.GetSecretResponse responseEnvelope = buildGetSecretResponse(); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(responseEnvelope); - addCallback(settableFuture, callback, directExecutor()); - settableFuture.set(responseEnvelope); - - when(client.getSecret(any(io.dapr.v1.DaprProtos.GetSecretRequest.class))) - .thenAnswer(context -> { - io.dapr.v1.DaprProtos.GetSecretRequest req = context.getArgument(0); - assertEquals("key", req.getKey()); - assertEquals(SECRET_STORE_NAME, req.getStoreName()); - assertEquals(0, req.getMetadataCount()); - return settableFuture; - }); - Map result = adapter.getSecret(SECRET_STORE_NAME, "key").block(); + doAnswer((Answer) invocation -> { + DaprProtos.GetSecretRequest req = invocation.getArgument(0); + assertEquals("key", req.getKey()); + assertEquals(SECRET_STORE_NAME, req.getStoreName()); + assertEquals(0, req.getMetadataCount()); + + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).getSecret(any(DaprProtos.GetSecretRequest.class), any()); + + Map result = client.getSecret(SECRET_STORE_NAME, "key").block(); assertTrue(result.isEmpty()); } @Test public void getSecretsException() { - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(new RuntimeException()); - addCallback(settableFuture, callback, directExecutor()); - settableFuture.setException(new RuntimeException()); - - when(client.getSecret(any(io.dapr.v1.DaprProtos.GetSecretRequest.class))) - .thenAnswer(context -> { - io.dapr.v1.DaprProtos.GetSecretRequest req = context.getArgument(0); - assertEquals("key", req.getKey()); - assertEquals(SECRET_STORE_NAME, req.getStoreName()); - assertEquals(0, req.getMetadataCount()); - return settableFuture; - }); + doAnswer((Answer) invocation -> { + DaprProtos.GetSecretRequest req = invocation.getArgument(0); + assertEquals("key", req.getKey()); + assertEquals(SECRET_STORE_NAME, req.getStoreName()); + assertEquals(0, req.getMetadataCount()); - assertThrowsDaprException(ExecutionException.class, () -> adapter.getSecret(SECRET_STORE_NAME, "key").block()); + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onError(new RuntimeException()); + return null; + }).when(daprStub).getSecret(any(DaprProtos.GetSecretRequest.class), any()); + + assertThrowsDaprException(ExecutionException.class, () -> client.getSecret(SECRET_STORE_NAME, "key").block()); } @Test public void getSecretsIllegalArgumentException() { - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // empty secret store name - adapter.getSecret("", "key").block(); + client.getSecret("", "key").block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // null secret store name - adapter.getSecret(null, "key").block(); + client.getSecret(null, "key").block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // empty key - adapter.getSecret(SECRET_STORE_NAME, "").block(); + client.getSecret(SECRET_STORE_NAME, "").block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // null key - adapter.getSecret(SECRET_STORE_NAME, null).block(); + client.getSecret(SECRET_STORE_NAME, null).block(); }); } @@ -1750,21 +1971,19 @@ public void getSecretsWithMetadata() { String expectedKey = "attributeKey"; String expectedValue = "Expected secret value"; DaprProtos.GetSecretResponse responseEnvelope = buildGetSecretResponse(expectedKey, expectedValue); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(responseEnvelope); - addCallback(settableFuture, callback, directExecutor()); - settableFuture.set(responseEnvelope); - - when(client.getSecret(any(io.dapr.v1.DaprProtos.GetSecretRequest.class))) - .thenAnswer(context -> { - io.dapr.v1.DaprProtos.GetSecretRequest req = context.getArgument(0); - assertEquals("key", req.getKey()); - assertEquals(SECRET_STORE_NAME, req.getStoreName()); - assertEquals("metavalue", req.getMetadataMap().get("metakey")); - return settableFuture; - }); - - Map result = adapter.getSecret( + doAnswer((Answer) invocation -> { + DaprProtos.GetSecretRequest req = invocation.getArgument(0); + assertEquals("key", req.getKey()); + assertEquals(SECRET_STORE_NAME, req.getStoreName()); + assertEquals("metavalue", req.getMetadataMap().get("metakey")); + + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).getSecret(any(DaprProtos.GetSecretRequest.class), any()); + + Map result = client.getSecret( SECRET_STORE_NAME, "key", Collections.singletonMap("metakey", "metavalue")).block(); @@ -1773,6 +1992,74 @@ public void getSecretsWithMetadata() { assertEquals(expectedValue, result.get(expectedKey)); } + @Test + public void getBulkSecrets() { + DaprProtos.GetBulkSecretResponse responseEnvelope = buildGetBulkSecretResponse( + new HashMap>() {{ + put("one", Collections.singletonMap("mysecretkey", "mysecretvalue")); + put("two", new HashMap() {{ + put("a", "1"); + put("b", "2"); + }}); + }}); + + doAnswer((Answer) invocation -> { + DaprProtos.GetBulkSecretRequest req = invocation.getArgument(0); + assertEquals(SECRET_STORE_NAME, req.getStoreName()); + assertEquals(0, req.getMetadataCount()); + + StreamObserver observer = + (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).getBulkSecret(any(DaprProtos.GetBulkSecretRequest.class), any()); + + Map> secrets = client.getBulkSecret(SECRET_STORE_NAME).block(); + + assertEquals(2, secrets.size()); + assertEquals(1, secrets.get("one").size()); + assertEquals("mysecretvalue", secrets.get("one").get("mysecretkey")); + assertEquals(2, secrets.get("two").size()); + assertEquals("1", secrets.get("two").get("a")); + assertEquals("2", secrets.get("two").get("b")); + } + + @Test + public void getBulkSecretsWithMetadata() { + DaprProtos.GetBulkSecretResponse responseEnvelope = buildGetBulkSecretResponse( + new HashMap>() {{ + put("one", Collections.singletonMap("mysecretkey", "mysecretvalue")); + put("two", new HashMap() {{ + put("a", "1"); + put("b", "2"); + }}); + }}); + + doAnswer((Answer) invocation -> { + DaprProtos.GetBulkSecretRequest req = invocation.getArgument(0); + assertEquals(SECRET_STORE_NAME, req.getStoreName()); + assertEquals(1, req.getMetadataCount()); + assertEquals("metavalue", req.getMetadataOrThrow("metakey")); + + StreamObserver observer = + (StreamObserver) invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).getBulkSecret(any(DaprProtos.GetBulkSecretRequest.class), any()); + + Map> secrets = client.getBulkSecret( + SECRET_STORE_NAME, Collections.singletonMap("metakey", "metavalue")).block(); + + assertEquals(2, secrets.size()); + assertEquals(1, secrets.get("one").size()); + assertEquals("mysecretvalue", secrets.get("one").get("mysecretkey")); + assertEquals(2, secrets.get("two").size()); + assertEquals("1", secrets.get("two").get("a")); + assertEquals("2", secrets.get("two").get("b")); + } + /* If this test is failing, it means that a new value was added to StateOptions.Consistency * enum, without creating a mapping to one of the proto defined gRPC enums */ @@ -1781,18 +2068,18 @@ public void stateOptionsConsistencyValuesHaveValidGrpcEnumMappings() { String key = "key1"; String etag = "ETag1"; String value = "State value"; - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.saveState(any(io.dapr.v1.DaprProtos.SaveStateRequest.class))).thenReturn(settableFuture); - settableFuture.set(Empty.newBuilder().build()); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).saveState(any(DaprProtos.SaveStateRequest.class), any()); + for (StateOptions.Consistency consistency : StateOptions.Consistency.values()) { StateOptions options = buildStateOptions(consistency, StateOptions.Concurrency.FIRST_WRITE); - Mono result = adapter.saveState(STATE_STORE_NAME, key, etag, value, options); + Mono result = client.saveState(STATE_STORE_NAME, key, etag, value, options); result.block(); } - - assertTrue(callback.wasCalled); } /* If this test is failing, it means that a new value was added to StateOptions.Concurrency @@ -1803,28 +2090,22 @@ public void stateOptionsConcurrencyValuesHaveValidGrpcEnumMappings() { String key = "key1"; String etag = "ETag1"; String value = "State value"; - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(Empty.newBuilder().build()); - addCallback(settableFuture, callback, directExecutor()); - when(client.saveState(any(io.dapr.v1.DaprProtos.SaveStateRequest.class))).thenReturn(settableFuture); - settableFuture.set(Empty.newBuilder().build()); + doAnswer((Answer) invocation -> { + StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; + observer.onNext(Empty.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).saveState(any(DaprProtos.SaveStateRequest.class), any()); + for (StateOptions.Concurrency concurrency : StateOptions.Concurrency.values()) { StateOptions options = buildStateOptions(StateOptions.Consistency.EVENTUAL, concurrency); - Mono result = adapter.saveState(STATE_STORE_NAME, key, etag, value, options); + Mono result = client.saveState(STATE_STORE_NAME, key, etag, value, options); result.block(); } - - assertTrue(callback.wasCalled); } - private SettableFuture buildFutureGetStateEnvelop(T value, String etag) throws IOException { - DaprProtos.GetStateResponse envelope = buildGetStateResponse(value, etag); - SettableFuture settableFuture = SettableFuture.create(); - MockCallback callback = new MockCallback<>(envelope); - addCallback(settableFuture, callback, directExecutor()); - settableFuture.set(envelope); - - return settableFuture; + private DaprProtos.GetStateResponse buildFutureGetStateEnvelop(T value, String etag) throws IOException { + return buildGetStateResponse(value, etag); } private DaprProtos.GetStateResponse buildGetStateResponse(T value, String etag) throws IOException { @@ -1844,6 +2125,16 @@ private DaprProtos.GetSecretResponse buildGetSecretResponse() { return DaprProtos.GetSecretResponse.newBuilder().build(); } + private DaprProtos.GetBulkSecretResponse buildGetBulkSecretResponse(Map> res) { + Map map = res.entrySet().stream().collect( + Collectors.toMap( + e -> e.getKey(), + e -> DaprProtos.SecretResponse.newBuilder().putAllSecrets(e.getValue()).build())); + return DaprProtos.GetBulkSecretResponse.newBuilder() + .putAllData(map) + .build(); + } + private StateOptions buildStateOptions(StateOptions.Consistency consistency, StateOptions.Concurrency concurrency) { StateOptions options = null; if (consistency != null || concurrency != null) { @@ -1861,37 +2152,6 @@ private ByteString serialize(Object value) throws IOException { return ByteString.copyFrom(byteValue); } - private static final class MockCallback implements FutureCallback { - private T value = null; - 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 == null, throwable == null); - if (failure != null) { - assertEquals(failure.getClass(), throwable.getClass()); - } - } - } - public static class MyObject { private Integer id; private String value; diff --git a/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java index b902b7d204..146846b457 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java @@ -6,8 +6,8 @@ import com.fasterxml.jackson.core.JsonParseException; import io.dapr.client.domain.DeleteStateRequestBuilder; +import io.dapr.client.domain.GetBulkStateRequestBuilder; import io.dapr.client.domain.GetStateRequestBuilder; -import io.dapr.client.domain.GetStatesRequestBuilder; import io.dapr.client.domain.HttpExtension; import io.dapr.client.domain.Response; import io.dapr.client.domain.State; @@ -26,6 +26,8 @@ import reactor.core.publisher.Mono; import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; @@ -35,6 +37,7 @@ import java.util.Map; import static io.dapr.utils.TestUtils.assertThrowsDaprException; +import static io.dapr.utils.TestUtils.findFreePort; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -51,7 +54,7 @@ public class DaprClientHttpTest { private final String EXPECTED_RESULT = "{\"data\":\"ewoJCSJwcm9wZXJ0eUEiOiAidmFsdWVBIiwKCQkicHJvcGVydHlCIjogInZhbHVlQiIKCX0=\"}"; - private DaprClientHttp daprClientHttp; + private DaprClient daprClientHttp; private DaprHttp daprHttp; @@ -63,6 +66,36 @@ public class DaprClientHttpTest { public void setUp() { mockInterceptor = new MockInterceptor(Behavior.UNORDERED); okHttpClient = new OkHttpClient.Builder().addInterceptor(mockInterceptor).build(); + daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); + daprClientHttp = new DaprClientProxy(new DaprClientHttp(daprHttp)); + } + + @Test + public void waitForSidecarTimeout() throws Exception { + int port = findFreePort(); + System.setProperty(Properties.HTTP_PORT.getName(), Integer.toString(port)); + daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), port, okHttpClient); + DaprClientHttp daprClientHttp = new DaprClientHttp(daprHttp); + assertThrows(RuntimeException.class, () -> daprClientHttp.waitForSidecar(1).block()); + } + + @Test + public void waitForSidecarTimeoutOK() throws Exception { + try (ServerSocket serverSocket = new ServerSocket(0)) { + final int port = serverSocket.getLocalPort(); + System.setProperty(Properties.HTTP_PORT.getName(), Integer.toString(port)); + Thread t = new Thread(() -> { + try { + try (Socket socket = serverSocket.accept()) { + } + } catch (IOException e) { + } + }); + t.start(); + daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), port, okHttpClient); + DaprClientHttp daprClientHttp = new DaprClientHttp(daprHttp); + daprClientHttp.waitForSidecar(10000).block(); + } } @Test @@ -83,8 +116,7 @@ public void publishEvent() { .post("http://127.0.0.1:3000/v1.0/publish/mypubsubname/A") .respond(EXPECTED_RESULT); String event = "{ \"message\": \"This is a test\" }"; - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + Mono mono = daprClientHttp.publishEvent("mypubsubname","A", event); assertNull(mono.block()); } @@ -92,11 +124,10 @@ public void publishEvent() { @Test public void publishEventIfTopicIsNullOrEmpty() { String event = "{ \"message\": \"This is a test\" }"; - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - assertThrowsDaprException(IllegalArgumentException.class, () -> + + assertThrows(IllegalArgumentException.class, () -> daprClientHttp.publishEvent("mypubsubname", null, event).block()); - assertThrowsDaprException(IllegalArgumentException.class, () -> + assertThrows(IllegalArgumentException.class, () -> daprClientHttp.publishEvent("mypubsubname", "", event).block()); } @@ -106,8 +137,7 @@ public void publishEventNoHotMono() { .post("http://127.0.0.1:3000/v1.0/publish/mypubsubname/A") .respond(EXPECTED_RESULT); String event = "{ \"message\": \"This is a test\" }"; - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + daprClientHttp.publishEvent("mypubsubname", "", event); // Should not throw exception because did not call block() on mono above. } @@ -118,10 +148,9 @@ public void invokeServiceVerbNull() { .post("http://127.0.0.1:3000/v1.0/publish/A") .respond(EXPECTED_RESULT); String event = "{ \"message\": \"This is a test\" }"; - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - assertThrowsDaprException(IllegalArgumentException.class, () -> - daprClientHttp.invokeService(null, "", "", null, null, (Class)null).block()); + + assertThrows(IllegalArgumentException.class, () -> + daprClientHttp.invokeMethod(null, "", "", null, null, (Class)null).block()); } @Test @@ -129,35 +158,34 @@ public void invokeServiceIllegalArgumentException() { mockInterceptor.addRule() .get("http://127.0.0.1:3000/v1.0/invoke/41/method/badorder") .respond("INVALID JSON"); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + + assertThrows(IllegalArgumentException.class, () -> { // null HttpMethod - daprClientHttp.invokeService("1", "2", "3", new HttpExtension(null, null), null, (Class)null).block(); + daprClientHttp.invokeMethod("1", "2", "3", new HttpExtension(null), null, (Class)null).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // null HttpExtension - daprClientHttp.invokeService("1", "2", "3", null, null, (Class)null).block(); + daprClientHttp.invokeMethod("1", "2", "3", null, null, (Class)null).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // empty appId - daprClientHttp.invokeService("", "1", null, HttpExtension.GET, null, (Class)null).block(); + daprClientHttp.invokeMethod("", "1", null, HttpExtension.GET, null, (Class)null).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // null appId, empty method - daprClientHttp.invokeService(null, "", null, HttpExtension.POST, null, (Class)null).block(); + daprClientHttp.invokeMethod(null, "", null, HttpExtension.POST, null, (Class)null).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // empty method - daprClientHttp.invokeService("1", "", null, HttpExtension.PUT, null, (Class)null).block(); + daprClientHttp.invokeMethod("1", "", null, HttpExtension.PUT, null, (Class)null).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { // null method - daprClientHttp.invokeService("1", null, null, HttpExtension.DELETE, null, (Class)null).block(); + daprClientHttp.invokeMethod("1", null, null, HttpExtension.DELETE, null, (Class)null).block(); }); assertThrowsDaprException(JsonParseException.class, () -> { // invalid JSON response - daprClientHttp.invokeService("41", "badorder", null, HttpExtension.GET, null, String.class).block(); + daprClientHttp.invokeMethod("41", "badorder", null, HttpExtension.GET, null, String.class).block(); }); } @@ -168,10 +196,9 @@ public void invokeServiceMethodNull() { .post("http://127.0.0.1:3000/v1.0/publish/A") .respond(EXPECTED_RESULT); String event = "{ \"message\": \"This is a test\" }"; - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - assertThrowsDaprException(IllegalArgumentException.class, () -> - daprClientHttp.invokeService("1", "", null, HttpExtension.POST, null, (Class)null).block()); + + assertThrows(IllegalArgumentException.class, () -> + daprClientHttp.invokeMethod("1", "", null, HttpExtension.POST, null, (Class)null).block()); } @Test @@ -179,9 +206,8 @@ public void invokeService() { mockInterceptor.addRule() .get("http://127.0.0.1:3000/v1.0/invoke/41/method/neworder") .respond("\"hello world\""); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - Mono mono = daprClientHttp.invokeService("41", "neworder", null, HttpExtension.GET, null, String.class); + + Mono mono = daprClientHttp.invokeMethod("41", "neworder", null, HttpExtension.GET, null, String.class); assertEquals("hello world", mono.block()); } @@ -190,9 +216,8 @@ public void invokeServiceNullResponse() { mockInterceptor.addRule() .get("http://127.0.0.1:3000/v1.0/invoke/41/method/neworder") .respond(new byte[0]); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - Mono mono = daprClientHttp.invokeService("41", "neworder", null, HttpExtension.GET, null, String.class); + + Mono mono = daprClientHttp.invokeMethod("41", "neworder", null, HttpExtension.GET, null, String.class); assertNull(mono.block()); } @@ -201,9 +226,8 @@ public void simpleInvokeService() { mockInterceptor.addRule() .get("http://127.0.0.1:3000/v1.0/invoke/41/method/neworder") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - Mono mono = daprClientHttp.invokeService("41", "neworder", null, HttpExtension.GET, byte[].class); + + Mono mono = daprClientHttp.invokeMethod("41", "neworder", null, HttpExtension.GET, byte[].class); assertEquals(new String(mono.block()), EXPECTED_RESULT); } @@ -213,9 +237,8 @@ public void invokeServiceWithMetadataMap() { mockInterceptor.addRule() .get("http://127.0.0.1:3000/v1.0/invoke/41/method/neworder") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - Mono mono = daprClientHttp.invokeService("41", "neworder", (byte[]) null, HttpExtension.GET, map); + + Mono mono = daprClientHttp.invokeMethod("41", "neworder", (byte[]) null, HttpExtension.GET, map); String monoString = new String(mono.block()); assertEquals(monoString, EXPECTED_RESULT); } @@ -226,9 +249,8 @@ public void invokeServiceWithOutRequest() { mockInterceptor.addRule() .get("http://127.0.0.1:3000/v1.0/invoke/41/method/neworder") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - Mono mono = daprClientHttp.invokeService("41", "neworder", HttpExtension.GET, map); + + Mono mono = daprClientHttp.invokeMethod("41", "neworder", HttpExtension.GET, map); assertNull(mono.block()); } @@ -238,9 +260,8 @@ public void invokeServiceWithRequest() { mockInterceptor.addRule() .get("http://127.0.0.1:3000/v1.0/invoke/41/method/neworder") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - Mono mono = daprClientHttp.invokeService("41", "neworder", "", HttpExtension.GET, map); + + Mono mono = daprClientHttp.invokeMethod("41", "neworder", "", HttpExtension.GET, map); assertNull(mono.block()); } @@ -250,12 +271,11 @@ public void invokeServiceWithRequestAndQueryString() { mockInterceptor.addRule() .get("http://127.0.0.1:3000/v1.0/invoke/41/method/neworder?test=1") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + Map queryString = new HashMap<>(); queryString.put("test", "1"); - HttpExtension httpExtension = new HttpExtension(DaprHttp.HttpMethods.GET, queryString); - Mono mono = daprClientHttp.invokeService("41", "neworder", "", httpExtension, map); + HttpExtension httpExtension = new HttpExtension(DaprHttp.HttpMethods.GET, queryString, null); + Mono mono = daprClientHttp.invokeMethod("41", "neworder", "", httpExtension, map); assertNull(mono.block()); } @@ -265,9 +285,8 @@ public void invokeServiceNoHotMono() { mockInterceptor.addRule() .get("http://127.0.0.1:3000/v1.0/invoke/41/method/neworder") .respond(500); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - daprClientHttp.invokeService("41", "neworder", "", HttpExtension.GET, map); + + daprClientHttp.invokeMethod("41", "neworder", "", HttpExtension.GET, map); // No exception should be thrown because did not call block() on mono above. } @@ -277,8 +296,7 @@ public void invokeBinding() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/bindings/sample-topic") .respond(""); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", ""); assertNull(mono.block()); } @@ -289,8 +307,7 @@ public void invokeBindingNullData() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/bindings/sample-topic") .respond(""); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", null); assertNull(mono.block()); } @@ -300,18 +317,17 @@ public void invokeBindingErrors() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/bindings/sample-topic") .respond("NOT VALID JSON"); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.invokeBinding(null, "myoperation", "").block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.invokeBinding("", "myoperation", "").block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.invokeBinding("topic", null, "").block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.invokeBinding("topic", "", "").block(); }); assertThrowsDaprException(JsonParseException.class, () -> { @@ -325,8 +341,7 @@ public void invokeBindingResponseNull() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/bindings/sample-topic") .respond(new byte[0]); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", null, String.class); assertNull(mono.block()); } @@ -337,8 +352,7 @@ public void invokeBindingResponseObject() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/bindings/sample-topic") .respond("\"OK\""); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", null, String.class); assertEquals("OK", mono.block()); } @@ -349,8 +363,7 @@ public void invokeBindingResponseDouble() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/bindings/sample-topic") .respond("1.5"); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", map, double.class); assertEquals(1.5, mono.block(), 0.0001); } @@ -361,8 +374,7 @@ public void invokeBindingResponseFloat() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/bindings/sample-topic") .respond("1.5"); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", null, float.class); assertEquals(1.5, mono.block(), 0.0001); } @@ -373,8 +385,7 @@ public void invokeBindingResponseChar() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/bindings/sample-topic") .respond("\"a\""); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", null, char.class); assertEquals('a', (char)mono.block()); } @@ -385,8 +396,7 @@ public void invokeBindingResponseByte() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/bindings/sample-topic") .respond("\"2\""); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", null, byte.class); assertEquals((byte)0x2, (byte)mono.block()); } @@ -397,8 +407,7 @@ public void invokeBindingResponseLong() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/bindings/sample-topic") .respond("1"); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", null, long.class); assertEquals(1, (long)mono.block()); } @@ -409,8 +418,7 @@ public void invokeBindingResponseInt() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/bindings/sample-topic") .respond("1"); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", null, int.class); assertEquals(1, (int)mono.block()); } @@ -421,9 +429,8 @@ public void invokeBindingNullName() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/bindings/sample-topic") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - assertThrowsDaprException(IllegalArgumentException.class, () -> + + assertThrows(IllegalArgumentException.class, () -> daprClientHttp.invokeBinding(null, "myoperation", "").block()); } @@ -433,9 +440,8 @@ public void invokeBindingNullOpName() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/bindings/sample-topic") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - assertThrowsDaprException(IllegalArgumentException.class, () -> + + assertThrows(IllegalArgumentException.class, () -> daprClientHttp.invokeBinding("sample-topic", null, "").block()); } @@ -445,8 +451,7 @@ public void bindingNoHotMono() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/bindings/sample-topic") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + daprClientHttp.invokeBinding(null, "", ""); // No exception is thrown because did not call block() on mono above. } @@ -456,28 +461,27 @@ public void getStatesErrors() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/state/MyStateStore/bulk") .respond("NOT VALID JSON"); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - assertThrowsDaprException(IllegalArgumentException.class, () -> { - daprClientHttp.getStates(STATE_STORE_NAME, null, String.class).block(); + + assertThrows(IllegalArgumentException.class, () -> { + daprClientHttp.getBulkState(STATE_STORE_NAME, null, String.class).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { - daprClientHttp.getStates(STATE_STORE_NAME, new ArrayList<>(), String.class).block(); + assertThrows(IllegalArgumentException.class, () -> { + daprClientHttp.getBulkState(STATE_STORE_NAME, new ArrayList<>(), String.class).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { - daprClientHttp.getStates(null, Arrays.asList("100", "200"), String.class).block(); + assertThrows(IllegalArgumentException.class, () -> { + daprClientHttp.getBulkState(null, Arrays.asList("100", "200"), String.class).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { - daprClientHttp.getStates("", Arrays.asList("100", "200"), String.class).block(); + assertThrows(IllegalArgumentException.class, () -> { + daprClientHttp.getBulkState("", Arrays.asList("100", "200"), String.class).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { - daprClientHttp.getStates( - new GetStatesRequestBuilder(STATE_STORE_NAME, "100").withParallelism(-1).build(), + assertThrows(IllegalArgumentException.class, () -> { + daprClientHttp.getBulkState( + new GetBulkStateRequestBuilder(STATE_STORE_NAME, "100").withParallelism(-1).build(), TypeRef.get(String.class)).block(); }); assertThrowsDaprException(JsonParseException.class, () -> { - daprClientHttp.getStates( - new GetStatesRequestBuilder(STATE_STORE_NAME, "100").build(), + daprClientHttp.getBulkState( + new GetBulkStateRequestBuilder(STATE_STORE_NAME, "100").build(), TypeRef.get(String.class)).block(); }); } @@ -488,10 +492,9 @@ public void getStatesString() { .post("http://127.0.0.1:3000/v1.0/state/MyStateStore/bulk") .respond("[{\"key\": \"100\", \"data\": \"hello world\", \"etag\": \"1\"}," + "{\"key\": \"200\", \"error\": \"not found\"}]"); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + List> result = - daprClientHttp.getStates(STATE_STORE_NAME, Arrays.asList("100", "200"), String.class).block(); + daprClientHttp.getBulkState(STATE_STORE_NAME, Arrays.asList("100", "200"), String.class).block(); assertEquals(2, result.size()); assertEquals("100", result.stream().findFirst().get().getKey()); assertEquals("hello world", result.stream().findFirst().get().getValue()); @@ -509,10 +512,9 @@ public void getStatesInteger() { .post("http://127.0.0.1:3000/v1.0/state/MyStateStore/bulk") .respond("[{\"key\": \"100\", \"data\": 1234, \"etag\": \"1\"}," + "{\"key\": \"200\", \"error\": \"not found\"}]"); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + List> result = - daprClientHttp.getStates(STATE_STORE_NAME, Arrays.asList("100", "200"), int.class).block(); + daprClientHttp.getBulkState(STATE_STORE_NAME, Arrays.asList("100", "200"), int.class).block(); assertEquals(2, result.size()); assertEquals("100", result.stream().findFirst().get().getKey()); assertEquals(1234, (int)result.stream().findFirst().get().getValue()); @@ -531,10 +533,9 @@ public void getStatesBoolean() { .post("http://127.0.0.1:3000/v1.0/state/MyStateStore/bulk") .respond("[{\"key\": \"100\", \"data\": true, \"etag\": \"1\"}," + "{\"key\": \"200\", \"error\": \"not found\"}]"); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + List> result = - daprClientHttp.getStates(STATE_STORE_NAME, Arrays.asList("100", "200"), boolean.class).block(); + daprClientHttp.getBulkState(STATE_STORE_NAME, Arrays.asList("100", "200"), boolean.class).block(); assertNotNull(result); assertEquals(2, result.size()); assertEquals("100", result.stream().findFirst().get().getKey()); @@ -555,12 +556,11 @@ public void getStatesByteArray() { .post("http://127.0.0.1:3000/v1.0/state/MyStateStore/bulk") .respond("[{\"key\": \"100\", \"data\": \"" + base64Value + "\", \"etag\": \"1\"}," + "{\"key\": \"200\", \"error\": \"not found\"}]"); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + // JSON cannot differentiate if data returned is String or byte[], it is ambiguous. So we get base64 encoded back. // So, users should use String instead of byte[]. List> result = - daprClientHttp.getStates(STATE_STORE_NAME, Arrays.asList("100", "200"), String.class).block(); + daprClientHttp.getBulkState(STATE_STORE_NAME, Arrays.asList("100", "200"), String.class).block(); assertEquals(2, result.size()); assertEquals("100", result.stream().findFirst().get().getKey()); assertEquals(base64Value, result.stream().findFirst().get().getValue()); @@ -580,12 +580,11 @@ public void getStatesObject() { .respond("[{\"key\": \"100\", \"data\": " + "{ \"id\": \"" + object.id + "\", \"value\": \"" + object.value + "\"}, \"etag\": \"1\"}," + "{\"key\": \"200\", \"error\": \"not found\"}]"); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + // JSON cannot differentiate if data returned is String or byte[], it is ambiguous. So we get base64 encoded back. // So, users should use String instead of byte[]. List> result = - daprClientHttp.getStates(STATE_STORE_NAME, Arrays.asList("100", "200"), MyObject.class).block(); + daprClientHttp.getBulkState(STATE_STORE_NAME, Arrays.asList("100", "200"), MyObject.class).block(); assertEquals(2, result.size()); assertEquals("100", result.stream().findFirst().get().getKey()); assertEquals(object, result.stream().findFirst().get().getValue()); @@ -610,18 +609,17 @@ public void getState() { mockInterceptor.addRule() .get("http://127.0.0.1:3000/v1.0/state/MyStateStore/keyBadPayload") .respond("NOT VALID"); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.getState(STATE_STORE_NAME, stateKeyNull, String.class).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.getState(STATE_STORE_NAME, stateKeyEmpty, String.class).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.getState(null, stateKeyValue, String.class).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.getState("", stateKeyValue, String.class).block(); }); assertThrowsDaprException(JsonParseException.class, () -> { @@ -639,10 +637,10 @@ public void getStatesEmptyEtag() { mockInterceptor.addRule() .get("http://127.0.0.1:3000/v1.0/state/MyStateStore/key") .respond("\"" + EXPECTED_RESULT + "\""); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - Mono> monoEmptyEtag = daprClientHttp.getState(STATE_STORE_NAME, stateEmptyEtag, String.class); - assertEquals(monoEmptyEtag.block().getKey(), "key"); + + State monoEmptyEtag = daprClientHttp.getState(STATE_STORE_NAME, stateEmptyEtag, String.class).block(); + assertEquals(monoEmptyEtag.getKey(), "key"); + assertNull(monoEmptyEtag.getEtag()); } @Test @@ -650,12 +648,11 @@ public void getStateWithMetadata() { Map metadata = new HashMap<>(); metadata.put("key_1", "val_1"); mockInterceptor.addRule() - .get("http://127.0.0.1:3000/v1.0/state/MyStateStore/key?key_1=val_1") + .get("http://127.0.0.1:3000/v1.0/state/MyStateStore/key?metadata.key_1=val_1") .respond("\"" + EXPECTED_RESULT + "\""); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + GetStateRequestBuilder builder = new GetStateRequestBuilder(STATE_STORE_NAME, "key"); - builder.withMetadata(metadata).withEtag(""); + builder.withMetadata(metadata); Mono>> monoMetadata = daprClientHttp.getState(builder.build(), TypeRef.get(String.class)); assertEquals(monoMetadata.block().getObject().getKey(), "key"); } @@ -666,10 +663,10 @@ public void getStatesNullEtag() { mockInterceptor.addRule() .get("http://127.0.0.1:3000/v1.0/state/MyStateStore/key") .respond("\"" + EXPECTED_RESULT + "\""); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - Mono> monoNullEtag = daprClientHttp.getState(STATE_STORE_NAME, stateNullEtag, String.class); - assertEquals(monoNullEtag.block().getKey(), "key"); + + State monoNullEtag = daprClientHttp.getState(STATE_STORE_NAME, stateNullEtag, String.class).block(); + assertEquals(monoNullEtag.getKey(), "key"); + assertNull(monoNullEtag.getEtag()); } @Test @@ -678,8 +675,7 @@ public void getStatesNoHotMono() { mockInterceptor.addRule() .get("http://127.0.0.1:3000/v1.0/state/MyStateStore/key") .respond(500); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + daprClientHttp.getState(STATE_STORE_NAME, stateNullEtag, String.class); // No exception should be thrown since did not call block() on mono above. } @@ -691,30 +687,27 @@ public void saveStates() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/state/MyStateStore") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - Mono mono = daprClientHttp.saveStates(STATE_STORE_NAME, stateKeyValueList); + + Mono mono = daprClientHttp.saveBulkState(STATE_STORE_NAME, stateKeyValueList); assertNull(mono.block()); } @Test public void saveStatesErrors() { - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - assertThrowsDaprException(IllegalArgumentException.class, () -> - daprClientHttp.saveStates(null, null).block()); - assertThrowsDaprException(IllegalArgumentException.class, () -> - daprClientHttp.saveStates("", null).block()); + + assertThrows(IllegalArgumentException.class, () -> + daprClientHttp.saveBulkState(null, null).block()); + assertThrows(IllegalArgumentException.class, () -> + daprClientHttp.saveBulkState("", null).block()); } @Test public void saveStatesNull() { List> stateKeyValueList = new ArrayList<>(); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - Mono mono = daprClientHttp.saveStates(STATE_STORE_NAME, null); + + Mono mono = daprClientHttp.saveBulkState(STATE_STORE_NAME, null); assertNull(mono.block()); - Mono mono1 = daprClientHttp.saveStates(STATE_STORE_NAME, stateKeyValueList); + Mono mono1 = daprClientHttp.saveBulkState(STATE_STORE_NAME, stateKeyValueList); assertNull(mono1.block()); } @@ -725,9 +718,8 @@ public void saveStatesNullState() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/state/MyStateStore") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - Mono mono1 = daprClientHttp.saveStates(STATE_STORE_NAME, stateKeyValueList); + + Mono mono1 = daprClientHttp.saveBulkState(STATE_STORE_NAME, stateKeyValueList); assertNull(mono1.block()); } @@ -738,9 +730,8 @@ public void saveStatesEtagNull() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/state/MyStateStore") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - Mono mono = daprClientHttp.saveStates(STATE_STORE_NAME, stateKeyValueList); + + Mono mono = daprClientHttp.saveBulkState(STATE_STORE_NAME, stateKeyValueList); assertNull(mono.block()); } @@ -751,9 +742,8 @@ public void saveStatesEtagEmpty() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/state/MyStateStore") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - Mono mono = daprClientHttp.saveStates(STATE_STORE_NAME, stateKeyValueList); + + Mono mono = daprClientHttp.saveBulkState(STATE_STORE_NAME, stateKeyValueList); assertNull(mono.block()); } @@ -763,8 +753,7 @@ public void simpleSaveStates() { .post("http://127.0.0.1:3000/v1.0/state/MyStateStore") .respond(EXPECTED_RESULT); StateOptions stateOptions = mock(StateOptions.class); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + Mono mono = daprClientHttp.saveState(STATE_STORE_NAME, "key", "etag", "value", stateOptions); assertNull(mono.block()); } @@ -775,8 +764,7 @@ public void saveStatesNoHotMono() { .post("http://127.0.0.1:3000/v1.0/state/MyStateStore") .respond(500); StateOptions stateOptions = mock(StateOptions.class); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + daprClientHttp.saveState(STATE_STORE_NAME, "key", "etag", "value", stateOptions); // No exception should be thrown because we did not call block() on the mono above. } @@ -790,8 +778,7 @@ public void simpleExecuteTransaction() { String key = "key1"; String data = "my data"; StateOptions stateOptions = mock(StateOptions.class); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + State stateKey = new State<>(data, key, etag, stateOptions); TransactionalStateOperation upsertOperation = new TransactionalStateOperation<>( @@ -800,7 +787,7 @@ public void simpleExecuteTransaction() { TransactionalStateOperation deleteOperation = new TransactionalStateOperation<>( TransactionalStateOperation.OperationType.DELETE, new State<>("deleteKey")); - Mono mono = daprClientHttp.executeTransaction(STATE_STORE_NAME, Arrays.asList(upsertOperation, + Mono mono = daprClientHttp.executeStateTransaction(STATE_STORE_NAME, Arrays.asList(upsertOperation, deleteOperation)); assertNull(mono.block()); } @@ -814,8 +801,7 @@ public void simpleExecuteTransactionNullEtag() { String key = "key1"; String data = "my data"; StateOptions stateOptions = mock(StateOptions.class); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + State stateKey = new State<>(data, key, etag, stateOptions); TransactionalStateOperation upsertOperation = new TransactionalStateOperation<>( @@ -824,7 +810,7 @@ public void simpleExecuteTransactionNullEtag() { TransactionalStateOperation deleteOperation = new TransactionalStateOperation<>( TransactionalStateOperation.OperationType.DELETE, new State<>("deleteKey")); - Mono mono = daprClientHttp.executeTransaction(STATE_STORE_NAME, Arrays.asList(upsertOperation, + Mono mono = daprClientHttp.executeStateTransaction(STATE_STORE_NAME, Arrays.asList(upsertOperation, deleteOperation)); assertNull(mono.block()); } @@ -838,8 +824,7 @@ public void simpleExecuteTransactionEmptyEtag() { String key = "key1"; String data = "my data"; StateOptions stateOptions = mock(StateOptions.class); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + State stateKey = new State<>(data, key, etag, stateOptions); TransactionalStateOperation upsertOperation = new TransactionalStateOperation<>( @@ -848,7 +833,7 @@ public void simpleExecuteTransactionEmptyEtag() { TransactionalStateOperation deleteOperation = new TransactionalStateOperation<>( TransactionalStateOperation.OperationType.DELETE, new State<>("deleteKey")); - Mono mono = daprClientHttp.executeTransaction(STATE_STORE_NAME, Arrays.asList(upsertOperation, + Mono mono = daprClientHttp.executeStateTransaction(STATE_STORE_NAME, Arrays.asList(upsertOperation, deleteOperation)); assertNull(mono.block()); } @@ -862,8 +847,7 @@ public void simpleExecuteTransactionNullOperationAndNullState() { String key = "key1"; String data = "my data"; StateOptions stateOptions = mock(StateOptions.class); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + State stateKey = new State<>(data, key, etag, stateOptions); TransactionalStateOperation upsertOperation = new TransactionalStateOperation<>( @@ -875,7 +859,7 @@ public void simpleExecuteTransactionNullOperationAndNullState() { TransactionalStateOperation nullStateOperation = new TransactionalStateOperation<>( TransactionalStateOperation.OperationType.DELETE, null); - Mono mono = daprClientHttp.executeTransaction(STATE_STORE_NAME, Arrays.asList( + Mono mono = daprClientHttp.executeStateTransaction(STATE_STORE_NAME, Arrays.asList( null, nullStateOperation, upsertOperation, @@ -885,12 +869,11 @@ public void simpleExecuteTransactionNullOperationAndNullState() { @Test public void executeTransactionErrors() { - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - assertThrowsDaprException(IllegalArgumentException.class, () -> - daprClientHttp.executeTransaction(null, null).block()); - assertThrowsDaprException(IllegalArgumentException.class, () -> - daprClientHttp.executeTransaction("", null).block()); + + assertThrows(IllegalArgumentException.class, () -> + daprClientHttp.executeStateTransaction(null, null).block()); + assertThrows(IllegalArgumentException.class, () -> + daprClientHttp.executeStateTransaction("", null).block()); } @Test @@ -898,11 +881,10 @@ public void simpleExecuteTransactionNull() { mockInterceptor.addRule() .post("http://127.0.0.1:3000/v1.0/state/MyStateStore/transaction") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - Mono mono = daprClientHttp.executeTransaction(STATE_STORE_NAME, null); + + Mono mono = daprClientHttp.executeStateTransaction(STATE_STORE_NAME, null); assertNull(mono.block()); - mono = daprClientHttp.executeTransaction(STATE_STORE_NAME, Collections.emptyList()); + mono = daprClientHttp.executeStateTransaction(STATE_STORE_NAME, Collections.emptyList()); assertNull(mono.block()); } @@ -913,8 +895,7 @@ public void deleteState() { mockInterceptor.addRule() .delete("http://127.0.0.1:3000/v1.0/state/MyStateStore/key") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + Mono mono = daprClientHttp.deleteState(STATE_STORE_NAME, stateKeyValue.getKey(), stateKeyValue.getEtag(), stateOptions); assertNull(mono.block()); } @@ -926,10 +907,9 @@ public void deleteStateWithMetadata() { StateOptions stateOptions = mock(StateOptions.class); State stateKeyValue = new State<>("value", "key", "etag", stateOptions); mockInterceptor.addRule() - .delete("http://127.0.0.1:3000/v1.0/state/MyStateStore/key?key_1=val_1") + .delete("http://127.0.0.1:3000/v1.0/state/MyStateStore/key?metadata.key_1=val_1") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + DeleteStateRequestBuilder builder = new DeleteStateRequestBuilder(STATE_STORE_NAME, stateKeyValue.getKey()); builder.withMetadata(metadata).withEtag(stateKeyValue.getEtag()).withStateOptions(stateOptions); Mono> monoMetadata = daprClientHttp.deleteState(builder.build()); @@ -943,8 +923,7 @@ public void deleteStateNoHotMono() { mockInterceptor.addRule() .delete("http://127.0.0.1:3000/v1.0/state/MyStateStore/key") .respond(500); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + daprClientHttp.deleteState(STATE_STORE_NAME, stateKeyValue.getKey(), stateKeyValue.getEtag(), stateOptions); // No exception should be thrown because we did not call block() on the mono above. } @@ -955,8 +934,7 @@ public void deleteStateNullEtag() { mockInterceptor.addRule() .delete("http://127.0.0.1:3000/v1.0/state/MyStateStore/key") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + Mono mono = daprClientHttp.deleteState(STATE_STORE_NAME, stateKeyValue.getKey(), stateKeyValue.getEtag(), null); assertNull(mono.block()); } @@ -967,8 +945,7 @@ public void deleteStateEmptyEtag() { mockInterceptor.addRule() .delete("http://127.0.0.1:3000/v1.0/state/MyStateStore/key") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + Mono mono = daprClientHttp.deleteState(STATE_STORE_NAME, stateKeyValue.getKey(), stateKeyValue.getEtag(), null); assertNull(mono.block()); } @@ -980,24 +957,23 @@ public void deleteStateIllegalArgumentException() { mockInterceptor.addRule() .delete("http://127.0.0.1:3000/v1.0/state/MyStateStore/key") .respond(EXPECTED_RESULT); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.deleteState(STATE_STORE_NAME, null, null, null).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.deleteState(STATE_STORE_NAME, "", null, null).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.deleteState(STATE_STORE_NAME, " ", null, null).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.deleteState(null, "key", null, null).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.deleteState("", "key", null, null).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.deleteState(" ", "key", null, null).block(); }); } @@ -1005,11 +981,10 @@ public void deleteStateIllegalArgumentException() { @Test public void getSecrets() { mockInterceptor.addRule() - .get("http://127.0.0.1:3000/v1.0/secrets/MySecretStore/key") - .respond("{ \"mysecretkey\": \"mysecretvalue\"}"); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + .get("http://127.0.0.1:3000/v1.0/secrets/MySecretStore/key") + .respond("{ \"mysecretkey\": \"mysecretvalue\"}"); + + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.getSecret(SECRET_STORE_NAME, null).block(); }); Map secret = daprClientHttp.getSecret(SECRET_STORE_NAME, "key").block(); @@ -1018,14 +993,28 @@ public void getSecrets() { assertEquals("mysecretvalue", secret.get("mysecretkey")); } + @Test + public void getSecretsSpecialCharsInKey() { + mockInterceptor.addRule() + .get("http://127.0.0.1:3000/v1.0/secrets/MySecretStore/key%2Fone") + .respond("{ \"mysecretkey\": \"mysecretvalue\"}"); + + assertThrows(IllegalArgumentException.class, () -> { + daprClientHttp.getSecret(SECRET_STORE_NAME, null).block(); + }); + Map secret = daprClientHttp.getSecret(SECRET_STORE_NAME, "key/one").block(); + + assertEquals(1, secret.size()); + assertEquals("mysecretvalue", secret.get("mysecretkey")); + } + @Test public void getSecretsEmpty() { mockInterceptor.addRule() .get("http://127.0.0.1:3000/v1.0/secrets/MySecretStore/key") .respond(""); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.getSecret(SECRET_STORE_NAME, null).block(); }); Map secret = daprClientHttp.getSecret(SECRET_STORE_NAME, "key").block(); @@ -1038,8 +1027,7 @@ public void getSecrets404() { mockInterceptor.addRule() .get("http://127.0.0.1:3000/v1.0/secrets/MySecretStore/key") .respond(404); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + assertThrowsDaprException("UNKNOWN", () -> daprClientHttp.getSecret(SECRET_STORE_NAME, "key").block() ); @@ -1053,8 +1041,7 @@ public void getSecrets404WithErrorCode() { ResponseBody.create("" + "{\"errorCode\":\"ERR_SECRET_STORE_NOT_FOUND\"," + "\"message\":\"error message\"}", MediaTypes.MEDIATYPE_JSON)); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + assertThrowsDaprException("ERR_SECRET_STORE_NOT_FOUND", "ERR_SECRET_STORE_NOT_FOUND: error message", () -> daprClientHttp.getSecret(SECRET_STORE_NAME, "key").block() ); @@ -1065,16 +1052,15 @@ public void getSecretsErrors() { mockInterceptor.addRule() .get("http://127.0.0.1:3000/v1.0/secrets/MySecretStore/key") .respond("INVALID JSON"); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - assertThrowsDaprException(IllegalArgumentException.class, () -> + + assertThrows(IllegalArgumentException.class, () -> daprClientHttp.getSecret(null, "key").block()); - assertThrowsDaprException(IllegalArgumentException.class, () -> + assertThrows(IllegalArgumentException.class, () -> daprClientHttp.getSecret("", "key").block()); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.getSecret(SECRET_STORE_NAME, null).block(); }); - assertThrowsDaprException(IllegalArgumentException.class, () -> { + assertThrows(IllegalArgumentException.class, () -> { daprClientHttp.getSecret(SECRET_STORE_NAME, "").block(); }); assertThrowsDaprException(JsonParseException.class, () -> { @@ -1088,10 +1074,9 @@ public void getSecretsWithMetadata() { .get("http://127.0.0.1:3000/v1.0/secrets/MySecretStore/key") .respond("{ \"mysecretkey\": \"mysecretvalue\"}"); mockInterceptor.addRule() - .get("http://127.0.0.1:3000/v1.0/secrets/MySecretStore/key?metakey=metavalue") + .get("http://127.0.0.1:3000/v1.0/secrets/MySecretStore/key?metadata.metakey=metavalue") .respond("{ \"mysecretkey2\": \"mysecretvalue2\"}"); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); + { Map secret = daprClientHttp.getSecret( SECRET_STORE_NAME, @@ -1113,18 +1098,51 @@ public void getSecretsWithMetadata() { } } + @Test + public void getBulkSecrets() { + mockInterceptor.addRule() + .get("http://127.0.0.1:3000/v1.0/secrets/MySecretStore/bulk") + .respond("{ \"one\": { \"mysecretkey\": \"mysecretvalue\"}, \"two\": { \"a\": \"1\", \"b\": \"2\"}}"); + + Map> secrets = daprClientHttp.getBulkSecret(SECRET_STORE_NAME).block(); + + assertEquals(2, secrets.size()); + assertEquals(1, secrets.get("one").size()); + assertEquals("mysecretvalue", secrets.get("one").get("mysecretkey")); + assertEquals(2, secrets.get("two").size()); + assertEquals("1", secrets.get("two").get("a")); + assertEquals("2", secrets.get("two").get("b")); + } + + @Test + public void getBulkSecretsWithMetadata() { + mockInterceptor.addRule() + .get("http://127.0.0.1:3000/v1.0/secrets/MySecretStore/bulk?metadata.metakey=metavalue") + .respond("{ \"one\": { \"mysecretkey\": \"mysecretvalue\"}, \"two\": { \"a\": \"1\", \"b\": \"2\"}}"); + + Map> secrets = + daprClientHttp.getBulkSecret(SECRET_STORE_NAME, Collections.singletonMap("metakey", "metavalue")).block(); + + assertEquals(2, secrets.size()); + assertEquals(1, secrets.get("one").size()); + assertEquals("mysecretvalue", secrets.get("one").get("mysecretkey")); + assertEquals(2, secrets.get("two").size()); + assertEquals("1", secrets.get("two").get("a")); + assertEquals("2", secrets.get("two").get("b")); + } + @Test public void closeException() { DaprHttp daprHttp = Mockito.mock(DaprHttp.class); - Mockito.doThrow(new IllegalStateException()).when(daprHttp).close(); + Mockito.doThrow(new RuntimeException()).when(daprHttp).close(); - // This method does not throw DaprException because IOException is expected by the Closeable interface. + // This method does not throw DaprException because it already throws RuntimeException and does not call Dapr. daprClientHttp = new DaprClientHttp(daprHttp); - assertThrowsDaprException(IllegalStateException.class, () -> daprClientHttp.close()); + assertThrows(RuntimeException.class, () -> daprClientHttp.close()); } @Test - public void close() { + public void close() throws Exception { DaprHttp daprHttp = Mockito.mock(DaprHttp.class); Mockito.doNothing().when(daprHttp).close(); diff --git a/sdk/src/test/java/io/dapr/client/DaprClientProxyTest.java b/sdk/src/test/java/io/dapr/client/DaprClientProxyTest.java new file mode 100644 index 0000000000..6b7766f434 --- /dev/null +++ b/sdk/src/test/java/io/dapr/client/DaprClientProxyTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ +package io.dapr.client; + +import io.dapr.client.domain.HttpExtension; +import org.junit.Test; +import org.mockito.Mockito; +import reactor.core.publisher.Mono; + +import static org.mockito.Mockito.times; + +public class DaprClientProxyTest { + + @Test + public void stateAPI() { + DaprClient client1 = Mockito.mock(DaprClient.class); + DaprClient client2 = Mockito.mock(DaprClient.class); + + Mockito.when(client1.saveState("state", "key", "value")).thenReturn(Mono.empty()); + Mockito.when(client2.saveState("state", "key", "value")).thenReturn(Mono.empty()); + + DaprClient proxy = new DaprClientProxy(client1, client2); + proxy.saveState("state", "key", "value").block(); + + Mockito.verify(client1, times(1)).saveState("state", "key", "value"); + Mockito.verify(client2, times(0)).saveState("state", "key", "value"); + } + + @Test + public void methodInvocationAPI() { + DaprClient client1 = Mockito.mock(DaprClient.class); + DaprClient client2 = Mockito.mock(DaprClient.class); + + Mockito.when(client1.invokeMethod("appId", "methodName", "body", HttpExtension.POST)) + .thenReturn(Mono.empty()); + Mockito.when(client2.invokeMethod("appId", "methodName", "body", HttpExtension.POST)) + .thenReturn(Mono.empty()); + + DaprClient proxy = new DaprClientProxy(client1, client2); + proxy.invokeMethod("appId", "methodName", "body", HttpExtension.POST).block(); + + Mockito.verify(client1, times(0)) + .invokeMethod("appId", "methodName", "body", HttpExtension.POST); + Mockito.verify(client2, times(1)) + .invokeMethod("appId", "methodName", "body", HttpExtension.POST); + } + + @Test + public void closeAllClients() throws Exception { + DaprClient client1 = Mockito.mock(DaprClient.class); + DaprClient client2 = Mockito.mock(DaprClient.class); + + DaprClient proxy = new DaprClientProxy(client1, client2); + proxy.close(); + + Mockito.verify(client1, times(1)).close(); + Mockito.verify(client2, times(1)).close(); + } + + @Test + public void closeSingleClient() throws Exception { + DaprClient client1 = Mockito.mock(DaprClient.class); + + DaprClient proxy = new DaprClientProxy(client1); + proxy.close(); + + Mockito.verify(client1, times(1)).close(); + } + +} \ No newline at end of file diff --git a/sdk/src/test/java/io/dapr/client/DaprHttpStub.java b/sdk/src/test/java/io/dapr/client/DaprHttpStub.java index c8dd83d093..c5a884cb33 100644 --- a/sdk/src/test/java/io/dapr/client/DaprHttpStub.java +++ b/sdk/src/test/java/io/dapr/client/DaprHttpStub.java @@ -8,7 +8,6 @@ import io.opentelemetry.context.Context; import reactor.core.publisher.Mono; -import java.io.IOException; import java.util.Map; /** @@ -33,7 +32,7 @@ public DaprHttpStub() { * {@inheritDoc} */ @Override - public Mono invokeApi(String method, String urlString, Map urlParameters, Map headers, Context context) { + public Mono invokeApi(String method, String[] pathSegments, Map urlParameters, Map headers, Context context) { return Mono.empty(); } @@ -41,7 +40,7 @@ public Mono invokeApi(String method, String urlString, Map invokeApi(String method, String urlString, Map urlParameters, String content, Map headers, Context context) { + public Mono invokeApi(String method, String[] pathSegments, Map urlParameters, String content, Map headers, Context context) { return Mono.empty(); } @@ -49,7 +48,7 @@ public Mono invokeApi(String method, String urlString, Map invokeApi(String method, String urlString, Map urlParameters, byte[] content, Map headers, Context context) { + public Mono invokeApi(String method, String[] pathSegments, Map urlParameters, byte[] content, Map headers, Context context) { 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 05c080da03..bffb461e58 100644 --- a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java @@ -32,6 +32,8 @@ public class DaprHttpTest { @Rule public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); + private static final String STATE_PATH = DaprHttp.API_VERSION + "/state"; + private static final String EXPECTED_RESULT = "{\"data\":\"ewoJCSJwcm9wZXJ0eUEiOiAidmFsdWVBIiwKCQkicHJvcGVydHlCIjogInZhbHVlQiIKCX0=\"}"; @@ -42,7 +44,7 @@ public class DaprHttpTest { private ObjectSerializer serializer = new ObjectSerializer(); @Before - public void setUp() throws Exception { + public void setUp() { mockInterceptor = new MockInterceptor(Behavior.UNORDERED); okHttpClient = new OkHttpClient.Builder().addInterceptor(mockInterceptor).build(); } @@ -57,7 +59,7 @@ public void invokeApi_daprApiToken_present() throws IOException { assertEquals("xyz", Properties.API_TOKEN.get()); DaprHttp daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3500, okHttpClient); Mono mono = - daprHttp.invokeApi("POST", "v1.0/state", null, (byte[]) null, null, Context.current()); + daprHttp.invokeApi("POST", "v1.0/state".split("/"), null, (byte[]) null, null, Context.current()); DaprHttp.Response response = mono.block(); String body = serializer.deserialize(response.getBody(), String.class); assertEquals(EXPECTED_RESULT, body); @@ -73,7 +75,7 @@ public void invokeApi_daprApiToken_absent() throws IOException { assertNull(Properties.API_TOKEN.get()); DaprHttp daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3500, okHttpClient); Mono mono = - daprHttp.invokeApi("POST", "v1.0/state", null, (byte[]) null, null, Context.current()); + daprHttp.invokeApi("POST", "v1.0/state".split("/"), null, (byte[]) null, null, Context.current()); DaprHttp.Response response = mono.block(); String body = serializer.deserialize(response.getBody(), String.class); assertEquals(EXPECTED_RESULT, body); @@ -89,7 +91,7 @@ public void invokeMethod() throws IOException { .respond(serializer.serialize(EXPECTED_RESULT)); DaprHttp daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3500, okHttpClient); Mono mono = - daprHttp.invokeApi("POST", "v1.0/state", null, (byte[]) null, headers, Context.current()); + daprHttp.invokeApi("POST", "v1.0/state".split("/"), null, (byte[]) null, headers, Context.current()); DaprHttp.Response response = mono.block(); String body = serializer.deserialize(response.getBody(), String.class); assertEquals(EXPECTED_RESULT, body); @@ -103,7 +105,7 @@ public void invokePostMethod() throws IOException { .addHeader("Header", "Value"); DaprHttp daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3500, okHttpClient); Mono mono = - daprHttp.invokeApi("POST", "v1.0/state", null, "", null, Context.current()); + daprHttp.invokeApi("POST", "v1.0/state".split("/"), null, "", null, Context.current()); DaprHttp.Response response = mono.block(); String body = serializer.deserialize(response.getBody(), String.class); assertEquals(EXPECTED_RESULT, body); @@ -116,7 +118,7 @@ public void invokeDeleteMethod() throws IOException { .respond(serializer.serialize(EXPECTED_RESULT)); DaprHttp daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3500, okHttpClient); Mono mono = - daprHttp.invokeApi("DELETE", "v1.0/state", null, (String) null, null, Context.current()); + daprHttp.invokeApi("DELETE", "v1.0/state".split("/"), null, (String) null, null, Context.current()); DaprHttp.Response response = mono.block(); String body = serializer.deserialize(response.getBody(), String.class); assertEquals(EXPECTED_RESULT, body); @@ -128,7 +130,7 @@ public void invokeGetMethod() throws IOException { .get("http://127.0.0.1:3500/v1.0/get") .respond(serializer.serialize(EXPECTED_RESULT)); DaprHttp daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3500, okHttpClient); - Mono mono = daprHttp.invokeApi("GET", "v1.0/get", null, null, Context.current()); + Mono mono = daprHttp.invokeApi("GET", "v1.0/get".split("/"), null, null, Context.current()); DaprHttp.Response response = mono.block(); String body = serializer.deserialize(response.getBody(), String.class); assertEquals(EXPECTED_RESULT, body); @@ -146,7 +148,7 @@ public void invokeMethodWithHeaders() throws IOException { .respond(serializer.serialize(EXPECTED_RESULT)); DaprHttp daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3500, okHttpClient); Mono mono = - daprHttp.invokeApi("GET", "v1.0/state/order", urlParameters, headers, Context.current()); + daprHttp.invokeApi("GET", "v1.0/state/order".split("/"), urlParameters, headers, Context.current()); DaprHttp.Response response = mono.block(); String body = serializer.deserialize(response.getBody(), String.class); assertEquals(EXPECTED_RESULT, body); @@ -159,7 +161,7 @@ public void invokePostMethodRuntime() throws IOException { .respond(500); DaprHttp daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3500, okHttpClient); Mono mono = - daprHttp.invokeApi("POST", "v1.0/state", null, null, Context.current()); + daprHttp.invokeApi("POST", "v1.0/state".split("/"), null, null, Context.current()); DaprHttp.Response response = mono.block(); String body = serializer.deserialize(response.getBody(), String.class); assertEquals(EXPECTED_RESULT, body); @@ -173,7 +175,7 @@ public void invokePostDaprError() throws IOException { .respond(500, ResponseBody.create(MediaType.parse("text"), "{\"errorCode\":null,\"message\":null}")); DaprHttp daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3500, okHttpClient); - Mono mono = daprHttp.invokeApi("POST", "v1.0/state", null, null, Context.current()); + Mono mono = daprHttp.invokeApi("POST", "v1.0/state".split("/"), null, null, Context.current()); DaprHttp.Response response = mono.block(); String body = serializer.deserialize(response.getBody(), String.class); assertEquals(EXPECTED_RESULT, body); @@ -186,7 +188,7 @@ public void invokePostMethodUnknownError() throws IOException { .respond(500, ResponseBody.create(MediaType.parse("application/json"), "{\"errorCode\":\"null\",\"message\":\"null\"}")); DaprHttp daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3500, okHttpClient); - Mono mono = daprHttp.invokeApi("POST", "v1.0/state", null, null, Context.current()); + Mono mono = daprHttp.invokeApi("POST", "v1.0/state".split("/"), null, null, Context.current()); DaprHttp.Response response = mono.block(); String body = serializer.deserialize(response.getBody(), String.class); assertEquals(EXPECTED_RESULT, body); @@ -215,8 +217,8 @@ public void invokePostMethodUnknownError() throws IOException { public void testCallbackCalledAtTheExpectedTimeTest() throws IOException { String deletedStateKey = "deletedKey"; String existingState = "existingState"; - String urlDeleteState = DaprClientHttp.STATE_PATH + "/" + deletedStateKey; - String urlExistingState = DaprClientHttp.STATE_PATH + "/" + existingState; + String urlDeleteState = STATE_PATH + "/" + deletedStateKey; + String urlExistingState = STATE_PATH + "/" + existingState; mockInterceptor.addRule() .get("http://127.0.0.1:3500/" + urlDeleteState) .respond(200, ResponseBody.create(MediaType.parse("application/json"), @@ -229,11 +231,11 @@ public void testCallbackCalledAtTheExpectedTimeTest() throws IOException { .respond(200, ResponseBody.create(MediaType.parse("application/json"), serializer.serialize(existingState))); DaprHttp daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3500, okHttpClient); - Mono response = daprHttp.invokeApi("GET", urlExistingState, null, null, Context.current()); + Mono response = daprHttp.invokeApi("GET", urlExistingState.split("/"), null, null, Context.current()); assertEquals(existingState, serializer.deserialize(response.block().getBody(), String.class)); - Mono responseDeleted = daprHttp.invokeApi("GET", urlDeleteState, null, null, Context.current()); + Mono responseDeleted = daprHttp.invokeApi("GET", urlDeleteState.split("/"), null, null, Context.current()); Mono responseDeleteKey = - daprHttp.invokeApi("DELETE", urlDeleteState, null, null, Context.current()); + daprHttp.invokeApi("DELETE", urlDeleteState.split("/"), null, null, Context.current()); assertNull(serializer.deserialize(responseDeleteKey.block().getBody(), String.class)); mockInterceptor.reset(); mockInterceptor.addRule() diff --git a/sdk/src/test/java/io/dapr/client/domain/StateTest.java b/sdk/src/test/java/io/dapr/client/domain/StateTest.java index 5cc955d047..68a08c9392 100644 --- a/sdk/src/test/java/io/dapr/client/domain/StateTest.java +++ b/sdk/src/test/java/io/dapr/client/domain/StateTest.java @@ -2,13 +2,13 @@ import org.junit.Test; +import java.util.HashMap; +import java.util.Map; + import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertNotEquals; - -import java.util.HashMap; -import java.util.Map; public class StateTest { diff --git a/sdk/src/test/java/io/dapr/runtime/DaprRuntimeTest.java b/sdk/src/test/java/io/dapr/runtime/DaprRuntimeTest.java index 6a4ca4a8e5..8685547735 100644 --- a/sdk/src/test/java/io/dapr/runtime/DaprRuntimeTest.java +++ b/sdk/src/test/java/io/dapr/runtime/DaprRuntimeTest.java @@ -8,8 +8,8 @@ import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerator; import io.dapr.client.DaprClient; -import io.dapr.client.DaprClientHttp; import io.dapr.client.DaprClientTestBuilder; +import io.dapr.client.DaprHttp; import io.dapr.client.DaprHttpStub; import io.dapr.client.domain.CloudEvent; import io.dapr.client.domain.HttpExtension; @@ -49,6 +49,10 @@ public class DaprRuntimeTest { private static final String METHOD_NAME = "mymethod"; + private static final String INVOKE_PATH = DaprHttp.API_VERSION + "/invoke"; + + private static final String PUBLISH_PATH = DaprHttp.API_VERSION + "/publish"; + private final DaprRuntime daprRuntime = Dapr.getInstance(); @Before @@ -121,10 +125,10 @@ public void pubSubHappyCase() throws Exception { for (Message message : messages) { when(daprHttp.invokeApi( eq("POST"), - eq(DaprClientHttp.PUBLISH_PATH + "/" + PUBSUB_NAME + "/" + TOPIC_NAME), + eq((PUBLISH_PATH + "/" + PUBSUB_NAME + "/" + TOPIC_NAME).split("/")), any(), eq(serializer.serialize(message.data)), - eq(null), + any(), any())) .thenAnswer(invocationOnMock -> this.daprRuntime.handleInvocation( TOPIC_NAME, @@ -209,7 +213,7 @@ public void invokeHappyCase() throws Exception { when(daprHttp.invokeApi( eq("POST"), - eq(DaprClientHttp.INVOKE_PATH + "/" + APP_ID + "/method/" + METHOD_NAME), + eq((INVOKE_PATH + "/" + APP_ID + "/method/" + METHOD_NAME).split("/")), any(), eq(serializer.serialize(message.data)), any(), @@ -220,7 +224,7 @@ public void invokeHappyCase() throws Exception { serializer.serialize(message.data), message.metadata) .map(r -> new DaprHttpStub.ResponseStub(r, null, 200))); - Mono response = client.invokeService(APP_ID, METHOD_NAME, message.data, HttpExtension.POST, + Mono response = client.invokeMethod(APP_ID, METHOD_NAME, message.data, HttpExtension.POST, message.metadata, byte[].class); Assert.assertArrayEquals(expectedResponse, response.block()); diff --git a/sdk/src/test/java/io/dapr/serializer/DefaultObjectSerializerTest.java b/sdk/src/test/java/io/dapr/serializer/DefaultObjectSerializerTest.java index 0a380bdb83..7cdd9ecc6a 100644 --- a/sdk/src/test/java/io/dapr/serializer/DefaultObjectSerializerTest.java +++ b/sdk/src/test/java/io/dapr/serializer/DefaultObjectSerializerTest.java @@ -12,9 +12,11 @@ import java.io.IOException; import java.io.Serializable; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Base64; import java.util.List; +import java.util.TreeMap; import java.util.function.Function; import static org.junit.Assert.assertEquals; @@ -233,6 +235,17 @@ public void serializeObjectTest() { } catch (IOException exception) { fail(exception.getMessage()); } + + try { + serializedValue = SERIALIZER.serialize(obj); + assertNotNull(serializedValue); + Type t = MyObjectTestToSerialize.class; + TypeRef tr = TypeRef.get(t); + MyObjectTestToSerialize deserializedValue = SERIALIZER.deserialize(serializedValue, tr); + assertEquals(obj, deserializedValue); + } catch (IOException exception) { + fail(exception.getMessage()); + } } @Test @@ -424,6 +437,16 @@ public void deserializeArrayObjectTest() { } catch (IOException exception) { fail(exception.getMessage()); } + + try { + TypeRef> tr1 = new TypeRef>(){}; + Type t = tr1.getType(); + TypeRef tr = TypeRef.get(t); + result = (List) SERIALIZER.deserialize(jsonToDeserialize.getBytes(), tr); + assertEquals("The expected value is different than the actual result", expectedResult, result.get(0)); + } catch (IOException exception) { + fail(exception.getMessage()); + } } @Test @@ -780,7 +803,7 @@ public void serializeDeserializeCloudEventEnvelope() throws Exception { public void deserializeCloudEventEnvelopeData() throws Exception { - Function deserializeData = (jsonData -> { + Function deserializeData = (jsonData -> { try { String payload = String.format("{\"data\": %s}", jsonData); return CloudEvent.deserialize(payload.getBytes()).getData(); @@ -789,26 +812,28 @@ public void deserializeCloudEventEnvelopeData() throws Exception { } }); - assertEquals("123", - deserializeData.apply("123")); - assertEquals("true", - deserializeData.apply("true")); - assertEquals("123.45", - deserializeData.apply("123.45")); + assertEquals(123, + deserializeData.apply("123")); + assertEquals(true, + deserializeData.apply("true")); + assertEquals(123.45, + deserializeData.apply("123.45")); assertEquals("AAEI", - deserializeData.apply(quote(Base64.getEncoder().encodeToString(new byte[] { 0, 1, 8})))); + deserializeData.apply(quote(Base64.getEncoder().encodeToString(new byte[]{0, 1, 8})))); assertEquals("hello world", - deserializeData.apply(quote("hello world"))); + deserializeData.apply(quote("hello world"))); assertEquals("\"hello world\"", - deserializeData.apply(quote("\\\"hello world\\\""))); + deserializeData.apply(quote("\\\"hello world\\\""))); assertEquals("\"hello world\"", - deserializeData.apply(new ObjectMapper().writeValueAsString("\"hello world\""))); + deserializeData.apply(new ObjectMapper().writeValueAsString("\"hello world\""))); assertEquals("hello world", - deserializeData.apply(new ObjectMapper().writeValueAsString("hello world"))); - assertEquals("{\"id\":\"123:\",\"name\":\"Jon Doe\"}", - deserializeData.apply("{\"id\": \"123:\", \"name\": \"Jon Doe\"}")); - assertEquals("{\"id\": \"123:\", \"name\": \"Jon Doe\"}", - deserializeData.apply(new ObjectMapper().writeValueAsString("{\"id\": \"123:\", \"name\": \"Jon Doe\"}"))); + deserializeData.apply(new ObjectMapper().writeValueAsString("hello world"))); + assertEquals(new TreeMap() {{ + put("id", "123"); + put("name", "Jon Doe"); + }}, deserializeData.apply("{\"id\": \"123\", \"name\": \"Jon Doe\"}")); + assertEquals("{\"id\": \"123\", \"name\": \"Jon Doe\"}", + deserializeData.apply(new ObjectMapper().writeValueAsString("{\"id\": \"123\", \"name\": \"Jon Doe\"}"))); } @Test diff --git a/sdk/src/test/java/io/dapr/utils/TestUtils.java b/sdk/src/test/java/io/dapr/utils/TestUtils.java index d29a77be61..7c1ecaf2ae 100644 --- a/sdk/src/test/java/io/dapr/utils/TestUtils.java +++ b/sdk/src/test/java/io/dapr/utils/TestUtils.java @@ -9,6 +9,9 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.function.Executable; +import java.io.IOException; +import java.net.ServerSocket; + public final class TestUtils { private TestUtils() {} @@ -46,4 +49,11 @@ public static void assertThrowsDaprException( Assertions.assertEquals(expectedErrorCode, daprException.getErrorCode()); Assertions.assertEquals(expectedErrorMessage, daprException.getMessage()); } + + public static int findFreePort() throws IOException { + try (ServerSocket socket = new ServerSocket(0)) { + socket.setReuseAddress(true); + return socket.getLocalPort(); + } + } }