diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 7c73e5d3e..850edd7da 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -100,10 +100,6 @@ jobs: echo "PATH=$PATH:$HOME/.local/bin" >> $GITHUB_ENV pip3 install setuptools wheel pip3 install mechanical-markdown - - name: Install Local mongo database using docker-compose - run: | - docker-compose -f ./sdk-tests/deploy/local-test.yml up -d mongo - docker ps - name: Clean up files run: ./mvnw clean - name: Build sdk @@ -146,14 +142,10 @@ jobs: working-directory: ./examples run: | mm.py ./src/main/java/io/dapr/examples/unittesting/README.md - - name: Validate Configuration gRPC API example + - name: Validate Configuration API example working-directory: ./examples run: | - mm.py ./src/main/java/io/dapr/examples/configuration/grpc/README.md - - name: Validate Configuration HTTP API example - working-directory: ./examples - run: | - mm.py ./src/main/java/io/dapr/examples/configuration/http/README.md + mm.py ./src/main/java/io/dapr/examples/configuration/README.md - name: Validate actors example working-directory: ./examples run: | diff --git a/README.md b/README.md index feaada85b..9c0efdd5d 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ Try the following examples to learn more about Dapr's Java SDK: * [Binding with input over Http](./examples/src/main/java/io/dapr/examples/bindings/http) * [Actors](./examples/src/main/java/io/dapr/examples/actors/) * [Secrets management](./examples/src/main/java/io/dapr/examples/secrets) +* [Configuration](./examples/src/main/java/io/dapr/examples/configuration) * [Distributed tracing with OpenTelemetry SDK](./examples/src/main/java/io/dapr/examples/tracing) * [Exception handling](./examples/src/main/java/io/dapr/examples/exception) * [Unit testing](./examples/src/main/java/io/dapr/examples/unittesting) diff --git a/examples/src/main/java/io/dapr/examples/OpenTelemetryInterceptor.java b/examples/src/main/java/io/dapr/examples/OpenTelemetryInterceptor.java index 4b62eb677..cc250113d 100644 --- a/examples/src/main/java/io/dapr/examples/OpenTelemetryInterceptor.java +++ b/examples/src/main/java/io/dapr/examples/OpenTelemetryInterceptor.java @@ -16,15 +16,15 @@ package io.dapr.examples; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.context.Context; import io.opentelemetry.context.propagation.TextMapPropagator; +import jakarta.servlet.DispatcherType; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; 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; -import jakarta.servlet.DispatcherType; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.util.Collections; @Component 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 552e92759..6324144ed 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 @@ -54,7 +54,7 @@ Run `dapr init` to initialize Dapr in Self-Hosted Mode if it's not already initi Before getting into the application code, follow these steps in order to set up a local instance of Kafka. This is needed for the local instances. -1. Run the container locally: +1. Run the Kafka locally: ```bash -dapr run --components-path ./components/configuration --app-id configgrpc --log-level debug -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.configuration.grpc.ConfigurationClient +dapr run --components-path ./components/configuration --app-id configgrpc --log-level debug -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.configuration.ConfigurationClient ``` diff --git a/examples/src/main/java/io/dapr/examples/configuration/http/ConfigurationClient.java b/examples/src/main/java/io/dapr/examples/configuration/http/ConfigurationClient.java deleted file mode 100644 index de1960737..000000000 --- a/examples/src/main/java/io/dapr/examples/configuration/http/ConfigurationClient.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2022 The Dapr Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io.dapr.examples.configuration.http; - -import io.dapr.client.DaprApiProtocol; -import io.dapr.client.DaprClient; -import io.dapr.client.DaprClientBuilder; -import io.dapr.client.domain.ConfigurationItem; -import io.dapr.client.domain.GetConfigurationRequest; -import io.dapr.client.domain.SubscribeConfigurationRequest; -import io.dapr.client.domain.SubscribeConfigurationResponse; -import io.dapr.config.Properties; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class ConfigurationClient { - - private static final String CONFIG_STORE_NAME = "configstore"; - private static String SUBSCRIPTION_ID; - - /** - * Executes various methods to check the different apis. - * @param args arguments - * @throws Exception throws Exception - */ - public static void main(String[] args) throws Exception { - System.getProperties().setProperty(Properties.API_PROTOCOL.getName(), DaprApiProtocol.HTTP.name()); - try (DaprClient client = (new DaprClientBuilder()).build()) { - System.out.println("Using Dapr client..."); - getConfigurations(client); - subscribeConfigurationRequest(client); - } - } - - /** - * Gets configurations for a list of keys. - * - * @param client DaprClient object - */ - public static void getConfigurations(DaprClient client) { - System.out.println("*******trying to retrieve configurations for a list of keys********"); - List keys = new ArrayList<>(); - keys.add("myconfig1"); - keys.add("myconfig2"); - keys.add("myconfig3"); - - Map hmap = new HashMap<>(); - hmap.put("meta_key","meta_value"); - GetConfigurationRequest req = new GetConfigurationRequest(CONFIG_STORE_NAME, keys); - req.setMetadata(hmap); - - try { - Mono> items = client.getConfiguration(req); - items.block().forEach((k,v) -> print(v, k)); - } catch (Exception ex) { - System.out.println(ex.getMessage()); - } - } - - /** - * Subscribe to a list of keys. - * - * @param client DaprClient object - */ - public static void subscribeConfigurationRequest(DaprClient client) throws InterruptedException { - System.out.println("Subscribing to key: myconfig2"); - SubscribeConfigurationRequest req = new SubscribeConfigurationRequest( - CONFIG_STORE_NAME, Collections.singletonList("myconfig2")); - Flux outFlux = client.subscribeConfiguration(req); - outFlux.subscribe( - cis -> { - SUBSCRIPTION_ID = cis.getSubscriptionId(); - }); - if (!SUBSCRIPTION_ID.isEmpty()) { - System.out.println("subscribing to myconfig2 is successful"); - } else { - System.out.println("error in subscribing to myconfig2"); - } - Thread.sleep(5000); - } - - private static void print(ConfigurationItem item, String key) { - System.out.println(item.getValue() + " : key ->" + key); - } -} diff --git a/examples/src/main/java/io/dapr/examples/configuration/http/ConfigurationHandler.java b/examples/src/main/java/io/dapr/examples/configuration/http/ConfigurationHandler.java deleted file mode 100644 index 370318528..000000000 --- a/examples/src/main/java/io/dapr/examples/configuration/http/ConfigurationHandler.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2022 The Dapr Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io.dapr.examples.configuration.http; - -import io.dapr.client.domain.SubscribeConfigurationResponse; -import io.dapr.examples.DaprApplication; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.Options; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -/** - * A sample springboot application to register and receive for updates on configuration items sent by Dapr. - * Users are free to write their own controllers to handle any specific route suited to the need. - * java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.configuration.http.ConfigurationSubscriber -p 3009 - */ -@RestController -public class ConfigurationHandler { - - /** - * Receives a subscription change notification. - * @param configStore Path variables for post call - * @param key Key whose value has changed - * @param response Configuration response - */ - @PostMapping(path = "/configuration/{configStore}/{key}", produces = MediaType.ALL_VALUE) - public void handleConfigUpdate(@PathVariable("configStore") String configStore, - @PathVariable("key") String key, - @RequestBody SubscribeConfigurationResponse response) { - System.out.println("Configuration update received for store: " + configStore); - response.getItems().forEach((k,v) -> System.out.println("Key: " + k + " Value :" + v.getValue())); - } - - /** - * This is entry point for Configuration Subscriber service. - * @param args Arguments for main - * @throws Exception Throws Exception - */ - public static void main(String[] args) throws Exception { - Options options = new Options(); - options.addRequiredOption("p", "port", true, "The port this app will listen on"); - CommandLineParser parser = new DefaultParser(); - CommandLine cmd = parser.parse(options, args); - // If port string is not valid, it will throw an exception. - int port = Integer.parseInt(cmd.getOptionValue("port")); - DaprApplication.start(port); - } -} diff --git a/examples/src/main/java/io/dapr/examples/configuration/http/README.md b/examples/src/main/java/io/dapr/examples/configuration/http/README.md deleted file mode 100644 index 21bd50b60..000000000 --- a/examples/src/main/java/io/dapr/examples/configuration/http/README.md +++ /dev/null @@ -1,218 +0,0 @@ -## Retrieve Configurations via Configuration API - -This example provides the different capabilities provided by Dapr Java SDK for Configuration. For further information about Configuration APIs please refer to [this link](https://docs.dapr.io/developing-applications/building-blocks/configuration/) - -### Using the ConfigurationAPI - -The java SDK exposes several methods for this - -* `client.getConfiguration(...)` for getting a configuration for a single/multiple keys. -* `client.subscribeConfiguration(...)` for subscribing to a list of keys for any change. -* `client.unsubscribeConfiguration(...)` for unsubscribing to changes from subscribed items. - -## Pre-requisites - -* [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/). -* Java JDK 11 (or greater): - * [Microsoft JDK 11](https://docs.microsoft.com/en-us/java/openjdk/download#openjdk-11) - * [Oracle JDK 11](https://www.oracle.com/technetwork/java/javase/downloads/index.html#JDK11) - * [OpenJDK 11](https://jdk.java.net/11/) -* [Apache Maven](https://maven.apache.org/install.html) version 3.x. - -### Checking out the code - -Clone this repository: - -```sh -git clone https://github.com/dapr/java-sdk.git -cd java-sdk -``` - -Then build the Maven project: - -```sh -# make sure you are in the `java-sdk` directory. -mvn install -``` - -Then get into the examples directory: - -```sh -cd examples -``` - -### Initialize Dapr - -Run `dapr init` to initialize Dapr in Self-Hosted Mode if it's not already initialized. - -## Store few dummy configurations in configurationstore - - -```bash -docker exec dapr_redis redis-cli MSET myconfig1 "val1||1" myconfig2 "val2||1" myconfig3 "val3||1" -``` - - -### Running the example - -This example uses the Java SDK Dapr client in order to **Get, Subscribe and Unsubscribe** from configuration items and utilizes `Redis` as configuration store. -`ConfigurationClient.java` is the example class demonstrating all 3 features. -Check [DaprClient.java](https://github.com/dapr/java-sdk/blob/master/sdk/src/main/java/io/dapr/client/DaprClient.java) for detailed description of the supported APIs. - -```java -public class ConfigurationClient { - // ... - /** - * Executes various methods to check the different apis. - * @param args arguments - * @throws Exception throws Exception - */ - public static void main(String[] args) throws Exception { - System.getProperties().setProperty(Properties.API_PROTOCOL.getName(), DaprApiProtocol.HTTP.name()); - try (DaprClient client = (new DaprClientBuilder()).build()) { - System.out.println("Using Dapr client..."); - getConfigurations(client); - subscribeConfigurationRequest(client); - } - } - - /** - * Gets configurations for a list of keys. - * - * @param client DaprClient object - */ - public static void getConfigurations(DaprClient client) { - System.out.println("*******trying to retrieve configurations for a list of keys********"); - GetConfigurationRequest req = new GetConfigurationRequest(CONFIG_STORE_NAME, keys); - try { - Mono> items = client.getConfiguration(req); - // ... - } catch (Exception ex) { - // ... - } - } - - /** - * Subscribe to a list of keys. - * - * @param client DaprClient object - */ - public static void subscribeConfigurationRequest(DaprClient client) { - // ... - SubscribeConfigurationRequest req = new SubscribeConfigurationRequest( - CONFIG_STORE_NAME, Collections.singletonList("myconfig2")); - Runnable subscribeTask = () -> { - Flux outFlux = client.subscribeConfiguration(req); - // ... - }; - // .. - } -} -``` - -Get into the examples' directory: -```sh -cd examples -``` - -#### Running the configuration subscriber app: - -`DaprApplication.start()` Method will run a Spring Boot application containing a `ConfigurationHandler`, a contoller -to receive configuration change notifications. - -```java -@RestController -public class ConfigurationHandler { - //... - @PostMapping(path = "/configuration/{configStore}/{key}", produces = MediaType.ALL_VALUE) - public void handleConfigUpdate(@PathVariable("configStore") String configStore, - @PathVariable("key") String key, - @RequestBody SubscribeConfigurationResponse response) { - System.out.println("Configuration update received for store: " + configStore); - response.getItems().forEach((k,v) -> System.out.println("Key: " + k + " Value :" + v.getValue())); - } - //.... -} -``` -Execute the following script to run the ConfigSubscriber app: - - - -```bash -dapr run --app-id confighandler -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.configuration.http.ConfigurationHandler -p 3009 -``` - - -#### Running the ConfigurationClient app: - -Use the following command to run this example- - - - -```bash -dapr run --components-path ./components/configuration --app-id confighttp --log-level debug --app-port 3009 --dapr-http-port 3500 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.configuration.http.ConfigurationClient -``` - -#### Update myconfig2 key in configurationstore - - - - -```bash -docker exec dapr_redis redis-cli MSET myconfig2 "updated_val2||1" -``` - - -### Sample output -``` -== APP == Using Dapr client... -== APP == *******trying to retrieve configurations for a list of keys******** -== APP == val1 : key ->myconfig1 -== APP == val2 : key ->myconfig2 -== APP == val3 : key ->myconfig3 -== APP == Subscribing to key: myconfig2 -== APP == subscribing to myconfig2 is successful -``` -### Cleanup - -To stop the app, run (or press CTRL+C): - - - -```bash -dapr stop --app-id confighttp -dapr stop --app-id confighandler -``` - - 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 7eeb50fae..8105a0664 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 @@ -13,17 +13,13 @@ limitations under the License. package io.dapr.examples.invoke.grpc; +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; import io.dapr.examples.DaprExamplesProtos.HelloReply; import io.dapr.examples.DaprExamplesProtos.HelloRequest; import io.dapr.examples.HelloWorldGrpc; -import io.grpc.Grpc; -import io.grpc.InsecureChannelCredentials; -import io.grpc.ManagedChannel; -import io.grpc.Metadata; import io.grpc.StatusRuntimeException; -import io.grpc.stub.MetadataUtils; -import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; @@ -45,22 +41,11 @@ public class HelloWorldClient { * @param args Array of messages to be sent. */ public static void main(String[] args) throws Exception { - String user = "World"; - String target = "localhost:" + System.getenv("DAPR_GRPC_PORT"); - - ManagedChannel channel = Grpc.newChannelBuilder(target, InsecureChannelCredentials.create()) - .build(); - - try { - HelloWorldGrpc.HelloWorldBlockingStub blockingStub = HelloWorldGrpc.newBlockingStub(channel); - - Metadata headers = new Metadata(); - headers.put(Metadata.Key.of("dapr-app-id", Metadata.ASCII_STRING_MARSHALLER), - "hellogrpc"); - - // MetadataUtils.attachHeaders is deprecated. - blockingStub = blockingStub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(headers)); + try (DaprClient client = new DaprClientBuilder().build()) { + HelloWorldGrpc.HelloWorldBlockingStub blockingStub = client.newGrpcStub( + "hellogrpc", + channel -> HelloWorldGrpc.newBlockingStub(channel)); logger.info("Will try to greet " + user + " ..."); try { @@ -70,10 +55,6 @@ public class HelloWorldClient { } catch (StatusRuntimeException e) { logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); } - } finally { - // To prevent leaking resources like threads and TCP connections - // the channel should be shut down when it will no longer be used. - channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS); } } } 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 eb1cdd23e..5da82d536 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 @@ -55,7 +55,7 @@ public class HelloWorldService { /** * Handling of the 'sayHello' method. * - * @param request Request to say something. + * @param req Request to say something. * @return Response with when it was said. */ @Override 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 0dd26012c..25588979c 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 @@ -61,7 +61,7 @@ In the `HelloWorldService.java` file, you will find the `HelloWorldService` clas /** * Handling of the 'sayHello' method. * - * @param request Request to say something. + * @param req Request to say something. * @return Response with when it was said. */ @Override @@ -93,27 +93,17 @@ The `app-id` argument is used to identify this service in Dapr's runtime. The `a ### Running the example's client -The other component is the client. It will add user name to the grpc request and send it to the server. Open the `HelloWorldClient.java` file, it creates a new grpc channel and sends request directly to the dapr side car through this channel. +The other component is the client. It will add user name to the grpc request and send it to the server. Open the `HelloWorldClient.java` file, it uses the DaprClient's grpc channel and sends request directly to the dapr side car through it, including necessary headers. ```java private static class HelloWorldClient { ///... public static void main(String[] args) throws Exception { - String user = "World"; - // Access a service running on the local machine on port 50051 - String target = "localhost:50051"; - - ManagedChannel channel = Grpc.newChannelBuilder(target, InsecureChannelCredentials.create()) - .build(); - - try { - HelloWorldGrpc.HelloWorldBlockingStub blockingStub = HelloWorldGrpc.newBlockingStub(channel); - - Metadata headers = new Metadata(); - headers.put(Metadata.Key.of("dapr-app-id", Metadata.ASCII_STRING_MARSHALLER), - "hellogrpc"); - blockingStub = MetadataUtils.attachHeaders(blockingStub, headers); + try (DaprClient client = new DaprClientBuilder().build()) { + HelloWorldGrpc.HelloWorldBlockingStub blockingStub = HelloWorldGrpc.newBlockingStub(client.getGrpcChannel()); + // Adds Dapr interceptors to populate gRPC metadata automatically. + blockingStub = DaprClientGrpcInterceptors.intercept("hellogrpc", blockingStub); logger.info("Will try to greet " + user + " ..."); try { @@ -123,10 +113,6 @@ private static class HelloWorldClient { } catch (StatusRuntimeException e) { logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); } - } finally { - // To prevent leaking resources like threads and TCP connections - // the channel should be shut down when it will no longer be used. - channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS); } } ///... diff --git a/examples/src/main/java/io/dapr/examples/lock/grpc/DistributedLockGrpcClient.java b/examples/src/main/java/io/dapr/examples/lock/DistributedLockGrpcClient.java similarity index 98% rename from examples/src/main/java/io/dapr/examples/lock/grpc/DistributedLockGrpcClient.java rename to examples/src/main/java/io/dapr/examples/lock/DistributedLockGrpcClient.java index b68b6e7e3..6d3d8247d 100644 --- a/examples/src/main/java/io/dapr/examples/lock/grpc/DistributedLockGrpcClient.java +++ b/examples/src/main/java/io/dapr/examples/lock/DistributedLockGrpcClient.java @@ -11,7 +11,7 @@ limitations under the License. */ -package io.dapr.examples.lock.grpc; +package io.dapr.examples.lock; import io.dapr.client.DaprClientBuilder; diff --git a/examples/src/main/java/io/dapr/examples/lock/grpc/README.md b/examples/src/main/java/io/dapr/examples/lock/README.md similarity index 97% rename from examples/src/main/java/io/dapr/examples/lock/grpc/README.md rename to examples/src/main/java/io/dapr/examples/lock/README.md index a98cf2245..f49cb4bf0 100644 --- a/examples/src/main/java/io/dapr/examples/lock/grpc/README.md +++ b/examples/src/main/java/io/dapr/examples/lock/README.md @@ -58,7 +58,7 @@ sleep: 5 --> ```bash -dapr run --components-path ./components/lock --app-id lockgrpc --log-level debug -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.lock.grpc.DistributedLockGrpcClient +dapr run --components-path ./components/lock --app-id lockgrpc --log-level debug -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.lock.DistributedLockGrpcClient ``` diff --git a/examples/src/main/java/io/dapr/examples/lock/http/DistributedLockHttpClient.java b/examples/src/main/java/io/dapr/examples/lock/http/DistributedLockHttpClient.java deleted file mode 100644 index 9c8b936de..000000000 --- a/examples/src/main/java/io/dapr/examples/lock/http/DistributedLockHttpClient.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2022 The Dapr Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io.dapr.examples.lock.http; - - -import io.dapr.client.DaprClientBuilder; -import io.dapr.client.DaprPreviewClient; -import io.dapr.client.domain.LockRequest; -import io.dapr.client.domain.UnlockRequest; -import io.dapr.client.domain.UnlockResponseStatus; -import reactor.core.publisher.Mono; - -/** - * DistributedLockGrpcClient. - */ -public class DistributedLockHttpClient { - private static final String LOCK_STORE_NAME = "lockstore"; - - /** - * Executes various methods to check the different apis. - * - * @param args arguments - * @throws Exception throws Exception - */ - public static void main(String[] args) throws Exception { - try (DaprPreviewClient client = (new DaprClientBuilder()).buildPreviewClient()) { - System.out.println("Using preview client..."); - tryLock(client); - unlock(client); - } - } - - /** - * Trying to get lock. - * - * @param client DaprPreviewClient object - */ - public static void tryLock(DaprPreviewClient client) { - System.out.println("*******trying to get a free distributed lock********"); - try { - LockRequest lockRequest = new LockRequest(LOCK_STORE_NAME, "resouce1", "owner1", 5); - Mono result = client.tryLock(lockRequest); - System.out.println("Lock result -> " + (Boolean.TRUE.equals(result.block()) ? "SUCCESS" : "FAIL")); - } catch (Exception ex) { - System.out.println(ex.getMessage()); - } - } - - /** - * Unlock a lock. - * - * @param client DaprPreviewClient object - */ - public static void unlock(DaprPreviewClient client) { - System.out.println("*******unlock a distributed lock********"); - try { - UnlockRequest unlockRequest = new UnlockRequest(LOCK_STORE_NAME, "resouce1", "owner1"); - Mono result = client.unlock(unlockRequest); - System.out.println("Unlock result ->" + result.block().name()); - } catch (Exception ex) { - System.out.println(ex.getMessage()); - } - } -} diff --git a/examples/src/main/java/io/dapr/examples/lock/http/README.md b/examples/src/main/java/io/dapr/examples/lock/http/README.md deleted file mode 100644 index d0a9c944f..000000000 --- a/examples/src/main/java/io/dapr/examples/lock/http/README.md +++ /dev/null @@ -1,87 +0,0 @@ -## Distributed Lock API Example - -This example provides the different capabilities provided by Dapr Java SDK for Distributed Lock. For further information about Distributed Lock APIs please refer to [this link](https://docs.dapr.io/developing-applications/building-blocks/distributed-lock/) -**This API is available in Preview Mode**. - -### Using the Distributed Lock API - -The java SDK exposes several methods for this - -* `client.tryLock(...)` for getting a free distributed lock -* `client.unlock(...)` for unlocking a lock - -## Pre-requisites - -* [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/). -* Java JDK 11 (or greater): - * [Microsoft JDK 11](https://docs.microsoft.com/en-us/java/openjdk/download#openjdk-11) - * [Oracle JDK 11](https://www.oracle.com/technetwork/java/javase/downloads/index.html#JDK11) - * [OpenJDK 11](https://jdk.java.net/11/) -* [Apache Maven](https://maven.apache.org/install.html) version 3.x. - -### Checking out the code - -Clone this repository: - -```sh -git clone https://github.com/dapr/java-sdk.git -cd java-sdk -``` - -Then build the Maven project: - -```sh -# make sure you are in the `java-sdk` directory. -mvn install -``` - - - -### Running the example - -Get into the examples' directory: -```sh -cd examples -``` - -Use the following command to run this example- - - - -```bash -dapr run --components-path ./components/lock --app-id lockhttp --log-level debug -- java -Ddapr.api.protocol=HTTP -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.lock.http.DistributedLockHttpClient -``` - - - -### Sample output -``` -== APP == Using preview client... -== APP == *******trying to get a free distributed lock******** -== APP == Lock result -> SUCCESS -== APP == *******unlock a distributed lock******** -== APP == Unlock result -> SUCCESS -``` -### Cleanup - -To stop the app, run (or press CTRL+C): - - - -```bash -dapr stop --app-id lockhttp -``` - - - diff --git a/examples/src/main/java/io/dapr/examples/querystate/README.md b/examples/src/main/java/io/dapr/examples/querystate/README.md index a7bae87d2..e6f25a0ef 100644 --- a/examples/src/main/java/io/dapr/examples/querystate/README.md +++ b/examples/src/main/java/io/dapr/examples/querystate/README.md @@ -36,6 +36,20 @@ cd examples Run `dapr init` to initialize Dapr in Self-Hosted Mode if it's not already initialized. +### Run MongoDB + + + +```bash +docker-compose -f ./src/main/java/io/dapr/examples/querystate/docker-compose-single-mongo.yml up -d +``` + + + + ### Running the State Client This example uses the Java SDK Dapr client in order to save bulk state and query state, in this case, an instance of a class. See the code snippets below: @@ -282,5 +296,16 @@ name: Cleanup ```bash dapr stop --app-id query-state-example ``` + + +Then, stop MongoDB container. + + + +```bash +docker-compose -f ./src/main/java/io/dapr/examples/querystate/docker-compose-single-mongo.yml down +``` diff --git a/examples/src/main/java/io/dapr/examples/querystate/docker-compose-single-mongo.yml b/examples/src/main/java/io/dapr/examples/querystate/docker-compose-single-mongo.yml new file mode 100644 index 000000000..bb17176df --- /dev/null +++ b/examples/src/main/java/io/dapr/examples/querystate/docker-compose-single-mongo.yml @@ -0,0 +1,6 @@ +version: '3' +services: + mongo: + image: mongo + ports: + - "27017:27017" \ No newline at end of file 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 ef42f34ca..b7839479d 100644 --- a/examples/src/main/java/io/dapr/examples/state/README.md +++ b/examples/src/main/java/io/dapr/examples/state/README.md @@ -36,6 +36,19 @@ cd examples Run `dapr init` to initialize Dapr in Self-Hosted Mode if it's not already initialized. +### Run MongoDB + + + +```bash +docker-compose -f ./src/main/java/io/dapr/examples/state/docker-compose-single-mongo.yml up -d +``` + + + ### Running the StateClient This example uses the Java SDK Dapr client in order to save, retrieve and delete a state, in this case, an instance of a class. Multiple state stores are supported since Dapr 0.4. See the code snippet bellow: @@ -206,3 +219,15 @@ dapr stop --app-id state-example ``` + +Then, stop MongoDB container. + + + +```bash +docker-compose -f ./src/main/java/io/dapr/examples/state/docker-compose-single-mongo.yml down +``` + + diff --git a/examples/src/main/java/io/dapr/examples/state/docker-compose-single-mongo.yml b/examples/src/main/java/io/dapr/examples/state/docker-compose-single-mongo.yml new file mode 100644 index 000000000..bb17176df --- /dev/null +++ b/examples/src/main/java/io/dapr/examples/state/docker-compose-single-mongo.yml @@ -0,0 +1,6 @@ +version: '3' +services: + mongo: + image: mongo + ports: + - "27017:27017" \ No newline at end of file diff --git a/examples/src/main/java/io/dapr/examples/workflows/chain/DemoChainClient.java b/examples/src/main/java/io/dapr/examples/workflows/chain/DemoChainClient.java index 810a365c3..1a190b4f8 100644 --- a/examples/src/main/java/io/dapr/examples/workflows/chain/DemoChainClient.java +++ b/examples/src/main/java/io/dapr/examples/workflows/chain/DemoChainClient.java @@ -16,7 +16,6 @@ package io.dapr.examples.workflows.chain; import io.dapr.workflows.client.DaprWorkflowClient; import io.dapr.workflows.client.WorkflowInstanceStatus; -import java.time.Duration; import java.util.concurrent.TimeoutException; public class DemoChainClient { diff --git a/examples/src/main/java/io/dapr/examples/workflows/continueasnew/DemoContinueAsNewClient.java b/examples/src/main/java/io/dapr/examples/workflows/continueasnew/DemoContinueAsNewClient.java index dbafb2ebb..a47edb6c3 100644 --- a/examples/src/main/java/io/dapr/examples/workflows/continueasnew/DemoContinueAsNewClient.java +++ b/examples/src/main/java/io/dapr/examples/workflows/continueasnew/DemoContinueAsNewClient.java @@ -14,6 +14,7 @@ limitations under the License. package io.dapr.examples.workflows.continueasnew; import io.dapr.workflows.client.DaprWorkflowClient; + import java.util.concurrent.TimeoutException; public class DemoContinueAsNewClient { diff --git a/examples/src/main/java/io/dapr/examples/workflows/externalevent/DemoExternalEventClient.java b/examples/src/main/java/io/dapr/examples/workflows/externalevent/DemoExternalEventClient.java index d7178cad7..adae11a99 100644 --- a/examples/src/main/java/io/dapr/examples/workflows/externalevent/DemoExternalEventClient.java +++ b/examples/src/main/java/io/dapr/examples/workflows/externalevent/DemoExternalEventClient.java @@ -14,6 +14,7 @@ limitations under the License. package io.dapr.examples.workflows.externalevent; import io.dapr.workflows.client.DaprWorkflowClient; + import java.util.concurrent.TimeoutException; public class DemoExternalEventClient { diff --git a/examples/src/main/java/io/dapr/examples/workflows/subworkflow/ReverseActivity.java b/examples/src/main/java/io/dapr/examples/workflows/subworkflow/ReverseActivity.java index 00d34382c..e231a16ee 100644 --- a/examples/src/main/java/io/dapr/examples/workflows/subworkflow/ReverseActivity.java +++ b/examples/src/main/java/io/dapr/examples/workflows/subworkflow/ReverseActivity.java @@ -13,7 +13,6 @@ limitations under the License. package io.dapr.examples.workflows.subworkflow; -import io.dapr.examples.workflows.chain.ToUpperCaseActivity; import io.dapr.workflows.runtime.WorkflowActivity; import io.dapr.workflows.runtime.WorkflowActivityContext; import org.slf4j.Logger; 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 index 1efa44646..6befd413f 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/client/ActorClient.java +++ b/sdk-actors/src/main/java/io/dapr/actors/client/ActorClient.java @@ -13,8 +13,6 @@ limitations under the License. package io.dapr.actors.client; -import io.dapr.client.DaprApiProtocol; -import io.dapr.client.DaprHttpBuilder; import io.dapr.client.resiliency.ResiliencyOptions; import io.dapr.config.Properties; import io.dapr.utils.Version; @@ -55,33 +53,21 @@ public class ActorClient implements AutoCloseable { * * @param resiliencyOptions Client resiliency options. */ - public ActorClient(ResiliencyOptions resiliencyOptions) { - this(Properties.API_PROTOCOL.get(), resiliencyOptions); + private ActorClient(ResiliencyOptions resiliencyOptions) { + this(buildManagedChannel(), resiliencyOptions); } /** * Instantiates a new channel for Dapr sidecar communication. * - * @param apiProtocol Dapr's API protocol. - * @param resiliencyOptions Client resiliency options. - */ - private ActorClient(DaprApiProtocol apiProtocol, ResiliencyOptions resiliencyOptions) { - this(apiProtocol, buildManagedChannel(apiProtocol), resiliencyOptions); - } - - /** - * Instantiates a new channel for Dapr sidecar communication. - * - * @param apiProtocol Dapr's API protocol. * @param grpcManagedChannel gRPC channel. * @param resiliencyOptions Client resiliency options. */ private ActorClient( - DaprApiProtocol apiProtocol, ManagedChannel grpcManagedChannel, ResiliencyOptions resiliencyOptions) { this.grpcManagedChannel = grpcManagedChannel; - this.daprClient = buildDaprClient(apiProtocol, grpcManagedChannel, resiliencyOptions); + this.daprClient = buildDaprClient(grpcManagedChannel, resiliencyOptions); } /** @@ -110,14 +96,9 @@ public class ActorClient implements AutoCloseable { /** * 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; - } - + private static ManagedChannel buildManagedChannel() { int port = Properties.GRPC_PORT.get(); if (port <= 0) { throw new IllegalArgumentException("Invalid port."); @@ -136,16 +117,8 @@ public class ActorClient implements AutoCloseable { * @throws java.lang.IllegalStateException if any required field is missing */ private static DaprClient buildDaprClient( - DaprApiProtocol apiProtocol, Channel grpcManagedChannel, ResiliencyOptions resiliencyOptions) { - switch (apiProtocol) { - case GRPC: return new DaprGrpcClient(DaprGrpc.newStub(grpcManagedChannel), resiliencyOptions); - case HTTP: { - LOGGER.warn("HTTP client protocol is deprecated and will be removed in Dapr's Java SDK version 1.10."); - return new DaprHttpClient(new DaprHttpBuilder().build()); - } - default: throw new IllegalStateException("Unsupported protocol: " + apiProtocol.name()); - } + return new DaprClientImpl(DaprGrpc.newStub(grpcManagedChannel), resiliencyOptions); } } diff --git a/sdk-actors/src/main/java/io/dapr/actors/client/DaprGrpcClient.java b/sdk-actors/src/main/java/io/dapr/actors/client/DaprClientImpl.java similarity index 90% rename from sdk-actors/src/main/java/io/dapr/actors/client/DaprGrpcClient.java rename to sdk-actors/src/main/java/io/dapr/actors/client/DaprClientImpl.java index efe37b0be..c060e01c5 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/client/DaprGrpcClient.java +++ b/sdk-actors/src/main/java/io/dapr/actors/client/DaprClientImpl.java @@ -17,7 +17,7 @@ import com.google.protobuf.ByteString; import io.dapr.client.resiliency.ResiliencyOptions; import io.dapr.config.Properties; import io.dapr.exceptions.DaprException; -import io.dapr.internal.opencensus.GrpcWrapper; +import io.dapr.internal.grpc.DaprClientGrpcInterceptors; import io.dapr.internal.resiliency.RetryPolicy; import io.dapr.internal.resiliency.TimeoutPolicy; import io.dapr.v1.DaprGrpc; @@ -40,7 +40,7 @@ import java.util.function.Consumer; /** * A DaprClient over GRPC for Actor. */ -class DaprGrpcClient implements DaprClient { +class DaprClientImpl implements DaprClient { /** * Timeout policy for SDK calls to Dapr API. @@ -63,7 +63,7 @@ class DaprGrpcClient implements DaprClient { * @param grpcClient Dapr's GRPC client. * @param resiliencyOptions Client resiliency options (optional) */ - DaprGrpcClient(DaprGrpc.DaprStub grpcClient, ResiliencyOptions resiliencyOptions) { + DaprClientImpl(DaprGrpc.DaprStub grpcClient, ResiliencyOptions resiliencyOptions) { this.client = intercept(grpcClient); this.timeoutPolicy = new TimeoutPolicy( resiliencyOptions == null ? null : resiliencyOptions.getTimeout()); @@ -85,7 +85,7 @@ class DaprGrpcClient implements DaprClient { .build(); return Mono.deferContextual( context -> this.createMono( - it -> intercept(context, client).invokeActor(req, it) + it -> intercept(context, this.timeoutPolicy, client).invokeActor(req, it) ) ).map(r -> r.getData().toByteArray()); } @@ -124,11 +124,13 @@ class DaprGrpcClient implements DaprClient { * Populates GRPC client with interceptors for telemetry. * * @param context Reactor's context. + * @param timeoutPolicy Timeout policy for gRPC call. * @param client GRPC client for Dapr. * @return Client after adding interceptors. */ - private static DaprGrpc.DaprStub intercept(ContextView context, DaprGrpc.DaprStub client) { - return GrpcWrapper.intercept(context, client); + private static DaprGrpc.DaprStub intercept( + ContextView context, TimeoutPolicy timeoutPolicy, DaprGrpc.DaprStub client) { + return DaprClientGrpcInterceptors.intercept(client, timeoutPolicy, context); } private Mono createMono(Consumer> consumer) { 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 deleted file mode 100644 index eff62ae7e..000000000 --- a/sdk-actors/src/main/java/io/dapr/actors/client/DaprHttpClient.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2021 The Dapr Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io.dapr.actors.client; - -import io.dapr.client.DaprHttp; -import reactor.core.publisher.Mono; - -/** - * DaprClient over HTTP for actor client. - * @deprecated This class will be deleted at SDK release version 1.10. - * @see DaprHttp - */ -@Deprecated -class DaprHttpClient implements DaprClient { - - /** - * The HTTP client to be used. - * - * @see DaprHttp - */ - private final DaprHttp client; - - /** - * Instantiates a new Dapr Http Client to invoke Actors. - * - * @param client Dapr's http client. - */ - DaprHttpClient(DaprHttp client) { - this.client = client; - } - - /** - * {@inheritDoc} - */ - @Override - 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(), pathSegments, null, jsonPayload, null, null); - return responseMono.map(r -> r.getBody()); - } -} 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 f9870fd0d..65ac1ada0 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 @@ -15,8 +15,6 @@ package io.dapr.actors.runtime; 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; import io.dapr.serializer.DefaultObjectSerializer; @@ -312,16 +310,12 @@ public class ActorRuntime implements Closeable { /** * Build an instance of the Client based on the provided setup. * - * @param channel GRPC managed channel (or null, if not using GRPC). + * @param channel GRPC managed channel. * @return an instance of the setup Client * @throws java.lang.IllegalStateException if any required field is missing */ private static DaprClient buildDaprClient(ManagedChannel channel) { - if (Properties.API_PROTOCOL.get() == DaprApiProtocol.GRPC) { - return new DaprGrpcClient(channel); - } - - return new DaprHttpClient(new DaprHttpBuilder().build()); + return new DaprGrpcClient(channel); } /** @@ -330,10 +324,6 @@ public class ActorRuntime implements Closeable { * @return GRPC managed channel or null. */ private static ManagedChannel buildManagedChannel() { - if (Properties.API_PROTOCOL.get() != DaprApiProtocol.GRPC) { - return null; - } - int port = Properties.GRPC_PORT.get(); if (port <= 0) { throw new IllegalStateException("Invalid port."); diff --git a/sdk-actors/src/test/java/io/dapr/actors/TestUtils.java b/sdk-actors/src/test/java/io/dapr/actors/TestUtils.java index 5ccc45386..67323aac2 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/TestUtils.java +++ b/sdk-actors/src/test/java/io/dapr/actors/TestUtils.java @@ -14,9 +14,9 @@ limitations under the License. package io.dapr.actors; import io.dapr.exceptions.DaprException; +import org.apache.commons.validator.routines.InetAddressValidator; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.function.Executable; -import org.apache.commons.validator.routines.InetAddressValidator; public final class TestUtils { 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 7f5a229d6..aeb450c9a 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 @@ -32,9 +32,10 @@ import java.io.IOException; import java.util.concurrent.ExecutionException; import static io.dapr.actors.TestUtils.assertThrowsDaprException; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.AdditionalAnswers.delegatesTo; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; public class DaprGrpcClientTest { @@ -89,7 +90,7 @@ public class DaprGrpcClientTest { } })); - private DaprGrpcClient client; + private DaprClientImpl client; @BeforeEach public void setup() throws IOException { @@ -105,7 +106,7 @@ public class DaprGrpcClientTest { InProcessChannelBuilder.forName(serverName).directExecutor().build()); // Create a HelloWorldClient using the in-process channel; - client = new DaprGrpcClient(DaprGrpc.newStub(channel), null); + client = new DaprClientImpl(DaprGrpc.newStub(channel), null); } @Test 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 deleted file mode 100644 index 69e47bfd0..000000000 --- a/sdk-actors/src/test/java/io/dapr/actors/client/DaprHttpClientTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2021 The Dapr Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and -limitations under the License. -*/ -package io.dapr.actors.client; - -import io.dapr.client.DaprHttp; -import io.dapr.client.DaprHttpProxy; -import io.dapr.config.Properties; -import okhttp3.OkHttpClient; -import okhttp3.ResponseBody; -import okhttp3.mock.Behavior; -import okhttp3.mock.MediaTypes; -import okhttp3.mock.MockInterceptor; -import org.junit.Before; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Mono; - -import static io.dapr.actors.TestUtils.formatIpAddress; -import static io.dapr.actors.TestUtils.assertThrowsDaprException; -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class DaprHttpClientTest { - - private DaprHttpClient DaprHttpClient; - - private OkHttpClient okHttpClient; - - private MockInterceptor mockInterceptor; - - private String sidecarIp; - - private final String EXPECTED_RESULT = "{\"data\":\"ewoJCSJwcm9wZXJ0eUEiOiAidmFsdWVBIiwKCQkicHJvcGVydHlCIjogInZhbHVlQiIKCX0=\"}"; - - @BeforeEach - public void setUp() { - sidecarIp = formatIpAddress(Properties.SIDECAR_IP.get()); - mockInterceptor = new MockInterceptor(Behavior.UNORDERED); - okHttpClient = new OkHttpClient.Builder().addInterceptor(mockInterceptor).build(); - } - - @Test - public void invokeActorMethod() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/actors/DemoActor/1/method/Payment") - .respond(EXPECTED_RESULT); - DaprHttp daprHttp = new DaprHttpProxy(sidecarIp, 3000, okHttpClient); - DaprHttpClient = new DaprHttpClient(daprHttp); - Mono mono = - DaprHttpClient.invoke("DemoActor", "1", "Payment", "".getBytes()); - assertEquals(new String(mono.block()), EXPECTED_RESULT); - } - - @Test - public void invokeActorMethodIPv6() { - String prevSidecarIp = sidecarIp; - System.setProperty(Properties.SIDECAR_IP.getName(), "2001:db8:3333:4444:5555:6666:7777:8888"); - sidecarIp = formatIpAddress(Properties.SIDECAR_IP.get()); - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/actors/DemoActor/1/method/Payment") - .respond(EXPECTED_RESULT); - DaprHttp daprHttp = new DaprHttpProxy(sidecarIp, 3000, okHttpClient); - DaprHttpClient = new DaprHttpClient(daprHttp); - System.setProperty(Properties.SIDECAR_IP.getName(), prevSidecarIp); - Mono mono = - DaprHttpClient.invoke("DemoActor", "1", "Payment", "".getBytes()); - assertEquals(new String(mono.block()), EXPECTED_RESULT); - } - - @Test - public void invokeActorMethodError() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/actors/DemoActor/1/method/Payment") - .respond(404, - ResponseBody.create("" + - "{\"errorCode\":\"ERR_SOMETHING\"," + - "\"message\":\"error message\"}", MediaTypes.MEDIATYPE_JSON)); - DaprHttp daprHttp = new DaprHttpProxy(sidecarIp, 3000, okHttpClient); - DaprHttpClient = new DaprHttpClient(daprHttp); - Mono mono = - DaprHttpClient.invoke("DemoActor", "1", "Payment", "".getBytes()); - - assertThrowsDaprException( - "ERR_SOMETHING", - "ERR_SOMETHING: error message", - () -> mono.block()); - } - -} 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 7342d04d7..6fd106943 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 @@ -19,7 +19,6 @@ import io.dapr.serializer.DefaultObjectSerializer; import io.dapr.utils.TypeRef; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Assertions; import reactor.core.publisher.Mono; import java.io.IOException; 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 94f02d1fa..1c5760665 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 @@ -39,8 +39,10 @@ import java.util.List; import java.util.concurrent.ExecutionException; import static io.dapr.actors.TestUtils.assertThrowsDaprException; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class DaprGrpcClientTest { 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 2a20d5bc1..a152f8342 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 @@ -35,10 +35,10 @@ import java.util.Base64; import java.util.Collections; import java.util.List; +import static io.dapr.actors.TestUtils.formatIpAddress; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.fail; -import static io.dapr.actors.TestUtils.formatIpAddress; public class DaprHttpClientTest { 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 a061b6675..a24bf7271 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 @@ -25,8 +25,12 @@ import reactor.core.publisher.Mono; import java.util.Arrays; import java.util.Objects; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; /** * Tests for the state store facade. 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 885a9f078..102186fa6 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 @@ -19,7 +19,6 @@ import io.dapr.actors.client.ActorProxy; import io.dapr.actors.client.ActorProxyImplForTests; import io.dapr.actors.client.DaprClientStub; import io.dapr.serializer.DefaultObjectSerializer; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; diff --git a/sdk-tests/deploy/local-test.yml b/sdk-tests/deploy/local-test.yml index edcfa2ea0..989757a78 100644 --- a/sdk-tests/deploy/local-test.yml +++ b/sdk-tests/deploy/local-test.yml @@ -26,7 +26,3 @@ services: image: mongo ports: - "27017:27017" - redis: - image: redis - ports: - - "6379:6379" 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 5900f6a22..4ad886b84 100644 --- a/sdk-tests/src/test/java/io/dapr/it/AppRun.java +++ b/sdk-tests/src/test/java/io/dapr/it/AppRun.java @@ -13,7 +13,6 @@ limitations under the License. package io.dapr.it; -import io.dapr.client.DaprApiProtocol; import io.dapr.config.Properties; import java.io.IOException; @@ -28,7 +27,7 @@ import static io.dapr.it.Retry.callWithRetry; public class AppRun implements Stoppable { private static final String APP_COMMAND = - "mvn exec:java -B -D exec.mainClass=%s -D exec.classpathScope=test -D exec.args=\"%s\" -D %s=%s -D %s=%s"; + "mvn exec:java -B -D exec.mainClass=%s -D exec.classpathScope=test -D exec.args=\"%s\""; private final DaprPorts ports; @@ -39,11 +38,10 @@ public class AppRun implements Stoppable { AppRun(DaprPorts ports, String successMessage, Class serviceClass, - int maxWaitMilliseconds, - DaprApiProtocol protocol) { + int maxWaitMilliseconds) { this.command = new Command( successMessage, - buildCommand(serviceClass, ports, protocol), + buildCommand(serviceClass, ports), new HashMap<>() {{ put("DAPR_HTTP_PORT", ports.getHttpPort().toString()); put("DAPR_GRPC_PORT", ports.getGrpcPort().toString()); @@ -81,11 +79,9 @@ public class AppRun implements Stoppable { } } - private static String buildCommand(Class serviceClass, DaprPorts ports, DaprApiProtocol protocol) { + private static String buildCommand(Class serviceClass, DaprPorts ports) { return String.format(APP_COMMAND, serviceClass.getCanonicalName(), - ports.getAppPort() != null ? ports.getAppPort().toString() : "", - Properties.API_PROTOCOL.getName(), protocol, - Properties.API_METHOD_INVOCATION_PROTOCOL.getName(), protocol); + ports.getAppPort() != null ? ports.getAppPort().toString() : ""); } private static void assertListeningOnPort(int port) { @@ -101,4 +97,7 @@ public class AppRun implements Stoppable { System.out.printf("Confirmed listening on port %d.\n", port); } + public enum AppProtocol { + HTTP, GRPC; + } } 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 c4f9d3cde..abef394b7 100644 --- a/sdk-tests/src/test/java/io/dapr/it/BaseIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/BaseIT.java @@ -14,18 +14,19 @@ limitations under the License. package io.dapr.it; import io.dapr.actors.client.ActorClient; -import io.dapr.client.DaprApiProtocol; import io.dapr.client.resiliency.ResiliencyOptions; import org.apache.commons.lang3.tuple.ImmutablePair; import org.junit.jupiter.api.AfterAll; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.Queue; -import static io.dapr.client.DaprApiProtocol.GRPC; -import static io.dapr.client.DaprApiProtocol.HTTP; +import static io.dapr.it.AppRun.AppProtocol.GRPC; +import static io.dapr.it.AppRun.AppProtocol.HTTP; public abstract class BaseIT { @@ -52,7 +53,7 @@ public abstract class BaseIT { String testName, String successMessage, Class serviceClass, - DaprApiProtocol appProtocol, + AppRun.AppProtocol appProtocol, int maxWaitMilliseconds) throws Exception { return startDaprApp(testName, successMessage, serviceClass, true, maxWaitMilliseconds, GRPC, appProtocol); } @@ -63,7 +64,7 @@ public abstract class BaseIT { Class serviceClass, Boolean useAppPort, int maxWaitMilliseconds, - DaprApiProtocol protocol) throws Exception { + AppRun.AppProtocol protocol) throws Exception { return startDaprApp( testName, successMessage, @@ -81,8 +82,8 @@ public abstract class BaseIT { Class serviceClass, Boolean useAppPort, int maxWaitMilliseconds, - DaprApiProtocol protocol, - DaprApiProtocol appProtocol) throws Exception { + AppRun.AppProtocol protocol, + AppRun.AppProtocol appProtocol) throws Exception { return startDaprApp( testName, successMessage, @@ -115,14 +116,13 @@ public abstract class BaseIT { Boolean useAppPort, Boolean useDaprPorts, int maxWaitMilliseconds, - DaprApiProtocol protocol, - DaprApiProtocol appProtocol) throws Exception { + AppRun.AppProtocol protocol, + AppRun.AppProtocol appProtocol) throws Exception { DaprRun.Builder builder = new DaprRun.Builder( testName, () -> DaprPorts.build(useAppPort, useDaprPorts, useDaprPorts), successMessage, maxWaitMilliseconds, - protocol, appProtocol).withServiceClass(serviceClass); DaprRun run = builder.build(); TO_BE_STOPPED.add(run); @@ -139,7 +139,7 @@ public abstract class BaseIT { Boolean useAppPort, int maxWaitMilliseconds) throws Exception { return startSplitDaprAndApp( - testName, successMessage, serviceClass, useAppPort, maxWaitMilliseconds, DaprApiProtocol.GRPC); + testName, successMessage, serviceClass, useAppPort, maxWaitMilliseconds, AppRun.AppProtocol.GRPC); } protected static ImmutablePair startSplitDaprAndApp( @@ -148,7 +148,7 @@ public abstract class BaseIT { Class serviceClass, Boolean useAppPort, int maxWaitMilliseconds, - DaprApiProtocol protocol) throws Exception { + AppRun.AppProtocol protocol) throws Exception { return startSplitDaprAndApp( testName, successMessage, @@ -165,14 +165,13 @@ public abstract class BaseIT { Class serviceClass, Boolean useAppPort, int maxWaitMilliseconds, - DaprApiProtocol protocol, - DaprApiProtocol appProtocol) throws Exception { + AppRun.AppProtocol protocol, + AppRun.AppProtocol appProtocol) throws Exception { DaprRun.Builder builder = new DaprRun.Builder( testName, () -> DaprPorts.build(useAppPort, true, true), successMessage, maxWaitMilliseconds, - protocol, appProtocol).withServiceClass(serviceClass); ImmutablePair runs = builder.splitBuild(); TO_BE_STOPPED.add(runs.left); @@ -199,9 +198,21 @@ public abstract class BaseIT { return newActorClient(null); } - protected static ActorClient newActorClient(ResiliencyOptions resiliencyOptions) { - ActorClient client = new ActorClient(resiliencyOptions); - TO_BE_CLOSED.add(client); - return client; + protected static ActorClient newActorClient(ResiliencyOptions resiliencyOptions) throws RuntimeException { + try { + Constructor constructor = ActorClient.class.getDeclaredConstructor(ResiliencyOptions.class); + constructor.setAccessible(true); + ActorClient client = constructor.newInstance(resiliencyOptions); + TO_BE_CLOSED.add(client); + return client; + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } } } 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 c0181b1db..9a7533a27 100644 --- a/sdk-tests/src/test/java/io/dapr/it/DaprRun.java +++ b/sdk-tests/src/test/java/io/dapr/it/DaprRun.java @@ -14,7 +14,6 @@ limitations under the License. package io.dapr.it; import com.google.protobuf.Empty; -import io.dapr.client.DaprApiProtocol; import io.dapr.config.Properties; import io.dapr.v1.AppCallbackHealthCheckGrpc; import io.grpc.ManagedChannel; @@ -42,13 +41,13 @@ 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 %s=%s -D %s=%s"; + " -- mvn exec:java -D exec.mainClass=%s -D exec.classpathScope=test -D exec.args=\"%s\""; private final DaprPorts ports; private final String appName; - private final DaprApiProtocol appProtocol; + private final AppRun.AppProtocol appProtocol; private final int maxWaitMilliseconds; @@ -67,15 +66,14 @@ public class DaprRun implements Stoppable { String successMessage, Class serviceClass, int maxWaitMilliseconds, - DaprApiProtocol protocol, - DaprApiProtocol appProtocol) { + AppRun.AppProtocol appProtocol) { // The app name needs to be deterministic since we depend on it to kill previous runs. this.appName = serviceClass == null ? testName.toLowerCase() : String.format("%s-%s", testName, serviceClass.getSimpleName()).toLowerCase(); this.appProtocol = appProtocol; this.startCommand = - new Command(successMessage, buildDaprCommand(this.appName, serviceClass, ports, protocol, appProtocol)); + new Command(successMessage, buildDaprCommand(this.appName, serviceClass, ports, appProtocol)); this.listCommand = new Command( this.appName, "dapr list"); @@ -145,29 +143,6 @@ public class DaprRun implements Stoppable { public void use() { this.ports.use(); - System.getProperties().setProperty(Properties.API_PROTOCOL.getName(), DaprApiProtocol.GRPC.name()); - System.getProperties().setProperty( - Properties.API_METHOD_INVOCATION_PROTOCOL.getName(), - DaprApiProtocol.GRPC.name()); - } - - public void switchToGRPC() { - System.getProperties().setProperty(Properties.API_PROTOCOL.getName(), DaprApiProtocol.GRPC.name()); - System.getProperties().setProperty( - Properties.API_METHOD_INVOCATION_PROTOCOL.getName(), - DaprApiProtocol.GRPC.name()); - } - - public void switchToHTTP() { - System.getProperties().setProperty(Properties.API_PROTOCOL.getName(), DaprApiProtocol.HTTP.name()); - System.getProperties().setProperty( - Properties.API_METHOD_INVOCATION_PROTOCOL.getName(), - DaprApiProtocol.HTTP.name()); - } - - public void switchToProtocol(DaprApiProtocol protocol) { - System.getProperties().setProperty(Properties.API_PROTOCOL.getName(), protocol.name()); - System.getProperties().setProperty(Properties.API_METHOD_INVOCATION_PROTOCOL.getName(), protocol.name()); } public void waitForAppHealth(int maxWaitMilliseconds) throws InterruptedException { @@ -175,7 +150,7 @@ public class DaprRun implements Stoppable { return; } - if (DaprApiProtocol.GRPC.equals(this.appProtocol)) { + if (AppRun.AppProtocol.GRPC.equals(this.appProtocol)) { ManagedChannel channel = ManagedChannelBuilder.forAddress("127.0.0.1", this.getAppPort()) .usePlaintext() .build(); @@ -263,7 +238,7 @@ public class DaprRun implements Stoppable { } private static String buildDaprCommand( - String appName, Class serviceClass, DaprPorts ports, DaprApiProtocol protocol, DaprApiProtocol appProtocol) { + String appName, Class serviceClass, DaprPorts ports, AppRun.AppProtocol appProtocol) { StringBuilder stringBuilder = new StringBuilder(String.format(DAPR_RUN, appName, appProtocol.toString().toLowerCase())) .append(ports.getAppPort() != null ? " --app-port " + ports.getAppPort() : "") @@ -273,9 +248,7 @@ public class DaprRun implements Stoppable { " --enable-app-health-check --app-health-probe-interval=1" : "") .append(serviceClass == null ? "" : String.format(DAPR_COMMAND, serviceClass.getCanonicalName(), - ports.getAppPort() != null ? ports.getAppPort().toString() : "", - Properties.API_PROTOCOL.getName(), protocol, - Properties.API_METHOD_INVOCATION_PROTOCOL.getName(), protocol)); + ports.getAppPort() != null ? ports.getAppPort().toString() : "")); return stringBuilder.toString(); } @@ -315,22 +288,18 @@ public class DaprRun implements Stoppable { private Class serviceClass; - private DaprApiProtocol protocol; - - private DaprApiProtocol appProtocol; + private AppRun.AppProtocol appProtocol; Builder( String testName, Supplier portsSupplier, String successMessage, int maxWaitMilliseconds, - DaprApiProtocol protocol, - DaprApiProtocol appProtocol) { + AppRun.AppProtocol appProtocol) { this.testName = testName; this.portsSupplier = portsSupplier; this.successMessage = successMessage; this.maxWaitMilliseconds = maxWaitMilliseconds; - this.protocol = protocol; this.appProtocol = appProtocol; } @@ -346,7 +315,6 @@ public class DaprRun implements Stoppable { this.successMessage, this.serviceClass, this.maxWaitMilliseconds, - this.protocol, this.appProtocol); } @@ -360,8 +328,7 @@ public class DaprRun implements Stoppable { ports, this.successMessage, this.serviceClass, - this.maxWaitMilliseconds, - this.protocol); + this.maxWaitMilliseconds); DaprRun daprRun = new DaprRun( this.testName, @@ -369,7 +336,6 @@ public class DaprRun implements Stoppable { DAPR_SUCCESS_MESSAGE, null, this.maxWaitMilliseconds, - this.protocol, this.appProtocol); return new ImmutablePair<>(appRun, daprRun); 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 d0f0570d7..73f0eb382 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,22 +22,24 @@ import io.dapr.it.DaprRun; import io.dapr.it.actors.app.ActorReminderDataParam; import io.dapr.it.actors.app.MyActorService; import org.apache.commons.lang3.tuple.ImmutablePair; -import org.junit.Before; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.junit.runners.Parameterized; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.time.Duration; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import java.util.stream.Stream; import static io.dapr.it.Retry.callWithRetry; -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.validateMessageContent; +import static io.dapr.it.actors.MyActorTestUtils.validateMethodCalls; public class ActorReminderRecoveryIT extends BaseIT { diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActorSdkResiliencytIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActorSdkResiliencytIT.java index ae9f8c676..9d6a8df9a 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActorSdkResiliencytIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActorSdkResiliencytIT.java @@ -75,10 +75,6 @@ public class ActorSdkResiliencytIT extends BaseIT { true, 60000); - ActorId actorId = new ActorId(UUID.randomUUID().toString()); - - // HTTP client is deprecated, so SDK resiliency is for gRPC client only. - daprRun.switchToGRPC(); demoActor = buildDemoActorProxy(null); daprClient = new DaprClientBuilder().build(); 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 90a160ef8..534fd481d 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 @@ -16,7 +16,7 @@ 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.client.DaprApiProtocol; +import io.dapr.it.AppRun; import io.dapr.it.BaseIT; import io.dapr.it.DaprRun; import io.dapr.it.actors.services.springboot.StatefulActor; @@ -45,16 +45,14 @@ public class ActorStateIT extends BaseIT { */ public static Stream data() { return Stream.of( - Arguments.of(DaprApiProtocol.HTTP, DaprApiProtocol.HTTP ), - Arguments.of(DaprApiProtocol.HTTP, DaprApiProtocol.GRPC ), - Arguments.of(DaprApiProtocol.GRPC, DaprApiProtocol.HTTP ), - Arguments.of(DaprApiProtocol.GRPC, DaprApiProtocol.GRPC ) + Arguments.of(AppRun.AppProtocol.HTTP ), + Arguments.of(AppRun.AppProtocol.GRPC ) ); } @ParameterizedTest @MethodSource("data") - public void writeReadState(DaprApiProtocol daprClientProtocol, DaprApiProtocol serviceAppProtocol) throws Exception { + public void writeReadState(AppRun.AppProtocol serviceAppProtocol) throws Exception { logger.debug("Starting actor runtime ..."); // The call below will fail if service cannot start successfully. DaprRun runtime = startDaprApp( @@ -65,13 +63,11 @@ public class ActorStateIT extends BaseIT { 60000, serviceAppProtocol); - runtime.switchToProtocol(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(), daprClientProtocol, serviceAppProtocol)); + String.format("%d-%b", System.currentTimeMillis(), serviceAppProtocol)); String actorType = "StatefulActorTest"; logger.debug("Building proxy ..."); ActorProxyBuilder proxyBuilder = @@ -161,8 +157,6 @@ public class ActorStateIT extends BaseIT { 60000, serviceAppProtocol); - runtime.switchToProtocol(daprClientProtocol); - // Need new proxy builder because the proxy builder holds the channel. proxyBuilder = new ActorProxyBuilder(actorType, ActorProxy.class, newActorClient()); ActorProxy newProxy = proxyBuilder.build(actorId); 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 d1d5cffd6..ae50aa6ab 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 @@ -20,7 +20,9 @@ import java.util.Date; import java.util.List; import java.util.stream.Collectors; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /** * Utility class for tests that use MyActor class. diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/app/MyActorBase.java b/sdk-tests/src/test/java/io/dapr/it/actors/app/MyActorBase.java index 46aebbbc7..b05dc3b2b 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/app/MyActorBase.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/app/MyActorBase.java @@ -24,7 +24,13 @@ import reactor.core.publisher.Mono; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.time.Duration; -import java.util.*; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Calendar; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.TimeZone; import java.util.function.Function; public abstract class MyActorBase extends AbstractActor implements MyActor, Remindable { diff --git a/sdk-tests/src/test/java/io/dapr/it/api/ApiIT.java b/sdk-tests/src/test/java/io/dapr/it/api/ApiIT.java index 4fd9999c7..462d22927 100644 --- a/sdk-tests/src/test/java/io/dapr/it/api/ApiIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/api/ApiIT.java @@ -4,34 +4,19 @@ import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; import io.dapr.it.BaseIT; import io.dapr.it.DaprRun; -import io.dapr.it.actors.ActorReminderRecoveryIT; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Arrays; -import java.util.Collection; - public class ApiIT extends BaseIT { private static final Logger logger = LoggerFactory.getLogger(ApiIT.class); private static final int DEFAULT_TIMEOUT = 60000; - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void testShutdownAPI(boolean useGrpc) throws Exception { + @Test + public void testShutdownAPI() throws Exception { DaprRun run = startDaprApp(this.getClass().getSimpleName(), DEFAULT_TIMEOUT); - if (useGrpc) { - run.switchToGRPC(); - } else { - run.switchToHTTP(); - } - // TODO(artursouza): change this to wait for the sidecar to be healthy (new method needed in DaprClient). Thread.sleep(3000); try (DaprClient client = new DaprClientBuilder().build()) { 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 8d66c26aa..cc83b9b62 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 @@ -20,8 +20,6 @@ import io.dapr.client.domain.HttpExtension; import io.dapr.it.BaseIT; import io.dapr.it.DaprRun; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; import java.util.Collections; import java.util.List; @@ -46,24 +44,14 @@ public class BindingIT extends BaseIT { public String message; } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void inputOutputBinding(boolean useGrpc) throws Exception { - System.out.println("Working Directory = " + System.getProperty("user.dir")); - String serviceNameVariant = useGrpc ? "-grpc" : "-http"; - + @Test + public void inputOutputBinding() throws Exception { DaprRun daprRun = startDaprApp( - this.getClass().getSimpleName() + serviceNameVariant, + this.getClass().getSimpleName() + "-grpc", InputBindingService.SUCCESS_MESSAGE, InputBindingService.class, true, 60000); - // At this point, it is guaranteed that the service above is running and all ports being listened to. - if (useGrpc) { - daprRun.switchToGRPC(); - } else { - daprRun.switchToHTTP(); - } try(DaprClient client = new DaprClientBuilder().build()) { callWithRetry(() -> { diff --git a/sdk-tests/src/test/java/io/dapr/it/configuration/grpc/ConfigurationClientIT.java b/sdk-tests/src/test/java/io/dapr/it/configuration/ConfigurationClientIT.java similarity index 94% rename from sdk-tests/src/test/java/io/dapr/it/configuration/grpc/ConfigurationClientIT.java rename to sdk-tests/src/test/java/io/dapr/it/configuration/ConfigurationClientIT.java index b66715842..02c5798de 100644 --- a/sdk-tests/src/test/java/io/dapr/it/configuration/grpc/ConfigurationClientIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/configuration/ConfigurationClientIT.java @@ -11,7 +11,7 @@ limitations under the License. */ -package io.dapr.it.configuration.grpc; +package io.dapr.it.configuration; import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; @@ -20,7 +20,6 @@ import io.dapr.client.domain.SubscribeConfigurationResponse; import io.dapr.client.domain.UnsubscribeConfigurationResponse; import io.dapr.it.BaseIT; import io.dapr.it.DaprRun; - import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -29,10 +28,14 @@ import reactor.core.Disposable; import reactor.core.publisher.Flux; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicReference; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ConfigurationClientIT extends BaseIT { @@ -65,7 +68,6 @@ public class ConfigurationClientIT extends BaseIT { @BeforeAll public static void init() throws Exception { daprRun = startDaprApp(ConfigurationClientIT.class.getSimpleName(), 5000); - daprRun.switchToGRPC(); daprClient = new DaprClientBuilder().build(); } @@ -198,6 +200,9 @@ public class ConfigurationClientIT extends BaseIT { try { process = processBuilder.start(); process.waitFor(); + if (process.exitValue() != 0) { + throw new RuntimeException("Not zero exit code for Redis command: " + process.exitValue()); + } } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { diff --git a/sdk-tests/src/test/java/io/dapr/it/configuration/http/ConfigSubscriberController.java b/sdk-tests/src/test/java/io/dapr/it/configuration/http/ConfigSubscriberController.java deleted file mode 100644 index c3323bde6..000000000 --- a/sdk-tests/src/test/java/io/dapr/it/configuration/http/ConfigSubscriberController.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2022 The Dapr Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io.dapr.it.configuration.http; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.dapr.client.domain.ConfigurationItem; -import io.dapr.client.domain.SubscribeConfigurationResponse; -import org.springframework.http.MediaType; -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.RequestBody; -import org.springframework.web.bind.annotation.RestController; -import reactor.core.publisher.Mono; - -import java.util.Iterator; -import java.util.Map; - -/** - * Spring boot Controller class for api endpoints. - */ -@RestController -public class ConfigSubscriberController { - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - - /** - * Api mapping for subscribe configuration. - * @param pathVarsMap Path variables for post call - * @param obj request Body - * @return Returns void - */ - @PostMapping(path = "/configuration/{configStore}/{key}", produces = MediaType.APPLICATION_JSON_VALUE) - public Mono handleMessage( - @PathVariable Map pathVarsMap, - @RequestBody SubscribeConfigurationResponse obj) { - return Mono.fromRunnable( - () -> { - try { - Map items = obj.getItems(); - for (Map.Entry entry : items.entrySet()) { - System.out.println(entry.getValue().getValue() + " : key ->" + entry.getKey()); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } - ); - } - - @GetMapping(path = "/health") - public void health() { - } -} diff --git a/sdk-tests/src/test/java/io/dapr/it/configuration/http/ConfigurationIT.java b/sdk-tests/src/test/java/io/dapr/it/configuration/http/ConfigurationIT.java deleted file mode 100644 index 93e3816a2..000000000 --- a/sdk-tests/src/test/java/io/dapr/it/configuration/http/ConfigurationIT.java +++ /dev/null @@ -1,83 +0,0 @@ -package io.dapr.it.configuration.http; - -import io.dapr.client.DaprClient; -import io.dapr.client.DaprClientBuilder; -import io.dapr.client.domain.ConfigurationItem; -import io.dapr.it.BaseIT; -import io.dapr.it.DaprRun; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.io.IOException; -import java.util.*; - -import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class ConfigurationIT extends BaseIT { - private static final String CONFIG_STORE_NAME = "redisconfigstore"; - - private static DaprRun daprRun; - - private static DaprClient daprClient; - - private static String key = "myconfig1"; - - private static List keys = new ArrayList<>(Arrays.asList("myconfig1", "myconfig2", "myconfig3")); - - private static String[] insertCmd = new String[] { - "docker", "exec", "dapr_redis", "redis-cli", - "MSET", - "myconfigkey1", "myconfigvalue1||1", - "myconfigkey2", "myconfigvalue2||1", - "myconfigkey3", "myconfigvalue3||1" - }; - - @BeforeAll - public static void init() throws Exception { - daprRun = startDaprApp(ConfigurationIT.class.getSimpleName(), 5000); - daprRun.switchToHTTP(); - daprClient = new DaprClientBuilder().build(); - } - - @AfterAll - public static void tearDown() throws Exception { - daprClient.close(); - } - - @BeforeEach - public void setupConfigStore() { - executeDockerCommand(insertCmd); - } - - @Test - public void getConfiguration() { - ConfigurationItem ci = daprClient.getConfiguration(CONFIG_STORE_NAME, "myconfigkey1").block(); - assertEquals(ci.getKey(), "myconfigkey1"); - assertEquals(ci.getValue(), "myconfigvalue1"); - } - - @Test - public void getConfigurations() { - Map cis = daprClient.getConfiguration(CONFIG_STORE_NAME, "myconfigkey1", "myconfigkey2").block(); - assertTrue(cis.size() == 2); - assertTrue(cis.containsKey("myconfigkey1")); - assertTrue(cis.containsKey("myconfigkey2")); - } - - private static void executeDockerCommand(String[] command) { - ProcessBuilder processBuilder = new ProcessBuilder(command); - Process process = null; - try { - process = processBuilder.start(); - process.waitFor(); - } catch (IOException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } -} diff --git a/sdk-tests/src/test/java/io/dapr/it/configuration/http/ConfigurationSubscribeIT.java b/sdk-tests/src/test/java/io/dapr/it/configuration/http/ConfigurationSubscribeIT.java deleted file mode 100644 index d2ebb50cd..000000000 --- a/sdk-tests/src/test/java/io/dapr/it/configuration/http/ConfigurationSubscribeIT.java +++ /dev/null @@ -1,91 +0,0 @@ -package io.dapr.it.configuration.http; - -import io.dapr.client.DaprClient; -import io.dapr.client.DaprClientBuilder; -import io.dapr.client.domain.SubscribeConfigurationResponse; -import io.dapr.client.domain.UnsubscribeConfigurationResponse; -import io.dapr.it.BaseIT; -import io.dapr.it.DaprRun; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; - -import java.io.IOException; -import java.util.*; -import java.util.concurrent.atomic.AtomicReference; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class ConfigurationSubscribeIT extends BaseIT { - private static final String CONFIG_STORE_NAME = "redisconfigstore"; - - private static DaprRun daprRun; - - private static DaprClient daprClient; - - private static String key = "myconfig1"; - - private static List keys = new ArrayList<>(Arrays.asList("myconfig1", "myconfig2", "myconfig3")); - - private static String[] insertCmd = new String[] { - "docker", "exec", "dapr_redis", "redis-cli", - "MSET", - "myconfigkey1", "myconfigvalue1||1", - "myconfigkey2", "myconfigvalue2||1", - "myconfigkey3", "myconfigvalue3||1" - }; - - @BeforeAll - public static void init() throws Exception { - daprRun = startDaprApp( - ConfigurationIT.class.getSimpleName(), - ConfigurationSubscriberService.SUCCESS_MESSAGE, - ConfigurationSubscriberService.class, - true, - 60000); - daprRun.switchToHTTP(); - daprClient = new DaprClientBuilder().build(); - } - - @AfterAll - public static void tearDown() throws Exception { - daprClient.close(); - } - - @BeforeEach - public void setupConfigStore() { - executeDockerCommand(insertCmd); - } - - @Test - public void subscribeAndUnsubscribeConfiguration() { - AtomicReference subId= new AtomicReference<>(""); - Flux outFlux = daprClient - .subscribeConfiguration(CONFIG_STORE_NAME, "myconfigkey1", "myconfigkey2"); - outFlux.subscribe(items -> { - subId.set(items.getSubscriptionId()); - }); - assertTrue(subId.get().length() > 0); - - UnsubscribeConfigurationResponse res = daprClient.unsubscribeConfiguration( - subId.get(), - CONFIG_STORE_NAME - ).block(); - assertTrue(res.getIsUnsubscribed()); - } - - private static void executeDockerCommand(String[] command) { - ProcessBuilder processBuilder = new ProcessBuilder(command); - Process process = null; - try { - process = processBuilder.start(); - process.waitFor(); - } catch (IOException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } -} diff --git a/sdk-tests/src/test/java/io/dapr/it/configuration/http/ConfigurationSubscriberService.java b/sdk-tests/src/test/java/io/dapr/it/configuration/http/ConfigurationSubscriberService.java deleted file mode 100644 index 1589c562e..000000000 --- a/sdk-tests/src/test/java/io/dapr/it/configuration/http/ConfigurationSubscriberService.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2022 The Dapr Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io.dapr.it.configuration.http; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * Service for ConfigurationSubscriber. - * dapr run --components-path ./components/configuration --app-id configsubscriber --app-port 3000 -- \ - * java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.configuration.http.ConfigurationSubscriber -p 3000 - */ -@SpringBootApplication -public class ConfigurationSubscriberService { - - public static final String SUCCESS_MESSAGE = "dapr initialized. Status: Running"; - - /** - * This is entry point for Configuration Subscriber service. - * @param args Arguments for main - * @throws Exception Throws Exception - */ - public static void main(String[] args) throws Exception { - int port = Integer.parseInt(args[0]); - - System.out.printf("Service starting on port %d ...\n", port); - - // Start Dapr's callback endpoint. - start(port); - } - - /** - * Starts Dapr's callback in a given port. - * - * @param port Port to listen to. - */ - private static void start(int port) { - SpringApplication app = new SpringApplication(ConfigurationSubscriberService.class); - app.run(String.format("--server.port=%d", port)); - } -} diff --git a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/grpc/MethodInvokeIT.java b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/grpc/MethodInvokeIT.java index 4d01dc05c..1750a8819 100644 --- a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/grpc/MethodInvokeIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/grpc/MethodInvokeIT.java @@ -1,12 +1,14 @@ package io.dapr.it.methodinvoke.grpc; -import io.dapr.client.DaprApiProtocol; import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; -import io.dapr.client.domain.HttpExtension; -import io.dapr.exceptions.DaprException; +import io.dapr.client.resiliency.ResiliencyOptions; +import io.dapr.it.AppRun; import io.dapr.it.BaseIT; import io.dapr.it.DaprRun; +import io.dapr.it.MethodInvokeServiceGrpc; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -15,7 +17,6 @@ import java.util.Map; import static io.dapr.it.MethodInvokeServiceProtos.DeleteMessageRequest; import static io.dapr.it.MethodInvokeServiceProtos.GetMessagesRequest; -import static io.dapr.it.MethodInvokeServiceProtos.GetMessagesResponse; import static io.dapr.it.MethodInvokeServiceProtos.PostMessageRequest; import static io.dapr.it.MethodInvokeServiceProtos.SleepRequest; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -38,15 +39,17 @@ public class MethodInvokeIT extends BaseIT { MethodInvokeIT.class.getSimpleName() + "grpc", MethodInvokeService.SUCCESS_MESSAGE, MethodInvokeService.class, - DaprApiProtocol.GRPC, // appProtocol + AppRun.AppProtocol.GRPC, // appProtocol 60000); - daprRun.switchToGRPC(); daprRun.waitForAppHealth(40000); } @Test public void testInvoke() throws Exception { try (DaprClient client = new DaprClientBuilder().build()) { + MethodInvokeServiceGrpc.MethodInvokeServiceBlockingStub stub = client.newGrpcStub( + daprRun.getAppName(), + channel -> MethodInvokeServiceGrpc.newBlockingStub(channel)); client.waitForSidecar(10000).block(); daprRun.waitForAppHealth(10000); @@ -54,59 +57,43 @@ public class MethodInvokeIT extends BaseIT { String message = String.format("This is message #%d", i); PostMessageRequest req = PostMessageRequest.newBuilder().setId(i).setMessage(message).build(); - client.invokeMethod(daprRun.getAppName(), "postMessage", req, HttpExtension.POST).block(); + stub.postMessage(req); + System.out.println("Invoke method messages : " + message); } - Map messages = client.invokeMethod( - daprRun.getAppName(), - "getMessages", - GetMessagesRequest.newBuilder().build(), - HttpExtension.POST, GetMessagesResponse.class).block().getMessagesMap(); + Map messages = stub.getMessages(GetMessagesRequest.newBuilder().build()).getMessagesMap(); assertEquals(10, messages.size()); // Delete one message. - client.invokeMethod( - daprRun.getAppName(), - "deleteMessage", - DeleteMessageRequest.newBuilder().setId(1).build(), - HttpExtension.POST).block(); - messages = client.invokeMethod( - daprRun.getAppName(), - "getMessages", - GetMessagesRequest.newBuilder().build(), - HttpExtension.POST, GetMessagesResponse.class).block().getMessagesMap(); + stub.deleteMessage(DeleteMessageRequest.newBuilder().setId(1).build()); + messages = stub.getMessages(GetMessagesRequest.newBuilder().build()).getMessagesMap(); assertEquals(9, messages.size()); // Now update one message. - client.invokeMethod( - daprRun.getAppName(), - "postMessage", - PostMessageRequest.newBuilder().setId(2).setMessage("updated message").build(), - HttpExtension.POST).block(); - messages = client.invokeMethod( - daprRun.getAppName(), - "getMessages", - GetMessagesRequest.newBuilder().build(), - HttpExtension.POST, GetMessagesResponse.class).block().getMessagesMap(); + stub.postMessage(PostMessageRequest.newBuilder().setId(2).setMessage("updated message").build()); + messages = stub.getMessages(GetMessagesRequest.newBuilder().build()).getMessagesMap(); assertEquals("updated message", messages.get(2)); } } @Test public void testInvokeTimeout() throws Exception { - try (DaprClient client = new DaprClientBuilder().build()) { + long timeoutMs = 100; + ResiliencyOptions resiliencyOptions = new ResiliencyOptions().setTimeout(Duration.ofMillis(timeoutMs)); + try (DaprClient client = new DaprClientBuilder().withResiliencyOptions(resiliencyOptions).build()) { + MethodInvokeServiceGrpc.MethodInvokeServiceBlockingStub stub = client.newGrpcStub( + daprRun.getAppName(), + channel -> MethodInvokeServiceGrpc.newBlockingStub(channel)); client.waitForSidecar(10000).block(); daprRun.waitForAppHealth(10000); long started = System.currentTimeMillis(); SleepRequest req = SleepRequest.newBuilder().setSeconds(1).build(); - String message = assertThrows(IllegalStateException.class, () -> - client.invokeMethod(daprRun.getAppName(), "sleep", req.toByteArray(), HttpExtension.POST) - .block(Duration.ofMillis(10))).getMessage(); + String message = assertThrows(StatusRuntimeException.class, () -> stub.sleep(req)).getMessage(); long delay = System.currentTimeMillis() - started; - assertTrue(delay <= 500); // 500 ms is a reasonable delay if the request timed out. - assertEquals("Timeout on blocking read for 10000000 NANOSECONDS", message); + assertTrue(delay >= timeoutMs); + assertTrue(message.startsWith("DEADLINE_EXCEEDED: deadline exceeded after")); } } @@ -115,17 +102,20 @@ public class MethodInvokeIT extends BaseIT { try (DaprClient client = new DaprClientBuilder().build()) { client.waitForSidecar(10000).block(); daprRun.waitForAppHealth(10000); - + + MethodInvokeServiceGrpc.MethodInvokeServiceBlockingStub stub = client.newGrpcStub( + daprRun.getAppName(), + channel -> MethodInvokeServiceGrpc.newBlockingStub(channel)); + SleepRequest req = SleepRequest.newBuilder().setSeconds(-9).build(); - DaprException exception = assertThrows(DaprException.class, () -> - client.invokeMethod(daprRun.getAppName(), "sleep", req.toByteArray(), HttpExtension.POST).block()); + StatusRuntimeException exception = assertThrows(StatusRuntimeException.class, () -> stub.sleep(req)); // The error messages should be improved once runtime has standardized error serialization in the API. // This message is not ideal but last time it was improved, there was side effects reported by users. // If this test fails, there might be a regression in runtime (like we had in 1.10.0). // The expectations below are as per 1.9 release and (later on) hotfixed in 1.10. - assertEquals("UNKNOWN", exception.getErrorCode()); - assertEquals("UNKNOWN: ", exception.getMessage()); + assertEquals(Status.UNKNOWN.getCode(), exception.getStatus().getCode()); + assertEquals("", exception.getStatus().getDescription()); } } } diff --git a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/grpc/MethodInvokeService.java b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/grpc/MethodInvokeService.java index 45648075f..ac7b157af 100644 --- a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/grpc/MethodInvokeService.java +++ b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/grpc/MethodInvokeService.java @@ -13,26 +13,18 @@ limitations under the License. package io.dapr.it.methodinvoke.grpc; -import com.google.protobuf.Any; import io.dapr.grpc.GrpcHealthCheckService; import io.dapr.it.DaprRunConfig; -import io.dapr.v1.AppCallbackGrpc; -import io.dapr.v1.CommonProtos; +import io.dapr.it.MethodInvokeServiceGrpc; import io.grpc.Server; import io.grpc.ServerBuilder; -import io.grpc.stub.StreamObserver; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import static io.dapr.it.MethodInvokeServiceProtos.DeleteMessageRequest; -import static io.dapr.it.MethodInvokeServiceProtos.DeleteMessageResponse; -import static io.dapr.it.MethodInvokeServiceProtos.GetMessagesRequest; import static io.dapr.it.MethodInvokeServiceProtos.GetMessagesResponse; -import static io.dapr.it.MethodInvokeServiceProtos.PostMessageRequest; -import static io.dapr.it.MethodInvokeServiceProtos.PostMessageResponse; import static io.dapr.it.MethodInvokeServiceProtos.SleepRequest; import static io.dapr.it.MethodInvokeServiceProtos.SleepResponse; @@ -48,7 +40,7 @@ public class MethodInvokeService { /** * Server mode: class that encapsulates all server-side logic for Grpc. */ - private static class MyDaprService extends AppCallbackGrpc.AppCallbackImplBase { + private static class MyDaprService extends MethodInvokeServiceGrpc.MethodInvokeServiceImplBase { private final Map messages = Collections.synchronizedMap(new HashMap<>()); @@ -92,57 +84,55 @@ public class MethodInvokeService { } /** - * Server mode: this is the Dapr method to receive Invoke operations via Grpc. - * - * @param request Dapr envelope request, - * @param responseObserver Dapr envelope response. + * {@inheritDoc} */ - @Override - public void onInvoke(CommonProtos.InvokeRequest request, - StreamObserver responseObserver) { - System.out.println("Server: received " + request.getMethod() + " ..."); - try { - if ("postMessage".equals(request.getMethod())) { - PostMessageRequest req = PostMessageRequest.parseFrom(request.getData().getValue().toByteArray()); + public void postMessage(io.dapr.it.MethodInvokeServiceProtos.PostMessageRequest request, + io.grpc.stub.StreamObserver responseObserver) { + this.messages.put(request.getId(), request.getMessage()); - this.messages.put(req.getId(), req.getMessage()); + io.dapr.it.MethodInvokeServiceProtos.PostMessageResponse.Builder responseBuilder = + io.dapr.it.MethodInvokeServiceProtos.PostMessageResponse.newBuilder(); + responseObserver.onNext(responseBuilder.build()); + responseObserver.onCompleted(); + } - CommonProtos.InvokeResponse.Builder responseBuilder = CommonProtos.InvokeResponse.newBuilder(); - responseBuilder.setData(Any.pack(PostMessageResponse.newBuilder().build())); - responseObserver.onNext(responseBuilder.build()); - } - if ("deleteMessage".equals(request.getMethod())) { - DeleteMessageRequest req = DeleteMessageRequest.parseFrom(request.getData().getValue().toByteArray()); + /** + * {@inheritDoc} + */ + public void deleteMessage(io.dapr.it.MethodInvokeServiceProtos.DeleteMessageRequest request, + io.grpc.stub.StreamObserver responseObserver) { + this.messages.remove(request.getId()); - this.messages.remove(req.getId()); + io.dapr.it.MethodInvokeServiceProtos.DeleteMessageResponse.Builder responseBuilder = + io.dapr.it.MethodInvokeServiceProtos.DeleteMessageResponse.newBuilder(); + responseObserver.onNext(responseBuilder.build()); + responseObserver.onCompleted(); + } - CommonProtos.InvokeResponse.Builder responseBuilder = CommonProtos.InvokeResponse.newBuilder(); - responseBuilder.setData(Any.pack(DeleteMessageResponse.newBuilder().build())); - responseObserver.onNext(responseBuilder.build()); - } - if ("getMessages".equals(request.getMethod())) { - GetMessagesRequest.parseFrom(request.getData().getValue().toByteArray()); + /** + * {@inheritDoc} + */ + public void getMessages(io.dapr.it.MethodInvokeServiceProtos.GetMessagesRequest request, + io.grpc.stub.StreamObserver responseObserver) { + GetMessagesResponse res = GetMessagesResponse.newBuilder().putAllMessages(this.messages).build(); - GetMessagesResponse res = GetMessagesResponse.newBuilder().putAllMessages(this.messages).build(); + io.dapr.it.MethodInvokeServiceProtos.GetMessagesResponse.Builder responseBuilder + = io.dapr.it.MethodInvokeServiceProtos.GetMessagesResponse.newBuilder(); + responseObserver.onNext(res); + responseObserver.onCompleted(); + } - CommonProtos.InvokeResponse.Builder responseBuilder = CommonProtos.InvokeResponse.newBuilder(); - responseBuilder.setData(Any.pack(res)); - responseObserver.onNext(responseBuilder.build()); - } - if ("sleep".equals(request.getMethod())) { - SleepRequest req = SleepRequest.parseFrom(request.getData().getValue().toByteArray()); + /** + * {@inheritDoc} + */ + public void sleep(io.dapr.it.MethodInvokeServiceProtos.SleepRequest request, + io.grpc.stub.StreamObserver responseObserver) { + SleepResponse res = this.sleep(request); - SleepResponse res = this.sleep(req); - - CommonProtos.InvokeResponse.Builder responseBuilder = CommonProtos.InvokeResponse.newBuilder(); - responseBuilder.setData(Any.pack(res)); - responseObserver.onNext(responseBuilder.build()); - } - } catch (Exception e) { - responseObserver.onError(e); - } finally { - responseObserver.onCompleted(); - } + io.dapr.it.MethodInvokeServiceProtos.SleepResponse.Builder responseBuilder = + io.dapr.it.MethodInvokeServiceProtos.SleepResponse.newBuilder(); + responseObserver.onNext(responseBuilder.build()); + responseObserver.onCompleted(); } public SleepResponse sleep(SleepRequest request) { 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 0cf9e42f5..c1efb6716 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 @@ -40,7 +40,6 @@ public class MethodInvokeIT extends BaseIT { MethodInvokeService.class, true, 30000); - daprRun.switchToHTTP(); daprRun.waitForAppHealth(20000); } 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 77b917450..347bd64de 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 @@ -34,8 +34,7 @@ import io.dapr.serializer.DaprObjectSerializer; import io.dapr.utils.TypeRef; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.ArrayList; @@ -99,49 +98,26 @@ public class PubSubIT extends BaseIT { } } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void publishPubSubNotFound(boolean useGrpc) throws Exception { + @Test + public void publishPubSubNotFound() throws Exception { DaprRun daprRun = closeLater(startDaprApp( this.getClass().getSimpleName(), 60000)); - if (useGrpc) { - daprRun.switchToGRPC(); - } else { - daprRun.switchToHTTP(); - } try (DaprClient client = new DaprClientBuilder().build()) { - - if (useGrpc) { - assertThrowsDaprExceptionWithReason( - "INVALID_ARGUMENT", - "INVALID_ARGUMENT: pubsub unknown pubsub is not found", - "DAPR_PUBSUB_NOT_FOUND", - () -> client.publishEvent("unknown pubsub", "mytopic", "payload").block()); - } else { - assertThrowsDaprExceptionWithReason( - "ERR_PUBSUB_NOT_FOUND", - "ERR_PUBSUB_NOT_FOUND: pubsub unknown pubsub is not found", - "DAPR_PUBSUB_NOT_FOUND", - () -> client.publishEvent("unknown pubsub", "mytopic", "payload").block()); - } + assertThrowsDaprExceptionWithReason( + "INVALID_ARGUMENT", + "INVALID_ARGUMENT: pubsub unknown pubsub is not found", + "DAPR_PUBSUB_NOT_FOUND", + () -> client.publishEvent("unknown pubsub", "mytopic", "payload").block()); } } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void testBulkPublishPubSubNotFound(boolean useGrpc) throws Exception { + @Test + public void testBulkPublishPubSubNotFound() throws Exception { DaprRun daprRun = closeLater(startDaprApp( this.getClass().getSimpleName(), 60000)); - if (useGrpc) { - daprRun.switchToGRPC(); - } else { - // No HTTP implementation for bulk publish - System.out.println("no HTTP impl for bulkPublish"); - return; - } try (DaprPreviewClient client = new DaprClientBuilder().buildPreviewClient()) { assertThrowsDaprException( @@ -151,22 +127,14 @@ public class PubSubIT extends BaseIT { } } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void testBulkPublish(boolean useGrpc) throws Exception { + @Test + public void testBulkPublish() throws Exception { final DaprRun daprRun = closeLater(startDaprApp( this.getClass().getSimpleName(), SubscriberService.SUCCESS_MESSAGE, SubscriberService.class, true, 60000)); - // At this point, it is guaranteed that the service above is running and all ports being listened to. - if (useGrpc) { - daprRun.switchToGRPC(); - } else { - System.out.println("HTTP BulkPublish is not implemented. So skipping tests"); - return; - } DaprObjectSerializer serializer = new DaprObjectSerializer() { @Override public byte[] serialize(Object o) throws JsonProcessingException { @@ -287,21 +255,14 @@ public class PubSubIT extends BaseIT { } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void testPubSub(boolean useGrpc) throws Exception { + @Test + public void testPubSub() throws Exception { final DaprRun daprRun = closeLater(startDaprApp( this.getClass().getSimpleName(), SubscriberService.SUCCESS_MESSAGE, SubscriberService.class, true, 60000)); - // At this point, it is guaranteed that the service above is running and all ports being listened to. - if (useGrpc) { - daprRun.switchToGRPC(); - } else { - daprRun.switchToHTTP(); - } DaprObjectSerializer serializer = new DaprObjectSerializer() { @Override @@ -508,21 +469,14 @@ public class PubSubIT extends BaseIT { } } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void testPubSubBinary(boolean useGrpc) throws Exception { + @Test + public void testPubSubBinary() throws Exception { final DaprRun daprRun = closeLater(startDaprApp( this.getClass().getSimpleName(), SubscriberService.SUCCESS_MESSAGE, SubscriberService.class, true, 60000)); - // At this point, it is guaranteed that the service above is running and all ports being listened to. - if (useGrpc) { - daprRun.switchToGRPC(); - } else { - daprRun.switchToHTTP(); - } DaprObjectSerializer serializer = new DaprObjectSerializer() { @Override @@ -565,17 +519,11 @@ public class PubSubIT extends BaseIT { } } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void testPubSubTTLMetadata(boolean useGrpc) throws Exception { + @Test + public void testPubSubTTLMetadata() throws Exception { DaprRun daprRun = closeLater(startDaprApp( this.getClass().getSimpleName(), 60000)); - if (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()) { @@ -602,11 +550,6 @@ public class PubSubIT extends BaseIT { SubscriberService.class, true, 60000)); - if (useGrpc) { - daprRun.switchToGRPC(); - } else { - daprRun.switchToHTTP(); - } // Sleeps for five seconds to give subscriber a chance to receive messages. Thread.sleep(5000); @@ -623,20 +566,14 @@ public class PubSubIT extends BaseIT { daprRun.stop(); } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void testPubSubBulkSubscribe(boolean useGrpc) throws Exception { + @Test + public void testPubSubBulkSubscribe() throws Exception { DaprRun daprRun = closeLater(startDaprApp( this.getClass().getSimpleName(), SubscriberService.SUCCESS_MESSAGE, SubscriberService.class, true, 60000)); - if (useGrpc) { - daprRun.switchToGRPC(); - } else { - daprRun.switchToHTTP(); - } // Send a batch of messages on one topic. try (DaprClient client = new DaprClientBuilder().build()) { @@ -686,21 +623,14 @@ public class PubSubIT extends BaseIT { daprRun.stop(); } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void testLongValues(boolean useGrpc) throws Exception { + @Test + public void testLongValues() throws Exception { final DaprRun daprRun = closeLater(startDaprApp( this.getClass().getSimpleName(), SubscriberService.SUCCESS_MESSAGE, SubscriberService.class, true, 60000)); - // At this point, it is guaranteed that the service above is running and all ports being listened to. - if (useGrpc) { - daprRun.switchToGRPC(); - } else { - daprRun.switchToHTTP(); - } Random random = new Random(590518626939830271L); Set values = new HashSet<>(); 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 d98d1bd5c..9fc5df3ee 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 @@ -15,7 +15,12 @@ package io.dapr.it.pubsub.http; import io.dapr.Rule; import io.dapr.Topic; -import io.dapr.client.domain.*; +import io.dapr.client.domain.BulkSubscribeAppResponse; +import io.dapr.client.domain.BulkSubscribeAppResponseEntry; +import io.dapr.client.domain.BulkSubscribeAppResponseStatus; +import io.dapr.client.domain.BulkSubscribeMessage; +import io.dapr.client.domain.BulkSubscribeMessageEntry; +import io.dapr.client.domain.CloudEvent; import io.dapr.springboot.annotations.BulkSubscribe; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; diff --git a/sdk-tests/src/test/java/io/dapr/it/resiliency/SdkResiliencytIT.java b/sdk-tests/src/test/java/io/dapr/it/resiliency/SdkResiliencytIT.java index 49ead52e0..82646f639 100644 --- a/sdk-tests/src/test/java/io/dapr/it/resiliency/SdkResiliencytIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/resiliency/SdkResiliencytIT.java @@ -15,7 +15,7 @@ package io.dapr.it.resiliency; import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; -import io.dapr.client.DaprClientGrpc; +import io.dapr.client.DaprClientImpl; import io.dapr.client.resiliency.ResiliencyOptions; import io.dapr.it.BaseIT; import io.dapr.it.DaprRun; @@ -65,8 +65,6 @@ public class SdkResiliencytIT extends BaseIT { @BeforeAll public static void init() throws Exception { daprRun = startDaprApp(SdkResiliencytIT.class.getSimpleName(), 5000); - // HTTP client is deprecated, so SDK resiliency is for gRPC client only. - daprRun.switchToGRPC(); daprClient = new DaprClientBuilder().build(); daprClient.waitForSidecar(8000).block(); @@ -87,10 +85,10 @@ public class SdkResiliencytIT extends BaseIT { new ResiliencyOptions().setTimeout(TIMEOUT).setMaxRetries(1)) .build(); - assertTrue(daprClient instanceof DaprClientGrpc); - assertTrue(daprToxiClient instanceof DaprClientGrpc); - assertTrue(daprResilientClient instanceof DaprClientGrpc); - assertTrue(daprRetriesOnceClient instanceof DaprClientGrpc); + assertTrue(daprClient instanceof DaprClientImpl); + assertTrue(daprToxiClient instanceof DaprClientImpl); + assertTrue(daprResilientClient instanceof DaprClientImpl); + assertTrue(daprRetriesOnceClient instanceof DaprClientImpl); } @AfterAll 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 022f0bfcd..fc6260a68 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 @@ -19,23 +19,14 @@ import io.dapr.client.DaprClientBuilder; import io.dapr.it.BaseIT; import io.dapr.it.DaprRun; import org.apache.commons.io.IOUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -82,13 +73,8 @@ public class SecretsClientIT extends BaseIT { daprRun = startDaprApp(SecretsClientIT.class.getSimpleName(), 5000); } - public void setup(boolean useGrpc) { - if (useGrpc) { - daprRun.switchToGRPC(); - } else { - daprRun.switchToHTTP(); - } - + @BeforeEach + public void setup() { this.daprClient = new DaprClientBuilder().build(); } @@ -98,22 +84,16 @@ public class SecretsClientIT extends BaseIT { clearSecretFile(); } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void getSecret(boolean useGrpc) throws Exception { - setup(useGrpc); - + @Test + public void getSecret() throws Exception { Map data = daprClient.getSecret(SECRETS_STORE_NAME, KEY1).block(); assertEquals(2, data.size()); assertEquals("The Metrics IV", data.get("title")); assertEquals("2020", data.get("year")); } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void getBulkSecret(boolean useGrpc) throws Exception { - setup(useGrpc); - + @Test + public void getBulkSecret() throws Exception { 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); @@ -124,19 +104,13 @@ public class SecretsClientIT extends BaseIT { assertEquals("Jon Doe", data.get(KYE2).get("name")); } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void getSecretKeyNotFound(boolean useGrpc) { - setup(useGrpc); - + @Test + public void getSecretKeyNotFound() { assertThrows(RuntimeException.class, () -> daprClient.getSecret(SECRETS_STORE_NAME, "unknownKey").block()); } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void getSecretStoreNotFound(boolean useGrpc) throws Exception { - setup(useGrpc); - + @Test + public void getSecretStoreNotFound() { assertThrows(RuntimeException.class, () -> daprClient.getSecret("unknownStore", "unknownKey").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 a9dd05a4e..1c77d93d2 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 @@ -37,7 +37,6 @@ public class GRPCStateClientIT extends AbstractStateClientIT { @BeforeAll public static void init() throws Exception { daprRun = startDaprApp(GRPCStateClientIT.class.getSimpleName(), 5000); - daprRun.switchToGRPC(); daprClient = new DaprClientBuilder().build(); } diff --git a/sdk-tests/src/test/java/io/dapr/it/state/HelloWorldClientIT.java b/sdk-tests/src/test/java/io/dapr/it/state/HelloWorldClientIT.java index 577d8b72d..1cf8db98e 100644 --- a/sdk-tests/src/test/java/io/dapr/it/state/HelloWorldClientIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/state/HelloWorldClientIT.java @@ -13,9 +13,9 @@ limitations under the License. package io.dapr.it.state; +import io.dapr.config.Properties; import io.dapr.it.BaseIT; import io.dapr.it.DaprRun; -import io.dapr.config.Properties; import io.dapr.v1.DaprGrpc; import io.dapr.v1.DaprProtos; import io.grpc.ManagedChannel; 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 deleted file mode 100644 index 9a281bd02..000000000 --- a/sdk-tests/src/test/java/io/dapr/it/state/HttpStateClientIT.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2021 The Dapr Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io.dapr.it.state; - -import io.dapr.client.DaprClient; -import io.dapr.client.DaprClientBuilder; -import io.dapr.client.DaprClientHttp; -import io.dapr.client.domain.State; -import io.dapr.it.DaprRun; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import java.util.Collections; - -import static io.dapr.it.TestUtils.assertThrowsDaprException; -import static org.junit.jupiter.api.Assertions.assertTrue; - -/** - * Test State HTTP DAPR capabilities using a DAPR instance with an empty service running - */ -public class HttpStateClientIT extends AbstractStateClientIT { - - private static DaprRun daprRun; - - private static DaprClient daprClient; - - @BeforeAll - public static void init() throws Exception { - daprRun = startDaprApp(HttpStateClientIT.class.getSimpleName(), 5000); - daprRun.switchToHTTP(); - daprClient = new DaprClientBuilder().build(); - assertTrue(daprClient instanceof DaprClientHttp); - } - - @AfterAll - public static void tearDown() throws Exception { - daprClient.close(); - } - - @Override - protected DaprClient buildDaprClient() { - return daprClient; - } - - /** Tests where HTTP and GRPC behavior differ in Dapr runtime. **/ - - @Test - public void getStateStoreNotFound() { - final String stateKey = "key"; - - DaprClient daprClient = buildDaprClient(); - - // 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 state store is not found", - () -> daprClient.getState("unknown state store", new State(stateKey), byte[].class).block()); - } - - @Test - public void getStatesStoreNotFound() { - final String stateKey = "key"; - - DaprClient daprClient = buildDaprClient(); - - // 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 state store is not found", - () -> daprClient.getBulkState( - "unknown state store", - Collections.singletonList(stateKey), - byte[].class).block()); - } - - @Test - public void publishPubSubNotFound() { - DaprClient daprClient = buildDaprClient(); - - - } -} diff --git a/sdk-tests/src/test/java/io/dapr/it/tracing/grpc/TracingIT.java b/sdk-tests/src/test/java/io/dapr/it/tracing/grpc/TracingIT.java index e82aa248c..e1f4c729f 100644 --- a/sdk-tests/src/test/java/io/dapr/it/tracing/grpc/TracingIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/tracing/grpc/TracingIT.java @@ -1,9 +1,9 @@ package io.dapr.it.tracing.grpc; -import io.dapr.client.DaprApiProtocol; import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; import io.dapr.client.domain.HttpExtension; +import io.dapr.it.AppRun; import io.dapr.it.BaseIT; import io.dapr.it.DaprRun; import io.dapr.it.tracing.Validation; @@ -12,8 +12,8 @@ import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Scope; import io.opentelemetry.sdk.OpenTelemetrySdk; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.util.UUID; @@ -28,28 +28,20 @@ public class TracingIT extends BaseIT { */ private DaprRun daprRun = null; - public void setup(boolean useGrpc) throws Exception { + @BeforeEach + public void setup() throws Exception { daprRun = startDaprApp( TracingIT.class.getSimpleName() + "grpc", Service.SUCCESS_MESSAGE, Service.class, - DaprApiProtocol.GRPC, // appProtocol + AppRun.AppProtocol.GRPC, // appProtocol 60000); - if (useGrpc) { - daprRun.switchToGRPC(); - } else { - daprRun.switchToHTTP(); - } - daprRun.waitForAppHealth(10000); } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void testInvoke(boolean useGrpc) throws Exception { - setup(useGrpc); - + @Test + public void testInvoke() throws Exception { final OpenTelemetry openTelemetry = createOpenTelemetry("service over grpc"); final Tracer tracer = openTelemetry.getTracer("grpc integration test tracer"); diff --git a/sdk-tests/src/test/java/io/dapr/it/tracing/http/OpenTelemetryInterceptor.java b/sdk-tests/src/test/java/io/dapr/it/tracing/http/OpenTelemetryInterceptor.java index 91bedea53..646a5f5a5 100644 --- a/sdk-tests/src/test/java/io/dapr/it/tracing/http/OpenTelemetryInterceptor.java +++ b/sdk-tests/src/test/java/io/dapr/it/tracing/http/OpenTelemetryInterceptor.java @@ -16,14 +16,14 @@ package io.dapr.it.tracing.http; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.context.Context; import io.opentelemetry.context.propagation.TextMapPropagator; +import jakarta.servlet.DispatcherType; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; -import jakarta.servlet.DispatcherType; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.util.Collections; @Component diff --git a/sdk-tests/src/test/java/io/dapr/it/tracing/http/TracingIT.java b/sdk-tests/src/test/java/io/dapr/it/tracing/http/TracingIT.java index 96b669ef7..8e28159f9 100644 --- a/sdk-tests/src/test/java/io/dapr/it/tracing/http/TracingIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/tracing/http/TracingIT.java @@ -11,8 +11,8 @@ import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Scope; import io.opentelemetry.sdk.OpenTelemetrySdk; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.util.UUID; @@ -26,7 +26,8 @@ public class TracingIT extends BaseIT { */ private DaprRun daprRun = null; - public void setup(boolean useGrpc) throws Exception { + @BeforeEach + public void setup() throws Exception { daprRun = startDaprApp( TracingIT.class.getSimpleName() + "http", Service.SUCCESS_MESSAGE, @@ -34,21 +35,12 @@ public class TracingIT extends BaseIT { true, 30000); - if (useGrpc) { - daprRun.switchToGRPC(); - } else { - daprRun.switchToHTTP(); - } - // Wait since service might be ready even after port is available. Thread.sleep(2000); } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void testInvoke(boolean useGrpc) throws Exception { - setup(useGrpc); - + @Test + public void testInvoke() throws Exception { final OpenTelemetry openTelemetry = createOpenTelemetry(OpenTelemetryConfig.SERVICE_NAME); final Tracer tracer = openTelemetry.getTracer(OpenTelemetryConfig.TRACER_NAME); diff --git a/sdk/src/main/java/io/dapr/client/AbstractDaprClient.java b/sdk/src/main/java/io/dapr/client/AbstractDaprClient.java index 95d7ef37f..c9660ca22 100644 --- a/sdk/src/main/java/io/dapr/client/AbstractDaprClient.java +++ b/sdk/src/main/java/io/dapr/client/AbstractDaprClient.java @@ -59,7 +59,7 @@ import java.util.stream.Collectors; * Abstract class with convenient methods common between client implementations. * * @see io.dapr.client.DaprClient - * @see io.dapr.client.DaprClientGrpc + * @see DaprClientImpl * @see io.dapr.client.DaprClientHttp */ abstract class AbstractDaprClient implements DaprClient, DaprPreviewClient { diff --git a/sdk/src/main/java/io/dapr/client/DaprApiProtocol.java b/sdk/src/main/java/io/dapr/client/DaprApiProtocol.java deleted file mode 100644 index a4d3fc3bf..000000000 --- a/sdk/src/main/java/io/dapr/client/DaprApiProtocol.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2021 The Dapr Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io.dapr.client; - -/** - * Transport protocol for Dapr's API. - * @deprecated This class will be deleted at SDK version 1.10. - */ -@Deprecated -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 f625aee76..fe01b356b 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClient.java +++ b/sdk/src/main/java/io/dapr/client/DaprClient.java @@ -34,11 +34,14 @@ import io.dapr.client.domain.TransactionalStateOperation; import io.dapr.client.domain.UnsubscribeConfigurationRequest; import io.dapr.client.domain.UnsubscribeConfigurationResponse; import io.dapr.utils.TypeRef; +import io.grpc.Channel; +import io.grpc.stub.AbstractStub; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.List; import java.util.Map; +import java.util.function.Function; /** * Generic Client Adapter to be used regardless of the GRPC or the HTTP Client implementation required. @@ -659,6 +662,15 @@ public interface DaprClient extends AutoCloseable { */ Mono unsubscribeConfiguration(UnsubscribeConfigurationRequest request); + /** + * Returns a newly created gRPC stub with proper interceptors and channel for gRPC proxy invocation. + * @param appId appId to be included in all gRPC calls for service invocation. + * @param stubBuilder user-provided callback method to construct a new stub given the channel. + * @return the gRPC stub with proper interceptors and channel. + * @param the generic type of the service to be invoked. + */ + > T newGrpcStub(String appId, Function stubBuilder); + /** * Gracefully shutdown the dapr runtime. * diff --git a/sdk/src/main/java/io/dapr/client/DaprClientBuilder.java b/sdk/src/main/java/io/dapr/client/DaprClientBuilder.java index dc67d019c..f57f122d2 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientBuilder.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientBuilder.java @@ -14,14 +14,11 @@ limitations under the License. package io.dapr.client; import io.dapr.client.resiliency.ResiliencyOptions; -import io.dapr.config.Properties; import io.dapr.serializer.DaprObjectSerializer; import io.dapr.serializer.DefaultObjectSerializer; import io.dapr.utils.NetworkUtils; import io.dapr.v1.DaprGrpc; import io.grpc.ManagedChannel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * A builder for the DaprClient, @@ -29,18 +26,6 @@ import org.slf4j.LoggerFactory; */ public class DaprClientBuilder { - private static final Logger LOGGER = LoggerFactory.getLogger(DaprClientBuilder.class); - - /** - * Determine if this builder will create GRPC clients instead of HTTP clients. - */ - 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. */ @@ -70,8 +55,6 @@ public class DaprClientBuilder { public DaprClientBuilder() { this.objectSerializer = new DefaultObjectSerializer(); this.stateSerializer = new DefaultObjectSerializer(); - this.apiProtocol = Properties.API_PROTOCOL.get(); - this.methodInvocationApiProtocol = Properties.API_METHOD_INVOCATION_PROTOCOL.get(); this.daprHttpBuilder = new DaprHttpBuilder(); } @@ -129,15 +112,7 @@ public class DaprClientBuilder { * @throws java.lang.IllegalStateException if any required field is missing */ public DaprClient build() { - if (this.apiProtocol == DaprApiProtocol.HTTP) { - LOGGER.warn("HTTP client protocol is deprecated and will be removed in Dapr's Java SDK version 1.10."); - } - - if (this.apiProtocol != this.methodInvocationApiProtocol) { - return new DaprClientProxy(buildDaprClient(this.apiProtocol), buildDaprClient(this.methodInvocationApiProtocol)); - } - - return buildDaprClient(this.apiProtocol); + return buildDaprClient(); } /** @@ -147,26 +122,7 @@ public class DaprClientBuilder { * @throws IllegalStateException if any required field is missing */ public DaprPreviewClient buildPreviewClient() { - return (DaprPreviewClient) 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."); - } - - switch (protocol) { - case GRPC: return buildDaprClientGrpc(); - case HTTP: return buildDaprClientHttp(); - default: throw new IllegalStateException("Unsupported protocol: " + protocol.name()); - } + return buildDaprClient(); } /** @@ -175,25 +131,17 @@ public class DaprClientBuilder { * @return the GRPC Client. * @throws java.lang.IllegalStateException if either host is missing or if port is missing or a negative number. */ - private DaprClient buildDaprClientGrpc() { + private DaprClientImpl buildDaprClient() { final ManagedChannel channel = NetworkUtils.buildGrpcManagedChannel(); - final GrpcChannelFacade channelFacade = new GrpcChannelFacade(channel, this.daprHttpBuilder.build()); + final DaprHttp daprHttp = this.daprHttpBuilder.build(); + final GrpcChannelFacade channelFacade = new GrpcChannelFacade(channel); DaprGrpc.DaprStub asyncStub = DaprGrpc.newStub(channel); - return new DaprClientGrpc( + return new DaprClientImpl( channelFacade, asyncStub, + daprHttp, this.objectSerializer, this.stateSerializer, this.resiliencyOptions); } - - /** - * Creates and instance of DaprClient over HTTP. - * - * @return DaprClient over HTTP. - */ - private DaprClient buildDaprClientHttp() { - return new DaprClientHttp(this.daprHttpBuilder.build(), this.objectSerializer, this.stateSerializer); - } - } diff --git a/sdk/src/main/java/io/dapr/client/DaprClientHttp.java b/sdk/src/main/java/io/dapr/client/DaprClientHttp.java deleted file mode 100644 index f9a01f984..000000000 --- a/sdk/src/main/java/io/dapr/client/DaprClientHttp.java +++ /dev/null @@ -1,1069 +0,0 @@ -/* - * Copyright 2021 The Dapr Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io.dapr.client; - -import com.fasterxml.jackson.databind.JsonNode; -import com.google.common.base.Strings; -import io.dapr.client.domain.BulkPublishRequest; -import io.dapr.client.domain.BulkPublishResponse; -import io.dapr.client.domain.ConfigurationItem; -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.GetConfigurationRequest; -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.LockRequest; -import io.dapr.client.domain.Metadata; -import io.dapr.client.domain.PublishEventRequest; -import io.dapr.client.domain.QueryStateItem; -import io.dapr.client.domain.QueryStateRequest; -import io.dapr.client.domain.QueryStateResponse; -import io.dapr.client.domain.SaveStateRequest; -import io.dapr.client.domain.State; -import io.dapr.client.domain.StateOptions; -import io.dapr.client.domain.SubscribeConfigurationRequest; -import io.dapr.client.domain.SubscribeConfigurationResponse; -import io.dapr.client.domain.TransactionalStateOperation; -import io.dapr.client.domain.TransactionalStateRequest; -import io.dapr.client.domain.UnlockRequest; -import io.dapr.client.domain.UnlockResponseStatus; -import io.dapr.client.domain.UnsubscribeConfigurationRequest; -import io.dapr.client.domain.UnsubscribeConfigurationResponse; -import io.dapr.config.Properties; -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 reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.util.retry.Retry; - -import java.io.IOException; -import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - - -/** - * An adapter for the HTTP Client. - * @deprecated This class will be deleted at SDK release version 1.10. - * @see io.dapr.client.DaprHttp - * @see io.dapr.client.DaprClient - */ -@Deprecated -public class DaprClientHttp extends AbstractDaprClient { - /** - * Header for the conditional operation. - */ - private static final String HEADER_HTTP_ETAG_ID = "If-Match"; - - /** - * Metadata prefix in query params. - */ - private static final String METADATA_PREFIX = "metadata."; - - /** - * Serializer for internal objects. - */ - private static final ObjectSerializer INTERNAL_SERIALIZER = new ObjectSerializer(); - - /** - * The HTTP client to be used. - * - * @see io.dapr.client.DaprHttp - */ - private final DaprHttp client; - - /** - * Flag determining if object serializer's input and output is Dapr's default instead of user provided. - */ - private final boolean isObjectSerializerDefault; - - /** - * Flag determining if state serializer is the default serializer instead of user provided. - */ - private final boolean isStateSerializerDefault; - - /** - * Default access level constructor, in order to create an instance of this class use io.dapr.client.DaprClientBuilder - * - * @param client Dapr's http client. - * @param objectSerializer Dapr's serializer for transient request/response objects. - * @param stateSerializer Dapr's serializer for state objects. - * @see DaprClientBuilder - * @see DefaultObjectSerializer - */ - DaprClientHttp(DaprHttp client, DaprObjectSerializer objectSerializer, DaprObjectSerializer stateSerializer) { - super(objectSerializer, stateSerializer); - this.client = client; - this.isObjectSerializerDefault = objectSerializer.getClass() == DefaultObjectSerializer.class; - this.isStateSerializerDefault = stateSerializer.getClass() == DefaultObjectSerializer.class; - } - - /** - * Constructor useful for tests. - * - * @param client Dapr's http client. - * @see io.dapr.client.DaprClientBuilder - * @see DefaultObjectSerializer - */ - DaprClientHttp(DaprHttp client) { - this(client, new DefaultObjectSerializer(), new DefaultObjectSerializer()); - } - - /** - * {@inheritDoc} - */ - @Override - public Mono waitForSidecar(int timeoutInMilliseconds) { - return Mono.defer(() -> { - String[] pathSegments = new String[] { DaprHttp.API_VERSION, "healthz", "outbound"}; - int maxRetries = 5; - - Retry retrySpec = Retry - .fixedDelay(maxRetries, Duration.ofMillis(500)) - .doBeforeRetry(retrySignal -> { - System.out.println("Retrying component health check..."); - }); - - Mono responseMono = this.client.invokeApi(DaprHttp.HttpMethods.GET.name(), pathSegments, - null, "", null, null); - - return responseMono - .retryWhen(retrySpec) - .timeout(Duration.ofMillis(timeoutInMilliseconds)) - .onErrorResume(DaprException.class, e -> - Mono.error(new RuntimeException(e))) - .switchIfEmpty(DaprException.wrapMono(new RuntimeException("Health check timed out"))) - .then(); - }); - } - - /** - * {@inheritDoc} - */ - @Override - public Mono publishEvent(PublishEventRequest request) { - try { - String pubsubName = request.getPubsubName(); - String topic = request.getTopic(); - - if (pubsubName == null || pubsubName.trim().isEmpty()) { - throw new IllegalArgumentException("Pubsub name cannot be null or empty."); - } - - if (topic == null || topic.trim().isEmpty()) { - throw new IllegalArgumentException("Topic name cannot be null or empty."); - } - - Object data = request.getData(); - Map metadata = request.getMetadata(); - - byte[] serializedEvent = objectSerializer.serialize(data); - // Content-type can be overwritten on a per-request basis. - // It allows CloudEvents to be handled differently, for example. - String contentType = request.getContentType(); - if (contentType == null || contentType.isEmpty()) { - contentType = objectSerializer.getContentType(); - } - Map headers = Collections.singletonMap("content-type", contentType); - - String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "publish", pubsubName, topic }; - - Map> queryArgs = metadataToQueryArgs(metadata); - return Mono.deferContextual( - context -> this.client.invokeApi( - DaprHttp.HttpMethods.POST.name(), pathSegments, queryArgs, serializedEvent, headers, context - ) - ).then(); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - } - - /** - * {@inheritDoc} - */ - @Override - public Mono> publishEvents(BulkPublishRequest request) { - return DaprException.wrapMono(new UnsupportedOperationException()); - } - - /** - * {@inheritDoc} - */ - @Override - public Mono invokeMethod(InvokeMethodRequest invokeMethodRequest, TypeRef type) { - try { - 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 Map metadata = invokeMethodRequest.getMetadata(); - - 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 - 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[] methodSegments = method.split("/"); - - List pathSegments = new ArrayList<>(Arrays.asList(DaprHttp.API_VERSION, "invoke", appId, "method")); - pathSegments.addAll(Arrays.asList(methodSegments)); - - final Map headers = new HashMap<>(); - headers.putAll(httpExtension.getHeaders()); - if (metadata != null) { - headers.putAll(metadata); - } - byte[] serializedRequestBody = objectSerializer.serialize(request); - if (contentType != null && !contentType.isEmpty()) { - headers.put(Metadata.CONTENT_TYPE, contentType); - } else { - headers.put(Metadata.CONTENT_TYPE, objectSerializer.getContentType()); - } - Mono response = Mono.deferContextual( - context -> this.client.invokeApi(httpMethod, pathSegments.toArray(new String[0]), - httpExtension.getQueryParams(), serializedRequestBody, headers, context) - ); - return response.flatMap(r -> getMono(type, 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); - } - } - - /** - * {@inheritDoc} - */ - @Override - public Mono invokeBinding(InvokeBindingRequest request, TypeRef type) { - try { - final String name = request.getName(); - final String operation = request.getOperation(); - final Object data = request.getData(); - final Map metadata = request.getMetadata(); - if (name == null || name.trim().isEmpty()) { - throw new IllegalArgumentException("Binding name cannot be null or empty."); - } - - if (operation == null || operation.trim().isEmpty()) { - throw new IllegalArgumentException("Binding operation cannot be null or empty."); - } - - Map jsonMap = new HashMap<>(); - jsonMap.put("operation", operation); - if (metadata != null) { - jsonMap.put("metadata", metadata); - } - - if (data != null) { - if (this.isObjectSerializerDefault) { - // If we are using Dapr's default serializer, we pass the object directly and skip objectSerializer. - // This allows binding to receive JSON directly without having to extract it from a quoted string. - // Example of output binding vs body in the input binding: - // This logic DOES this: - // Output Binding: { "data" : { "mykey": "myvalue" } } - // Input Binding: { "mykey": "myvalue" } - // This logic AVOIDS this: - // Output Binding: { "data" : "{ \"mykey\": \"myvalue\" }" } - // Input Binding: "{ \"mykey\": \"myvalue\" }" - jsonMap.put("data", data); - } else { - // When customer provides a custom serializer, he will get a Base64 encoded String back - always. - // Example of body in the input binding resulting from this logic: - // { "data" : "eyJrZXkiOiAidmFsdWUifQ==" } - jsonMap.put("data", objectSerializer.serialize(data)); - } - } - - byte[] payload = INTERNAL_SERIALIZER.serialize(jsonMap); - String httpMethod = DaprHttp.HttpMethods.POST.name(); - - String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "bindings", name }; - - Mono response = Mono.deferContextual( - context -> this.client.invokeApi( - httpMethod, pathSegments, null, payload, null, context) - ); - return response.flatMap(r -> getMono(type, r)); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - } - - /** - * {@inheritDoc} - */ - @Override - public Mono>> getBulkState(GetBulkStateRequest request, TypeRef type) { - try { - final String stateStoreName = request.getStoreName(); - final List keys = request.getKeys(); - final int parallelism = request.getParallelism(); - final Map metadata = request.getMetadata(); - if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { - throw new IllegalArgumentException("State store name cannot be null or empty."); - } - if (keys == null || keys.isEmpty()) { - throw new IllegalArgumentException("Key cannot be null or empty."); - } - - if (parallelism < 0) { - throw new IllegalArgumentException("Parallelism cannot be negative."); - } - - 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 Mono.deferContextual( - context -> this.client - .invokeApi(DaprHttp.HttpMethods.POST.name(), pathSegments, queryArgs, requestBody, null, context) - ).flatMap(s -> { - try { - return Mono.just(buildStates(s, type)); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - }); - - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - } - - - /** - * {@inheritDoc} - */ - @Override - public Mono> getState(GetStateRequest request, TypeRef type) { - try { - final String stateStoreName = request.getStoreName(); - final String key = request.getKey(); - final StateOptions options = request.getStateOptions(); - final Map metadata = request.getMetadata(); - - if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { - throw new IllegalArgumentException("State store name cannot be null or empty."); - } - if ((key == null) || (key.trim().isEmpty())) { - throw new IllegalArgumentException("Key cannot be null or empty."); - } - Map optionsMap = Optional.ofNullable(options) - .map(o -> o.getStateOptionsAsMap()) - .orElse(Collections.emptyMap()); - - final Map> queryParams = new HashMap<>(); - queryParams.putAll(metadataToQueryArgs(metadata)); - queryParams.putAll(optionsMap.entrySet().stream().collect( - Collectors.toMap(kv -> kv.getKey(), kv -> Collections.singletonList(kv.getValue())))); - - String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "state", stateStoreName, key }; - - return Mono.deferContextual( - context -> this.client - .invokeApi(DaprHttp.HttpMethods.GET.name(), pathSegments, queryParams, null, context) - ).flatMap(s -> { - try { - return Mono.justOrEmpty(buildState(s, key, options, type)); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - }); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - } - - /** - * {@inheritDoc} - */ - @Override - public Mono executeStateTransaction(ExecuteStateTransactionRequest request) { - try { - final String stateStoreName = request.getStateStoreName(); - final List> operations = request.getOperations(); - final Map metadata = request.getMetadata(); - if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { - throw new IllegalArgumentException("State store name cannot be null or empty."); - } - if (operations == null || operations.isEmpty()) { - return Mono.empty(); - } - - List> internalOperationObjects = new ArrayList<>(operations.size()); - for (TransactionalStateOperation operation : operations) { - if (operation == null) { - continue; - } - State state = operation.getRequest(); - if (state == null) { - continue; - } - if (this.isStateSerializerDefault) { - // If default serializer is being used, we just pass the object through to be serialized directly. - // This avoids a JSON object from being quoted inside a string. - // We WANT this: { "value" : { "myField" : 123 } } - // We DON't WANT this: { "value" : "{ \"myField\" : 123 }" } - internalOperationObjects.add(operation); - continue; - } - byte[] data = this.stateSerializer.serialize(state.getValue()); - // Custom serializer, so everything is byte[]. - internalOperationObjects.add(new TransactionalStateOperation<>(operation.getOperation(), - new State<>(state.getKey(), data, state.getEtag(), state.getMetadata(), state.getOptions()))); - } - TransactionalStateRequest req = new TransactionalStateRequest<>(internalOperationObjects, metadata); - byte[] serializedOperationBody = INTERNAL_SERIALIZER.serialize(req); - - String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "state", stateStoreName, "transaction" }; - - return Mono.deferContextual( - context -> this.client.invokeApi( - DaprHttp.HttpMethods.POST.name(), pathSegments, null, serializedOperationBody, null, context - ) - ).then(); - } catch (Exception e) { - return DaprException.wrapMono(e); - } - } - - /** - * {@inheritDoc} - */ - @Override - public Mono saveBulkState(SaveStateRequest request) { - try { - final String stateStoreName = request.getStoreName(); - final List> states = request.getStates(); - if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { - throw new IllegalArgumentException("State store name cannot be null or empty."); - } - if (states == null || states.isEmpty()) { - return Mono.empty(); - } - - List> internalStateObjects = new ArrayList<>(states.size()); - for (State state : states) { - if (state == null) { - continue; - } - if (this.isStateSerializerDefault) { - // If default serializer is being used, we just pass the object through to be serialized directly. - // This avoids a JSON object from being quoted inside a string. - // We WANT this: { "value" : { "myField" : 123 } } - // We DON't WANT this: { "value" : "{ \"myField\" : 123 }" } - internalStateObjects.add(state); - continue; - } - - byte[] data = this.stateSerializer.serialize(state.getValue()); - // Custom serializer, so everything is byte[]. - internalStateObjects.add(new State<>(state.getKey(), data, state.getEtag(), state.getMetadata(), - state.getOptions())); - } - byte[] serializedStateBody = INTERNAL_SERIALIZER.serialize(internalStateObjects); - - String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "state", stateStoreName }; - - return Mono.deferContextual( - context -> this.client.invokeApi( - DaprHttp.HttpMethods.POST.name(), pathSegments, null, serializedStateBody, null, context) - ).then(); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - } - - /** - * {@inheritDoc} - */ - @Override - public Mono deleteState(DeleteStateRequest request) { - try { - final String stateStoreName = request.getStateStoreName(); - final String key = request.getKey(); - final StateOptions options = request.getStateOptions(); - final String etag = request.getEtag(); - final Map metadata = request.getMetadata(); - - if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { - throw new IllegalArgumentException("State store name cannot be null or empty."); - } - 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); - } - - Map optionsMap = Optional.ofNullable(options) - .map(o -> o.getStateOptionsAsMap()) - .orElse(Collections.emptyMap()); - - final Map> queryParams = new HashMap<>(); - queryParams.putAll(metadataToQueryArgs(metadata)); - queryParams.putAll(optionsMap.entrySet().stream().collect( - Collectors.toMap(kv -> kv.getKey(), kv -> Collections.singletonList(kv.getValue())))); - - String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "state", stateStoreName, key }; - - return Mono.deferContextual( - context -> this.client.invokeApi( - DaprHttp.HttpMethods.DELETE.name(), pathSegments, queryParams, headers, context) - ).then(); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - } - - /** - * Builds a State object based on the Response. - * - * @param response The response of the HTTP Call - * @param requestedKey The Key Requested. - * @param type The Class of the Value of the state - * @param The Type of the Value of the state - * @return A State instance - * @throws IOException If there's a issue deserializing the response. - */ - private State buildState( - DaprHttp.Response response, String requestedKey, StateOptions stateOptions, TypeRef type) throws IOException { - // The state is in the body directly, so we use the state serializer here. - T value = stateSerializer.deserialize(response.getBody(), type); - String etag = null; - if (response.getHeaders() != null && response.getHeaders().containsKey("Etag")) { - etag = response.getHeaders().get("Etag"); - } - return new State<>(requestedKey, value, etag, Collections.emptyMap(), stateOptions); - } - - /** - * Builds a State object based on the Response. - * - * @param response The response of the HTTP Call - * @param type The Class of the Value of the state - * @param The Type of the Value of the state - * @return A list of states. - * @throws IOException If there's a issue deserializing the response. - */ - private List> buildStates( - DaprHttp.Response response, TypeRef type) throws IOException { - JsonNode root = INTERNAL_SERIALIZER.parseNode(response.getBody()); - List> result = new ArrayList<>(); - for (Iterator it = root.elements(); it.hasNext(); ) { - JsonNode node = it.next(); - String key = node.path("key").asText(); - String error = node.path("error").asText(); - if (!Strings.isNullOrEmpty(error)) { - result.add(new State<>(key, error)); - continue; - } - - 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()); - T value = stateSerializer.deserialize(data, type); - result.add(new State<>(key, value, etag)); - } - - return result; - } - - /** - * {@inheritDoc} - */ - @Override - public Mono> getSecret(GetSecretRequest request) { - String secretStoreName = request.getStoreName(); - String key = request.getKey(); - Map metadata = request.getMetadata(); - try { - if ((secretStoreName == null) || (secretStoreName.trim().isEmpty())) { - throw new IllegalArgumentException("Secret store name cannot be null or empty."); - } - if ((key == null) || (key.trim().isEmpty())) { - throw new IllegalArgumentException("Secret key cannot be null or empty."); - } - } catch (Exception e) { - return DaprException.wrapMono(e); - } - - Map> queryArgs = metadataToQueryArgs(metadata); - String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "secrets", secretStoreName, key }; - - return Mono.deferContextual( - context -> 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); - } - - /** - * {@inheritDoc} - */ - @Override - public Mono>> getBulkSecret(GetBulkSecretRequest request) { - String secretStoreName = request.getStoreName(); - Map metadata = request.getMetadata(); - try { - if ((secretStoreName == null) || (secretStoreName.trim().isEmpty())) { - throw new IllegalArgumentException("Secret store name cannot be null or empty."); - } - } catch (Exception e) { - return DaprException.wrapMono(e); - } - - Map> queryArgs = metadataToQueryArgs(metadata); - String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "secrets", secretStoreName, "bulk" }; - - return Mono.deferContextual( - context -> 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); - } - - /** - * {@inheritDoc} - */ - @Override - public Mono tryLock(LockRequest request) { - try { - final String stateStoreName = request.getStoreName(); - final String resourceId = request.getResourceId(); - final String lockOwner = request.getLockOwner(); - final Integer expiryInSeconds = request.getExpiryInSeconds(); - - if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { - throw new IllegalArgumentException("State store name cannot be null or empty."); - } - if (resourceId == null || resourceId.isEmpty()) { - throw new IllegalArgumentException("ResourceId cannot be null or empty."); - } - if (lockOwner == null || lockOwner.isEmpty()) { - throw new IllegalArgumentException("LockOwner cannot be null or empty."); - } - if (expiryInSeconds < 0) { - throw new IllegalArgumentException("ExpiryInSeconds cannot be negative."); - } - - byte[] requestBody = INTERNAL_SERIALIZER.serialize(request); - - String[] pathSegments = new String[]{DaprHttp.ALPHA_1_API_VERSION, "lock", stateStoreName}; - - return Mono.deferContextual( - context -> this.client - .invokeApi(DaprHttp.HttpMethods.POST.name(), pathSegments, null, requestBody, null, context) - ).flatMap(response -> { - try { - Map m = INTERNAL_SERIALIZER.deserialize(response.getBody(), Map.class); - if (m == null) { - return Mono.just(Boolean.FALSE); - } - return Mono.just((Boolean) m.get("success")); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - }); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - } - - /** - * {@inheritDoc} - */ - @Override - public Mono unlock(UnlockRequest request) { - try { - final String stateStoreName = request.getStoreName(); - final String resourceId = request.getResourceId(); - final String lockOwner = request.getLockOwner(); - - if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { - throw new IllegalArgumentException("State store name cannot be null or empty."); - } - if (resourceId == null || resourceId.isEmpty()) { - throw new IllegalArgumentException("ResourceId cannot be null or empty."); - } - if (lockOwner == null || lockOwner.isEmpty()) { - throw new IllegalArgumentException("LockOwner cannot be null or empty."); - } - - byte[] requestBody = INTERNAL_SERIALIZER.serialize(request); - - String[] pathSegments = new String[]{DaprHttp.ALPHA_1_API_VERSION, "unlock", stateStoreName}; - - return Mono.deferContextual( - context -> this.client - .invokeApi(DaprHttp.HttpMethods.POST.name(), pathSegments, null, requestBody, null, context) - ).flatMap(response -> { - try { - Map m = INTERNAL_SERIALIZER.deserialize(response.getBody(), Map.class); - if (m == null) { - return Mono.just(UnlockResponseStatus.INTERNAL_ERROR); - } - - Integer statusCode = (Integer) m.get("status"); - - return Mono.just(UnlockResponseStatus.valueOf(statusCode)); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - }); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - } - - /** - * {@inheritDoc} - */ - @Override - public Mono> queryState(QueryStateRequest request, TypeRef type) { - try { - if (request == null) { - throw new IllegalArgumentException("Query state request cannot be null."); - } - String stateStoreName = request.getStoreName(); - Map metadata = request.getMetadata(); - if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { - throw new IllegalArgumentException("State store name cannot be null or empty."); - } - Map> queryArgs = metadataToQueryArgs(metadata); - String[] pathSegments = new String[]{ DaprHttp.ALPHA_1_API_VERSION, "state", stateStoreName, "query" }; - String serializedRequest; - if (request.getQuery() != null) { - serializedRequest = JSON_REQUEST_MAPPER.writeValueAsString(request.getQuery()); - } else if (request.getQueryString() != null) { - serializedRequest = request.getQueryString(); - } else { - throw new IllegalArgumentException("Both query and queryString fields are not set."); - } - return Mono.deferContextual( - context -> this.client - .invokeApi(DaprHttp.HttpMethods.POST.name(), pathSegments, - queryArgs, serializedRequest, null, context) - ).flatMap(response -> { - try { - return Mono.justOrEmpty(buildQueryStateResponse(response, type)); - } catch (Exception e) { - return DaprException.wrapMono(e); - } - }); - } catch (Exception e) { - return DaprException.wrapMono(e); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void close() { - client.close(); - } - - /** - * {@inheritDoc} - */ - @Override - public Mono shutdown() { - String[] pathSegments = new String[]{ DaprHttp.API_VERSION, "shutdown" }; - return Mono.deferContextual( - context -> client.invokeApi(DaprHttp.HttpMethods.POST.name(), pathSegments, - null, null, context)) - .then(); - } - - private QueryStateResponse buildQueryStateResponse(DaprHttp.Response response, - TypeRef type) throws IOException { - JsonNode root = INTERNAL_SERIALIZER.parseNode(response.getBody()); - if (!root.has("results")) { - return new QueryStateResponse<>(Collections.emptyList(), null); - } - String token = null; - if (root.has("token")) { - token = root.path("token").asText(); - } - Map metadata = new HashMap<>(); - if (root.has("metadata")) { - for (Iterator> it = root.get("metadata").fields(); it.hasNext(); ) { - Map.Entry entry = it.next(); - metadata.put(entry.getKey(), entry.getValue().asText()); - } - } - List> result = new ArrayList<>(); - for (Iterator it = root.get("results").elements(); it.hasNext(); ) { - JsonNode node = it.next(); - String key = node.path("key").asText(); - String error = node.path("error").asText(); - if (!Strings.isNullOrEmpty(error)) { - result.add(new QueryStateItem<>(key, null, error)); - continue; - } - - 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()); - T value = stateSerializer.deserialize(data, type); - result.add(new QueryStateItem<>(key, value, etag)); - } - - return new QueryStateResponse<>(result, token).setMetadata(metadata); - } - - /** - * {@inheritDoc} - */ - @Override - public Mono> getConfiguration(GetConfigurationRequest request) { - try { - final String configurationStoreName = request.getStoreName(); - final List keys = request.getKeys(); - final Map metadata = request.getMetadata(); - - if ((configurationStoreName == null) || (configurationStoreName.trim().isEmpty())) { - throw new IllegalArgumentException("Configuration Store Name cannot be null or empty."); - } - - Map> queryParams = new HashMap<>(); - if (!keys.isEmpty()) { - queryParams.put("key", Collections.unmodifiableList(keys)); - } - - // Appending passed metadata too into queryparams - Map> queryArgs = metadataToQueryArgs(metadata); - queryParams.putAll(queryArgs); - - String[] pathSegments = new String[] {DaprHttp.API_VERSION, "configuration", configurationStoreName }; - return Mono.deferContextual( - context -> this.client - .invokeApi( - DaprHttp.HttpMethods.GET.name(), - pathSegments, queryParams, - (String) null, null, context) - ).map( - response -> { - try { - Map m = INTERNAL_SERIALIZER.deserialize(response.getBody(), Map.class); - Set set = m.keySet(); - JsonNode root = INTERNAL_SERIALIZER.parseNode(response.getBody()); - Iterator itr = set.iterator(); - Map result = new HashMap<>(); - while (itr.hasNext()) { - String key = itr.next(); - String value = root.get(key).path("value").asText(); - String version = root.get(key).path("version").asText(); - result.put(key, new ConfigurationItem( - key, - value, - version, - new HashMap<>() - )); - } - return Collections.unmodifiableMap(result); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - ); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - } - - /** - * {@inheritDoc} - */ - @Override - public Flux subscribeConfiguration(SubscribeConfigurationRequest request) { - try { - final String configurationStoreName = request.getStoreName(); - final List keys = request.getKeys(); - final Map metadata = request.getMetadata(); - - if (configurationStoreName == null || (configurationStoreName.trim().isEmpty())) { - throw new IllegalArgumentException("Configuration Store Name can not be null or empty."); - } - - Map> queryParams = new HashMap<>(); - if (!keys.isEmpty()) { - queryParams.put("key", Collections.unmodifiableList(keys)); - } - - // Appending passed metadata too into queryparams - Map> queryArgs = metadataToQueryArgs(metadata); - queryParams.putAll(queryArgs); - - String[] pathSegments = - new String[] { DaprHttp.API_VERSION, "configuration", configurationStoreName, "subscribe" }; - SubscribeConfigurationResponse res = Mono.deferContextual( - context -> this.client.invokeApi( - DaprHttp.HttpMethods.GET.name(), - pathSegments, queryParams, - (String) null, null, context - ) - ).map(response -> { - try { - JsonNode root = INTERNAL_SERIALIZER.parseNode(response.getBody()); - String subscriptionId = root.path("id").asText(); - return new SubscribeConfigurationResponse(subscriptionId, new HashMap<>()); - } catch (IOException e) { - throw new RuntimeException(e); - } - }).block(); - if (res != null) { - return Flux.just(res); - } - return Flux.empty(); - } catch (Exception ex) { - return DaprException.wrapFlux(ex); - } - } - - /** - * {@inheritDoc} - */ - @Override - public Mono unsubscribeConfiguration(UnsubscribeConfigurationRequest request) { - try { - final String id = request.getSubscriptionId(); - final String configStoreName = request.getStoreName(); - if (configStoreName == null || (configStoreName.trim().isEmpty())) { - throw new IllegalArgumentException("Configuration Store Name can not be null or empty."); - } - if (id.isEmpty()) { - throw new IllegalArgumentException("Subscription id can not be null or empty."); - } - - String[] pathSegments = new String[] - { DaprHttp.API_VERSION, "configuration", configStoreName, id, "unsubscribe" }; - - return Mono.deferContextual( - context -> this.client - .invokeApi( - DaprHttp.HttpMethods.GET.name(), - pathSegments, null, - (String) null, null, context) - ).map( - response -> { - JsonNode root = null; - try { - root = INTERNAL_SERIALIZER.parseNode(response.getBody()); - } catch (IOException e) { - throw new RuntimeException(e); - } - boolean ok = root.path("ok").asBoolean(); - String message = root.path("message").asText(); - return new UnsubscribeConfigurationResponse(ok, message); - } - ); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - } - - /** - * Converts metadata map into Query params. - * - * @param metadata metadata map - * @return Query params - */ - private static Map> metadataToQueryArgs(Map metadata) { - if (metadata == null) { - return Collections.emptyMap(); - } - - return metadata - .entrySet() - .stream() - .filter(e -> e.getKey() != null) - .collect(Collectors.toMap(e -> METADATA_PREFIX + e.getKey(), e -> Collections.singletonList(e.getValue()))); - } -} diff --git a/sdk/src/main/java/io/dapr/client/DaprClientGrpc.java b/sdk/src/main/java/io/dapr/client/DaprClientImpl.java similarity index 86% rename from sdk/src/main/java/io/dapr/client/DaprClientGrpc.java rename to sdk/src/main/java/io/dapr/client/DaprClientImpl.java index eb9c045fc..bcc1418b1 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientGrpc.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientImpl.java @@ -14,7 +14,6 @@ limitations under the License. package io.dapr.client; import com.google.common.base.Strings; -import com.google.protobuf.Any; import com.google.protobuf.ByteString; import com.google.protobuf.Empty; import io.dapr.client.domain.BulkPublishEntry; @@ -48,9 +47,8 @@ import io.dapr.client.domain.UnlockResponseStatus; import io.dapr.client.domain.UnsubscribeConfigurationRequest; import io.dapr.client.domain.UnsubscribeConfigurationResponse; import io.dapr.client.resiliency.ResiliencyOptions; -import io.dapr.config.Properties; import io.dapr.exceptions.DaprException; -import io.dapr.internal.opencensus.GrpcWrapper; +import io.dapr.internal.grpc.DaprClientGrpcInterceptors; import io.dapr.internal.resiliency.RetryPolicy; import io.dapr.internal.resiliency.TimeoutPolicy; import io.dapr.serializer.DaprObjectSerializer; @@ -60,22 +58,20 @@ import io.dapr.utils.TypeRef; import io.dapr.v1.CommonProtos; import io.dapr.v1.DaprGrpc; import io.dapr.v1.DaprProtos; -import io.grpc.CallOptions; import io.grpc.Channel; -import io.grpc.ClientCall; -import io.grpc.ClientInterceptor; -import io.grpc.ForwardingClientCall; -import io.grpc.Metadata; -import io.grpc.MethodDescriptor; +import io.grpc.stub.AbstractStub; import io.grpc.stub.StreamObserver; import reactor.core.publisher.Flux; import reactor.core.publisher.FluxSink; import reactor.core.publisher.Mono; import reactor.core.publisher.MonoSink; import reactor.util.context.ContextView; +import reactor.util.retry.Retry; import java.io.IOException; +import java.time.Duration; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -83,15 +79,16 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.function.Consumer; +import java.util.function.Function; import java.util.stream.Collectors; /** - * An adapter for the GRPC Client. + * Implementation of the Dapr client combining gRPC and HTTP (when applicable). * * @see io.dapr.v1.DaprGrpc * @see io.dapr.client.DaprClient */ -public class DaprClientGrpc extends AbstractDaprClient { +public class DaprClientImpl extends AbstractDaprClient { /** * The GRPC managed channel to be used. @@ -114,21 +111,11 @@ public class DaprClientGrpc extends AbstractDaprClient { private final DaprGrpc.DaprStub asyncStub; /** - * Default access level constructor, in order to create an instance of this class use io.dapr.client.DaprClientBuilder + * The HTTP client to be used for healthz and HTTP service invocation only. * - * @param channel Facade for the managed GRPC channel - * @param asyncStub async gRPC stub - * @param objectSerializer Serializer for transient request/response objects. - * @param stateSerializer Serializer for state objects. - * @see DaprClientBuilder + * @see io.dapr.client.DaprHttp */ - DaprClientGrpc( - GrpcChannelFacade channel, - DaprGrpc.DaprStub asyncStub, - DaprObjectSerializer objectSerializer, - DaprObjectSerializer stateSerializer) { - this(channel, asyncStub, objectSerializer, stateSerializer, null); - } + private final DaprHttp httpClient; /** * Default access level constructor, in order to create an instance of this class use io.dapr.client.DaprClientBuilder @@ -137,18 +124,39 @@ public class DaprClientGrpc extends AbstractDaprClient { * @param asyncStub async gRPC stub * @param objectSerializer Serializer for transient request/response objects. * @param stateSerializer Serializer for state objects. + * @see DaprClientBuilder + */ + DaprClientImpl( + GrpcChannelFacade channel, + DaprGrpc.DaprStub asyncStub, + DaprHttp httpClient, + DaprObjectSerializer objectSerializer, + DaprObjectSerializer stateSerializer) { + this(channel, asyncStub, httpClient, objectSerializer, stateSerializer, null); + } + + /** + * Default access level constructor, in order to create an instance of this class use io.dapr.client.DaprClientBuilder + * + * @param channel Facade for the managed GRPC channel + * @param asyncStub async gRPC stub + * @param httpClient client for http service invocation + * @param objectSerializer Serializer for transient request/response objects. + * @param stateSerializer Serializer for state objects. * @param resiliencyOptions Client-level override for resiliency options. * @see DaprClientBuilder */ - DaprClientGrpc( + DaprClientImpl( GrpcChannelFacade channel, DaprGrpc.DaprStub asyncStub, + DaprHttp httpClient, DaprObjectSerializer objectSerializer, DaprObjectSerializer stateSerializer, ResiliencyOptions resiliencyOptions) { super(objectSerializer, stateSerializer); this.channel = channel; - this.asyncStub = intercept(asyncStub); + this.asyncStub = asyncStub; + this.httpClient = httpClient; this.timeoutPolicy = new TimeoutPolicy( resiliencyOptions == null ? null : resiliencyOptions.getTimeout()); this.retryPolicy = new RetryPolicy( @@ -177,12 +185,72 @@ public class DaprClientGrpc extends AbstractDaprClient { } } + /** + * {@inheritDoc} + */ + public > T newGrpcStub(String appId, Function stubBuilder) { + // Adds Dapr interceptors to populate gRPC metadata automatically. + return DaprClientGrpcInterceptors.intercept(appId, stubBuilder.apply(this.channel.getGrpcChannel()), timeoutPolicy); + } + /** * {@inheritDoc} */ @Override public Mono waitForSidecar(int timeoutInMilliseconds) { - return this.channel.waitForChannelReady(timeoutInMilliseconds); + String[] pathSegments = new String[] { DaprHttp.API_VERSION, "healthz", "outbound"}; + int maxRetries = 5; + + Retry retrySpec = Retry + .fixedDelay(maxRetries, Duration.ofMillis(500)) + .doBeforeRetry(retrySignal -> { + System.out.println("Retrying component health check..."); + }); + + /* + NOTE: (Cassie) Uncomment this once it actually gets implemented: + https://github.com/grpc/grpc-java/issues/4359 + + int maxChannelStateRetries = 5; + + // Retry logic for checking the channel state + Retry channelStateRetrySpec = Retry + .fixedDelay(maxChannelStateRetries, Duration.ofMillis(500)) + .doBeforeRetry(retrySignal -> { + System.out.println("Retrying channel state check..."); + }); + */ + + // Do the Dapr Http endpoint check to have parity with Dotnet + Mono responseMono = this.httpClient.invokeApi(DaprHttp.HttpMethods.GET.name(), pathSegments, + null, "", null, null); + + return responseMono + .retryWhen(retrySpec) + /* + NOTE: (Cassie) Uncomment this once it actually gets implemented: + https://github.com/grpc/grpc-java/issues/4359 + .flatMap(response -> { + // Check the status code + int statusCode = response.getStatusCode(); + + // Check if the channel's state is READY + return Mono.defer(() -> { + if (this.channel.getState(true) == ConnectivityState.READY) { + // Return true if the status code is in the 2xx range + if (statusCode >= 200 && statusCode < 300) { + return Mono.empty(); // Continue with the flow + } + } + return Mono.error(new RuntimeException("Health check failed")); + }).retryWhen(channelStateRetrySpec); + }) + */ + .timeout(Duration.ofMillis(timeoutInMilliseconds)) + .onErrorResume(DaprException.class, e -> + Mono.error(new RuntimeException(e))) + .switchIfEmpty(DaprException.wrapMono(new RuntimeException("Health check timed out"))) + .then(); } /** @@ -309,38 +377,63 @@ public class DaprClientGrpc extends AbstractDaprClient { } } - /** - * {@inheritDoc} - */ @Override public Mono invokeMethod(InvokeMethodRequest invokeMethodRequest, TypeRef type) { try { - String appId = invokeMethodRequest.getAppId(); - String method = invokeMethodRequest.getMethod(); - Object body = invokeMethodRequest.getBody(); - HttpExtension httpExtension = invokeMethodRequest.getHttpExtension(); - DaprProtos.InvokeServiceRequest envelope = buildInvokeServiceRequest( - httpExtension, - appId, - method, - 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 + 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 Map metadata = invokeMethodRequest.getMetadata(); - return Mono.deferContextual( - context -> this.createMono( - it -> intercept(context, asyncStub).invokeService(envelope, it) - ) - ).flatMap( - it -> { - try { - return Mono.justOrEmpty(objectSerializer.deserialize(it.getData().getValue().toByteArray(), type)); - } catch (IOException e) { - throw DaprException.propagate(e); - } - } + 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 + 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[] methodSegments = method.split("/"); + + List pathSegments = new ArrayList<>(Arrays.asList(DaprHttp.API_VERSION, "invoke", appId, "method")); + pathSegments.addAll(Arrays.asList(methodSegments)); + + final Map headers = new HashMap<>(); + headers.putAll(httpExtension.getHeaders()); + if (metadata != null) { + headers.putAll(metadata); + } + byte[] serializedRequestBody = objectSerializer.serialize(request); + if (contentType != null && !contentType.isEmpty()) { + headers.put(io.dapr.client.domain.Metadata.CONTENT_TYPE, contentType); + } else { + headers.put(io.dapr.client.domain.Metadata.CONTENT_TYPE, objectSerializer.getContentType()); + } + Mono response = Mono.deferContextual( + context -> this.httpClient.invokeApi(httpMethod, pathSegments.toArray(new String[0]), + httpExtension.getQueryParams(), serializedRequestBody, headers, context) ); + return response.flatMap(r -> getMonoForHttpResponse(type, r)); + } catch (Exception ex) { + return DaprException.wrapMono(ex); + } + } + + private Mono getMonoForHttpResponse(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); } @@ -673,48 +766,6 @@ public class DaprClientGrpc extends AbstractDaprClient { } } - /** - * Builds the object io.dapr.{@link DaprProtos.InvokeServiceRequest} to be send based on the parameters. - * - * @param httpExtension Object for HttpExtension - * @param appId The application id to be invoked - * @param method The application method to be invoked - * @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. - */ - private DaprProtos.InvokeServiceRequest buildInvokeServiceRequest( - HttpExtension httpExtension, - String appId, - String method, - 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 (body != null) { - byte[] byteRequest = objectSerializer.serialize(body); - Any data = Any.newBuilder().setValue(ByteString.copyFrom(byteRequest)).build(); - requestBuilder.setData(data); - } else { - requestBuilder.setData(Any.newBuilder().build()); - } - CommonProtos.HTTPExtension.Builder httpExtensionBuilder = CommonProtos.HTTPExtension.newBuilder(); - - httpExtensionBuilder.setVerb(CommonProtos.HTTPExtension.Verb.valueOf(httpExtension.getMethod().toString())) - .setQuerystring(httpExtension.encodeQueryString()); - requestBuilder.setHttpExtension(httpExtensionBuilder.build()); - - requestBuilder.setContentType(objectSerializer.getContentType()); - - DaprProtos.InvokeServiceRequest.Builder envelopeBuilder = DaprProtos.InvokeServiceRequest.newBuilder() - .setId(appId) - .setMessage(requestBuilder.build()); - return envelopeBuilder.build(); - } - /** * {@inheritDoc} */ @@ -963,12 +1014,15 @@ public class DaprClientGrpc extends AbstractDaprClient { */ @Override public void close() throws Exception { - if (channel != null) { - DaprException.wrap(() -> { + DaprException.wrap(() -> { + if (channel != null) { channel.close(); - return true; - }).call(); - } + } + if (httpClient != null) { + httpClient.close(); + } + return true; + }).call(); } /** @@ -1054,7 +1108,7 @@ public class DaprClientGrpc extends AbstractDaprClient { DaprProtos.SubscribeConfigurationRequest envelope = builder.build(); return this.createFlux( - it -> intercept(asyncStub).subscribeConfiguration(envelope, it) + it -> intercept(null, asyncStub).subscribeConfiguration(envelope, it) ).map( it -> { Map configMap = new HashMap<>(); @@ -1094,7 +1148,7 @@ public class DaprClientGrpc extends AbstractDaprClient { DaprProtos.UnsubscribeConfigurationRequest envelope = builder.build(); return this.createMono( - it -> intercept(asyncStub).unsubscribeConfiguration(envelope, it) + it -> intercept(null, asyncStub).unsubscribeConfiguration(envelope, it) ).map( it -> new UnsubscribeConfigurationResponse(it.getOk(), it.getMessage()) ); @@ -1119,35 +1173,6 @@ public class DaprClientGrpc extends AbstractDaprClient { ); } - /** - * Populates GRPC client with interceptors. - * - * @param client GRPC client for Dapr. - * @return Client after adding interceptors. - */ - private DaprGrpc.DaprStub intercept(DaprGrpc.DaprStub client) { - ClientInterceptor interceptor = new ClientInterceptor() { - @Override - public ClientCall interceptCall( - MethodDescriptor methodDescriptor, - CallOptions options, - Channel channel) { - ClientCall clientCall = channel.newCall(methodDescriptor, timeoutPolicy.apply(options)); - return new ForwardingClientCall.SimpleForwardingClientCall(clientCall) { - @Override - public void start(final Listener responseListener, final Metadata metadata) { - String daprApiToken = Properties.API_TOKEN.get(); - if (daprApiToken != null) { - metadata.put(Metadata.Key.of(Headers.DAPR_API_TOKEN, Metadata.ASCII_STRING_MARSHALLER), daprApiToken); - } - super.start(responseListener, metadata); - } - }; - } - }; - return client.withInterceptors(interceptor); - } - /** * Populates GRPC client with interceptors for telemetry. * @@ -1155,8 +1180,8 @@ public class DaprClientGrpc extends AbstractDaprClient { * @param client GRPC client for Dapr. * @return Client after adding interceptors. */ - private static DaprGrpc.DaprStub intercept(ContextView context, DaprGrpc.DaprStub client) { - return GrpcWrapper.intercept(context, client); + private DaprGrpc.DaprStub intercept(ContextView context, DaprGrpc.DaprStub client) { + return DaprClientGrpcInterceptors.intercept(client, this.timeoutPolicy, context); } private Mono createMono(Consumer> consumer) { diff --git a/sdk/src/main/java/io/dapr/client/DaprClientProxy.java b/sdk/src/main/java/io/dapr/client/DaprClientProxy.java deleted file mode 100644 index 370091a96..000000000 --- a/sdk/src/main/java/io/dapr/client/DaprClientProxy.java +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Copyright 2021 The Dapr Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io.dapr.client; - -import io.dapr.client.domain.ConfigurationItem; -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.GetConfigurationRequest; -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.SaveStateRequest; -import io.dapr.client.domain.State; -import io.dapr.client.domain.StateOptions; -import io.dapr.client.domain.SubscribeConfigurationRequest; -import io.dapr.client.domain.SubscribeConfigurationResponse; -import io.dapr.client.domain.TransactionalStateOperation; -import io.dapr.client.domain.UnsubscribeConfigurationRequest; -import io.dapr.client.domain.UnsubscribeConfigurationResponse; -import io.dapr.utils.TypeRef; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.util.List; -import java.util.Map; - -/** - * Class that delegates to other implementations. - * @deprecated This class will be deleted at SDK release version 1.10. - * @see DaprClient - * @see DaprClientGrpc - * @see DaprClientHttp - */ -@Deprecated -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 Mono getConfiguration(String storeName, String key) { - return client.getConfiguration(storeName, key); - } - - /** - * {@inheritDoc} - */ - @Override - public Mono getConfiguration(String storeName, String key, Map metadata) { - return client.getConfiguration(storeName, key, metadata); - } - - /** - * {@inheritDoc} - */ - @Override - public Mono> getConfiguration(String storeName, String... keys) { - return client.getConfiguration(storeName, keys); - } - - /** - * {@inheritDoc} - */ - @Override - public Mono> getConfiguration(String storeName, List keys, - Map metadata) { - return client.getConfiguration(storeName, keys, metadata); - } - - /** - * {@inheritDoc} - */ - @Override - public Mono> getConfiguration(GetConfigurationRequest request) { - return client.getConfiguration(request); - } - - /** - * {@inheritDoc} - */ - @Override - public Flux subscribeConfiguration(String storeName, String... keys) { - return client.subscribeConfiguration(storeName, keys); - } - - /** - * {@inheritDoc} - */ - @Override - public Flux subscribeConfiguration(String storeName, List keys, - Map metadata) { - return client.subscribeConfiguration(storeName, keys, metadata); - } - - /** - * {@inheritDoc} - */ - @Override - public Flux subscribeConfiguration(SubscribeConfigurationRequest request) { - return client.subscribeConfiguration(request); - } - - /** - * {@inheritDoc} - */ - @Override - public Mono unsubscribeConfiguration(String id, String storeName) { - return client.unsubscribeConfiguration(id, storeName); - } - - /** - * {@inheritDoc} - */ - @Override - public Mono unsubscribeConfiguration(UnsubscribeConfigurationRequest request) { - return client.unsubscribeConfiguration(request); - } - - /** - * {@inheritDoc} - */ - @Override - public void close() throws Exception { - client.close(); - if (client != methodInvocationOverrideClient) { - methodInvocationOverrideClient.close(); - } - } - - /** - * {@inheritDoc} - */ - @Override - public Mono shutdown() { - return client.shutdown(); - } -} diff --git a/sdk/src/main/java/io/dapr/client/DaprHttpBuilder.java b/sdk/src/main/java/io/dapr/client/DaprHttpBuilder.java index 73842b546..e33b2e698 100644 --- a/sdk/src/main/java/io/dapr/client/DaprHttpBuilder.java +++ b/sdk/src/main/java/io/dapr/client/DaprHttpBuilder.java @@ -23,9 +23,7 @@ import java.util.concurrent.TimeUnit; /** * A builder for the DaprHttp. - * @deprecated Use {@link DaprClientBuilder} instead, this will be removed in a future release. */ -@Deprecated public class DaprHttpBuilder { /** diff --git a/sdk/src/main/java/io/dapr/client/DaprTracingInterceptor.java b/sdk/src/main/java/io/dapr/client/DaprTracingInterceptor.java new file mode 100644 index 000000000..20f6d1c06 --- /dev/null +++ b/sdk/src/main/java/io/dapr/client/DaprTracingInterceptor.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024 The Dapr Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and +limitations under the License. +*/ + +package io.dapr.client; + +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.ClientCall; +import io.grpc.ClientInterceptor; +import io.grpc.MethodDescriptor; +import reactor.util.context.ContextView; + +/** + * Injects tracing headers to gRPC metadata. + */ +public class DaprTracingInterceptor implements ClientInterceptor { + + private final io.dapr.internal.grpc.interceptors.DaprTracingInterceptor delegate; + + /** + * Creates an instance of the injector for gRPC context from Reactor's context. + * @param context Reactor's context + */ + public DaprTracingInterceptor(ContextView context) { + this.delegate = new io.dapr.internal.grpc.interceptors.DaprTracingInterceptor(context); + } + + /** + * {@inheritDoc} + */ + @Override + public ClientCall interceptCall( + MethodDescriptor methodDescriptor, + CallOptions callOptions, + Channel channel) { + return this.delegate.interceptCall(methodDescriptor, callOptions, channel); + } +} diff --git a/sdk/src/main/java/io/dapr/client/GrpcChannelFacade.java b/sdk/src/main/java/io/dapr/client/GrpcChannelFacade.java index b0e13e033..5647f5294 100644 --- a/sdk/src/main/java/io/dapr/client/GrpcChannelFacade.java +++ b/sdk/src/main/java/io/dapr/client/GrpcChannelFacade.java @@ -13,18 +13,11 @@ limitations under the License. package io.dapr.client; -import io.dapr.config.Properties; -import io.dapr.exceptions.DaprException; import io.dapr.v1.DaprGrpc; -import io.grpc.ConnectivityState; import io.grpc.ManagedChannel; -import okhttp3.OkHttpClient; -import reactor.core.publisher.Mono; -import reactor.util.retry.Retry; import java.io.Closeable; import java.io.IOException; -import java.time.Duration; /** * Facade for common operations on gRPC channel. @@ -39,11 +32,6 @@ class GrpcChannelFacade implements Closeable { */ private final ManagedChannel channel; - /** - * The reference to the DaprHttp client. - */ - private final DaprHttp daprHttp; - /** * Default access level constructor, in order to create an instance of this class use io.dapr.client.DaprClientBuilder @@ -51,75 +39,23 @@ class GrpcChannelFacade implements Closeable { * @param channel A Managed GRPC channel * @see DaprClientBuilder */ - GrpcChannelFacade(ManagedChannel channel, DaprHttp daprHttp) { + GrpcChannelFacade(ManagedChannel channel) { this.channel = channel; - this.daprHttp = daprHttp; + } + + /** + * Returns the gRPC channel to the sidecar. + * @return Sidecar's gRPC channel. + */ + ManagedChannel getGrpcChannel() { + return this.channel; } @Override public void close() throws IOException { - if (daprHttp != null) { - daprHttp.close(); - } - if (channel != null && !channel.isShutdown()) { channel.shutdown(); } } - public Mono waitForChannelReady(int timeoutInMilliseconds) { - String[] pathSegments = new String[] { DaprHttp.API_VERSION, "healthz", "outbound"}; - int maxRetries = 5; - - Retry retrySpec = Retry - .fixedDelay(maxRetries, Duration.ofMillis(500)) - .doBeforeRetry(retrySignal -> { - System.out.println("Retrying component health check..."); - }); - - /* - NOTE: (Cassie) Uncomment this once it actually gets implemented: - https://github.com/grpc/grpc-java/issues/4359 - - int maxChannelStateRetries = 5; - - // Retry logic for checking the channel state - Retry channelStateRetrySpec = Retry - .fixedDelay(maxChannelStateRetries, Duration.ofMillis(500)) - .doBeforeRetry(retrySignal -> { - System.out.println("Retrying channel state check..."); - }); - */ - - // Do the Dapr Http endpoint check to have parity with Dotnet - Mono responseMono = this.daprHttp.invokeApi(DaprHttp.HttpMethods.GET.name(), pathSegments, - null, "", null, null); - - return responseMono - .retryWhen(retrySpec) - /* - NOTE: (Cassie) Uncomment this once it actually gets implemented: - https://github.com/grpc/grpc-java/issues/4359 - .flatMap(response -> { - // Check the status code - int statusCode = response.getStatusCode(); - - // Check if the channel's state is READY - return Mono.defer(() -> { - if (this.channel.getState(true) == ConnectivityState.READY) { - // Return true if the status code is in the 2xx range - if (statusCode >= 200 && statusCode < 300) { - return Mono.empty(); // Continue with the flow - } - } - return Mono.error(new RuntimeException("Health check failed")); - }).retryWhen(channelStateRetrySpec); - }) - */ - .timeout(Duration.ofMillis(timeoutInMilliseconds)) - .onErrorResume(DaprException.class, e -> - Mono.error(new RuntimeException(e))) - .switchIfEmpty(DaprException.wrapMono(new RuntimeException("Health check timed out"))) - .then(); - } } diff --git a/sdk/src/main/java/io/dapr/client/domain/BulkSubscribeAppResponse.java b/sdk/src/main/java/io/dapr/client/domain/BulkSubscribeAppResponse.java index 511e3468f..cccddc117 100644 --- a/sdk/src/main/java/io/dapr/client/domain/BulkSubscribeAppResponse.java +++ b/sdk/src/main/java/io/dapr/client/domain/BulkSubscribeAppResponse.java @@ -16,7 +16,6 @@ package io.dapr.client.domain; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.ArrayList; import java.util.Collections; import java.util.List; diff --git a/sdk/src/main/java/io/dapr/client/domain/PublishEventRequest.java b/sdk/src/main/java/io/dapr/client/domain/PublishEventRequest.java index a2e65955a..61249bb15 100644 --- a/sdk/src/main/java/io/dapr/client/domain/PublishEventRequest.java +++ b/sdk/src/main/java/io/dapr/client/domain/PublishEventRequest.java @@ -14,7 +14,6 @@ limitations under the License. package io.dapr.client.domain; import java.util.Collections; -import java.util.HashMap; import java.util.Map; /** diff --git a/sdk/src/main/java/io/dapr/config/Properties.java b/sdk/src/main/java/io/dapr/config/Properties.java index 2ceeffb4a..27769c6cc 100644 --- a/sdk/src/main/java/io/dapr/config/Properties.java +++ b/sdk/src/main/java/io/dapr/config/Properties.java @@ -13,7 +13,6 @@ limitations under the License. package io.dapr.config; -import io.dapr.client.DaprApiProtocol; import io.dapr.utils.NetworkUtils; import java.nio.charset.Charset; @@ -50,16 +49,6 @@ public class Properties { */ private static final Duration DEFAULT_API_TIMEOUT = Duration.ofMillis(0L); - /** - * 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 DaprApiProtocol DEFAULT_API_METHOD_INVOCATION_PROTOCOL = DaprApiProtocol.HTTP; - /** * Dapr's default String encoding: UTF-8. */ @@ -143,28 +132,6 @@ public class Properties { "DAPR_API_TIMEOUT_MILLISECONDS", DEFAULT_API_TIMEOUT); - /** - * Determines if Dapr client will use gRPC or HTTP to talk to Dapr's side car. - * @deprecated This attribute will be deleted at SDK version 1.10. - */ - @Deprecated - 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. - * @deprecated This attribute will be deleted at SDK version 1.10. - */ - @Deprecated - 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. */ diff --git a/sdk/src/main/java/io/dapr/internal/grpc/DaprClientGrpcInterceptors.java b/sdk/src/main/java/io/dapr/internal/grpc/DaprClientGrpcInterceptors.java new file mode 100644 index 000000000..9a47d1aeb --- /dev/null +++ b/sdk/src/main/java/io/dapr/internal/grpc/DaprClientGrpcInterceptors.java @@ -0,0 +1,139 @@ +/* + * Copyright 2024 The Dapr Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and +limitations under the License. +*/ + +package io.dapr.internal.grpc; + +import io.dapr.internal.grpc.interceptors.DaprApiTokenInterceptor; +import io.dapr.internal.grpc.interceptors.DaprAppIdInterceptor; +import io.dapr.internal.grpc.interceptors.DaprTimeoutInterceptor; +import io.dapr.internal.grpc.interceptors.DaprTracingInterceptor; +import io.dapr.internal.resiliency.TimeoutPolicy; +import io.grpc.stub.AbstractStub; +import reactor.util.context.ContextView; + +/** + * Class to be used as part of your service's client stub interceptor. + * Usage: myClientStub = DaprClientGrpcInterceptors.intercept(myClientStub); + */ +public class DaprClientGrpcInterceptors { + + /** + * Adds all Dapr interceptors to a gRPC async stub. + * @param appId the appId to be invoked + * @param client gRPC client + * @param async client type + * @return async client instance with interceptors + */ + public static > T intercept(final String appId, final T client) { + return intercept(appId, client, null, null); + } + + /** + * Adds all Dapr interceptors to a gRPC async stub. + * @param client gRPC client + * @param async client type + * @return async client instance with interceptors + */ + public static > T intercept(final T client) { + return intercept(null, client, null, null); + } + + /** + * Adds all Dapr interceptors to a gRPC async stub. + * @param appId the appId to be invoked + * @param client gRPC client + * @param timeoutPolicy timeout policy for gRPC call + * @param async client type + * @return async client instance with interceptors + */ + public static > T intercept( + final String appId, final T client, final TimeoutPolicy timeoutPolicy) { + return intercept(appId, client, timeoutPolicy, null); + } + + /** + * Adds all Dapr interceptors to a gRPC async stub. + * @param client gRPC client + * @param timeoutPolicy timeout policy for gRPC call + * @param async client type + * @return async client instance with interceptors + */ + public static > T intercept(final T client, final TimeoutPolicy timeoutPolicy) { + return intercept(null, client, timeoutPolicy, null); + } + + /** + * Adds all Dapr interceptors to a gRPC async stub. + * @param appId the appId to be invoked + * @param client gRPC client + * @param context Reactor context for tracing + * @param async client type + * @return async client instance with interceptors + */ + public static > T intercept( + final String appId, final T client, final ContextView context) { + return intercept(appId, client, null, context); + } + + /** + * Adds all Dapr interceptors to a gRPC async stub. + * @param client gRPC client + * @param context Reactor context for tracing + * @param async client type + * @return async client instance with interceptors + */ + public static > T intercept(final T client, final ContextView context) { + return intercept(null, client, null, context); + } + + /** + * Adds all Dapr interceptors to a gRPC async stub. + * @param client gRPC client + * @param timeoutPolicy timeout policy for gRPC call + * @param context Reactor context for tracing + * @param async client type + * @return async client instance with interceptors + */ + public static > T intercept( + final T client, + final TimeoutPolicy timeoutPolicy, + final ContextView context) { + return intercept(null, client, timeoutPolicy, context); + } + + /** + * Adds all Dapr interceptors to a gRPC async stub. + * @param appId the appId to be invoked + * @param client gRPC client + * @param timeoutPolicy timeout policy for gRPC call + * @param context Reactor context for tracing + * @param async client type + * @return async client instance with interceptors + */ + public static > T intercept( + final String appId, + final T client, + final TimeoutPolicy timeoutPolicy, + final ContextView context) { + if (client == null) { + throw new IllegalArgumentException("client cannot be null"); + } + + return client.withInterceptors( + new DaprAppIdInterceptor(appId), + new DaprApiTokenInterceptor(), + new DaprTimeoutInterceptor(timeoutPolicy), + new DaprTracingInterceptor(context)); + } + +} diff --git a/sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprApiTokenInterceptor.java b/sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprApiTokenInterceptor.java new file mode 100644 index 000000000..cda6e896b --- /dev/null +++ b/sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprApiTokenInterceptor.java @@ -0,0 +1,49 @@ +/* + * Copyright 2024 The Dapr Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and +limitations under the License. +*/ + +package io.dapr.internal.grpc.interceptors; + +import io.dapr.client.Headers; +import io.dapr.config.Properties; +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.ClientCall; +import io.grpc.ClientInterceptor; +import io.grpc.ForwardingClientCall; +import io.grpc.Metadata; +import io.grpc.MethodDescriptor; + +/** + * Class to be used as part of your service's client stub interceptor to include Dapr tokens. + */ +public class DaprApiTokenInterceptor implements ClientInterceptor { + + @Override + public ClientCall interceptCall( + MethodDescriptor methodDescriptor, + CallOptions options, + Channel channel) { + ClientCall clientCall = channel.newCall(methodDescriptor, options); + return new ForwardingClientCall.SimpleForwardingClientCall<>(clientCall) { + @Override + public void start(final Listener responseListener, final Metadata metadata) { + String daprApiToken = Properties.API_TOKEN.get(); + if (daprApiToken != null) { + metadata.put(Metadata.Key.of(Headers.DAPR_API_TOKEN, Metadata.ASCII_STRING_MARSHALLER), daprApiToken); + } + super.start(responseListener, metadata); + } + }; + } + +} diff --git a/sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprAppIdInterceptor.java b/sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprAppIdInterceptor.java new file mode 100644 index 000000000..33715e73d --- /dev/null +++ b/sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprAppIdInterceptor.java @@ -0,0 +1,63 @@ +/* + * Copyright 2024 The Dapr Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and +limitations under the License. +*/ + +package io.dapr.internal.grpc.interceptors; + +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.ClientCall; +import io.grpc.ClientInterceptor; +import io.grpc.ForwardingClientCall; +import io.grpc.Metadata; +import io.grpc.MethodDescriptor; + +/** + * Class to be used as part of your service's client stub interceptor to include Dapr App Id metadata. + */ +public class DaprAppIdInterceptor implements ClientInterceptor { + + private final Metadata extraHeaders; + + public DaprAppIdInterceptor(String appId) { + this.extraHeaders = buildMetadata(appId); + } + + private static final Metadata buildMetadata(String appId) { + if (appId == null) { + return null; + } + + Metadata headers = new Metadata(); + headers.put(Metadata.Key.of("dapr-app-id", Metadata.ASCII_STRING_MARSHALLER), appId); + return headers; + } + + @Override + public ClientCall interceptCall( + MethodDescriptor methodDescriptor, + CallOptions options, + Channel channel) { + ClientCall clientCall = channel.newCall(methodDescriptor, options); + final Metadata extraHeaders = this.extraHeaders; + return new ForwardingClientCall.SimpleForwardingClientCall<>(clientCall) { + @Override + public void start(ClientCall.Listener responseListener, Metadata headers) { + if (extraHeaders != null) { + headers.merge(extraHeaders); + } + super.start(responseListener, headers); + } + }; + } + +} diff --git a/sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprTimeoutInterceptor.java b/sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprTimeoutInterceptor.java new file mode 100644 index 000000000..5ab17ba81 --- /dev/null +++ b/sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprTimeoutInterceptor.java @@ -0,0 +1,46 @@ +/* + * Copyright 2024 The Dapr Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and +limitations under the License. +*/ + +package io.dapr.internal.grpc.interceptors; + +import io.dapr.internal.resiliency.TimeoutPolicy; +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.ClientCall; +import io.grpc.ClientInterceptor; +import io.grpc.MethodDescriptor; + +/** + * Class to be used as part of your service's client stub interceptor to include timeout. + */ +public class DaprTimeoutInterceptor implements ClientInterceptor { + + private final TimeoutPolicy timeoutPolicy; + + public DaprTimeoutInterceptor(TimeoutPolicy timeoutPolicy) { + this.timeoutPolicy = timeoutPolicy; + } + + @Override + public ClientCall interceptCall( + MethodDescriptor methodDescriptor, + CallOptions options, + Channel channel) { + if (timeoutPolicy == null) { + return channel.newCall(methodDescriptor, options); + } + + return channel.newCall(methodDescriptor, timeoutPolicy.apply(options)); + } + +} diff --git a/sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprTracingInterceptor.java b/sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprTracingInterceptor.java new file mode 100644 index 000000000..d93838de9 --- /dev/null +++ b/sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprTracingInterceptor.java @@ -0,0 +1,58 @@ +/* + * Copyright 2024 The Dapr Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and +limitations under the License. +*/ + +package io.dapr.internal.grpc.interceptors; + +import io.dapr.internal.opencensus.GrpcHelper; +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.ClientCall; +import io.grpc.ClientInterceptor; +import io.grpc.ForwardingClientCall; +import io.grpc.Metadata; +import io.grpc.MethodDescriptor; +import reactor.util.context.ContextView; + +/** + * Injects tracing headers to gRPC metadata. + */ +public class DaprTracingInterceptor implements ClientInterceptor { + + private final ContextView context; + + /** + * Creates an instance of the injector for gRPC context from Reactor's context. + * @param context Reactor's context + */ + public DaprTracingInterceptor(ContextView context) { + this.context = context; + } + + @Override + public ClientCall interceptCall( + MethodDescriptor methodDescriptor, + CallOptions callOptions, + Channel channel) { + ClientCall clientCall = channel.newCall(methodDescriptor, callOptions); + return new ForwardingClientCall.SimpleForwardingClientCall<>(clientCall) { + @Override + public void start(final Listener responseListener, final Metadata metadata) { + if (context != null) { + GrpcHelper.populateMetadata(context, metadata); + } + super.start(responseListener, metadata); + } + }; + } + +} diff --git a/sdk/src/main/java/io/dapr/internal/opencensus/GrpcHelper.java b/sdk/src/main/java/io/dapr/internal/opencensus/GrpcHelper.java new file mode 100644 index 000000000..5845f9f9b --- /dev/null +++ b/sdk/src/main/java/io/dapr/internal/opencensus/GrpcHelper.java @@ -0,0 +1,96 @@ +/* + * Copyright 2021 The Dapr Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and +limitations under the License. +*/ + +package io.dapr.internal.opencensus; + +import io.grpc.Metadata; +import reactor.util.context.Context; +import reactor.util.context.ContextView; + +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +/** + * Helper to extract tracing information for gRPC calls. + */ +public final class GrpcHelper { + + private static final Logger LOGGER = Logger.getLogger(GrpcHelper.class.getName()); + + /** + * Binary formatter to generate grpc-trace-bin. + */ + private static final BinaryFormatImpl OPENCENSUS_BINARY_FORMAT = new BinaryFormatImpl(); + + private static final Metadata.Key GRPC_TRACE_BIN_KEY = + Metadata.Key.of("grpc-trace-bin", Metadata.BINARY_BYTE_MARSHALLER); + + private static final Metadata.Key TRACEPARENT_KEY = + Metadata.Key.of("traceparent", Metadata.ASCII_STRING_MARSHALLER); + + private static final Metadata.Key TRACESTATE_KEY = + Metadata.Key.of("tracestate", Metadata.ASCII_STRING_MARSHALLER); + + private GrpcHelper() { + } + + /** + * Populates GRPC client's metadata with tracing headers. + * + * @param context Reactor's context. + * @param metadata GRPC client metadata to be populated. + */ + public static void populateMetadata(final ContextView context, final Metadata metadata) { + Map map = (context == null ? Context.empty() : context) + .stream() + .filter(e -> (e.getKey() != null) && (e.getValue() != null)) + .collect(Collectors.toMap(e -> e.getKey().toString(), e -> e.getValue())); + if (map.containsKey(GRPC_TRACE_BIN_KEY.name())) { + byte[] value = (byte[]) map.get(GRPC_TRACE_BIN_KEY.name()); + metadata.put(GRPC_TRACE_BIN_KEY, value); + } + if (map.containsKey(TRACEPARENT_KEY.name())) { + String value = map.get(TRACEPARENT_KEY.name()).toString(); + metadata.put(TRACEPARENT_KEY, value); + } + if (map.containsKey(TRACESTATE_KEY.name())) { + String value = map.get(TRACESTATE_KEY.name()).toString(); + metadata.put(TRACESTATE_KEY, value); + } + + // Dapr only supports "grpc-trace-bin" for GRPC and OpenTelemetry SDK does not support that yet: + // https://github.com/open-telemetry/opentelemetry-specification/issues/639 + // This should be the only use of OpenCensus SDK: populate "grpc-trace-bin". + SpanContext opencensusSpanContext = extractOpenCensusSpanContext(metadata); + if (opencensusSpanContext != null) { + byte[] grpcTraceBin = OPENCENSUS_BINARY_FORMAT.toByteArray(opencensusSpanContext); + metadata.put(GRPC_TRACE_BIN_KEY, grpcTraceBin); + } + } + + private static SpanContext extractOpenCensusSpanContext(Metadata metadata) { + if (!metadata.keys().contains(TRACEPARENT_KEY.name())) { + // Trying to extract context without this key will throw an "expected" exception, so we avoid it here. + return null; + } + + try { + return TraceContextFormat.extract(metadata); + } catch (RuntimeException e) { + LOGGER.log(Level.FINE, "Could not extract span context.", e); + return null; + } + } +} diff --git a/sdk/src/main/java/io/dapr/internal/opencensus/GrpcWrapper.java b/sdk/src/main/java/io/dapr/internal/opencensus/GrpcWrapper.java deleted file mode 100644 index 61db83627..000000000 --- a/sdk/src/main/java/io/dapr/internal/opencensus/GrpcWrapper.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2021 The Dapr Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io.dapr.internal.opencensus; - -import io.dapr.config.Property; -import io.dapr.v1.DaprGrpc; -import io.grpc.CallOptions; -import io.grpc.Channel; -import io.grpc.ClientCall; -import io.grpc.ClientInterceptor; -import io.grpc.ForwardingClientCall; -import io.grpc.Metadata; -import io.grpc.MethodDescriptor; -import reactor.util.context.Context; -import reactor.util.context.ContextView; - -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -/** - * Wraps a Dapr gRPC stub with telemetry interceptor. - */ -public final class GrpcWrapper { - - private static final Logger LOGGER = Logger.getLogger(Property.class.getName()); - - /** - * Binary formatter to generate grpc-trace-bin. - */ - private static final BinaryFormatImpl OPENCENSUS_BINARY_FORMAT = new BinaryFormatImpl(); - - private static final Metadata.Key GRPC_TRACE_BIN_KEY = - Metadata.Key.of("grpc-trace-bin", Metadata.BINARY_BYTE_MARSHALLER); - - private static final Metadata.Key TRACEPARENT_KEY = - Metadata.Key.of("traceparent", Metadata.ASCII_STRING_MARSHALLER); - - private static final Metadata.Key TRACESTATE_KEY = - Metadata.Key.of("tracestate", Metadata.ASCII_STRING_MARSHALLER); - - private GrpcWrapper() { - } - - /** - * Populates GRPC client with interceptors. - * - * @param context Reactor's context. - * @param client GRPC client for Dapr. - * @return Client after adding interceptors. - */ - public static DaprGrpc.DaprStub intercept(final ContextView context, DaprGrpc.DaprStub client) { - ClientInterceptor interceptor = new ClientInterceptor() { - @Override - public ClientCall interceptCall( - MethodDescriptor methodDescriptor, - CallOptions callOptions, - Channel channel) { - ClientCall clientCall = channel.newCall(methodDescriptor, callOptions); - return new ForwardingClientCall.SimpleForwardingClientCall(clientCall) { - @Override - public void start(final Listener responseListener, final Metadata metadata) { - Map map = (context == null ? Context.empty() : context) - .stream() - .filter(e -> (e.getKey() != null) && (e.getValue() != null)) - .collect(Collectors.toMap(e -> e.getKey().toString(), e -> e.getValue())); - if (map.containsKey(GRPC_TRACE_BIN_KEY.name())) { - byte[] value = (byte[]) map.get(GRPC_TRACE_BIN_KEY.name()); - metadata.put(GRPC_TRACE_BIN_KEY, value); - } - if (map.containsKey(TRACEPARENT_KEY.name())) { - String value = map.get(TRACEPARENT_KEY.name()).toString(); - metadata.put(TRACEPARENT_KEY, value); - } - if (map.containsKey(TRACESTATE_KEY.name())) { - String value = map.get(TRACESTATE_KEY.name()).toString(); - metadata.put(TRACESTATE_KEY, value); - } - - // Dapr only supports "grpc-trace-bin" for GRPC and OpenTelemetry SDK does not support that yet: - // https://github.com/open-telemetry/opentelemetry-specification/issues/639 - // This should be the only use of OpenCensus SDK: populate "grpc-trace-bin". - SpanContext opencensusSpanContext = extractOpenCensusSpanContext(metadata); - if (opencensusSpanContext != null) { - byte[] grpcTraceBin = OPENCENSUS_BINARY_FORMAT.toByteArray(opencensusSpanContext); - metadata.put(GRPC_TRACE_BIN_KEY, grpcTraceBin); - } - - super.start(responseListener, metadata); - } - }; - } - }; - return client.withInterceptors(interceptor); - } - - private static SpanContext extractOpenCensusSpanContext(Metadata metadata) { - if (!metadata.keys().contains(TRACEPARENT_KEY.name())) { - // Trying to extract context without this key will throw an "expected" exception, so we avoid it here. - return null; - } - - try { - return TraceContextFormat.extract(metadata); - } catch (RuntimeException e) { - LOGGER.log(Level.FINE, "Could not extract span context.", e); - return null; - } - } -} diff --git a/sdk/src/main/java/io/dapr/utils/TypeRef.java b/sdk/src/main/java/io/dapr/utils/TypeRef.java index c606d6da7..983d748fd 100644 --- a/sdk/src/main/java/io/dapr/utils/TypeRef.java +++ b/sdk/src/main/java/io/dapr/utils/TypeRef.java @@ -13,8 +13,6 @@ limitations under the License. package io.dapr.utils; -import com.fasterxml.jackson.databind.JavaType; - import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; diff --git a/sdk/src/test/java/io/dapr/client/CloudEventCustom.java b/sdk/src/test/java/io/dapr/client/CloudEventCustom.java index 4c581d819..bc055f3ee 100644 --- a/sdk/src/test/java/io/dapr/client/CloudEventCustom.java +++ b/sdk/src/test/java/io/dapr/client/CloudEventCustom.java @@ -15,11 +15,8 @@ package io.dapr.client; import io.dapr.client.domain.CloudEvent; -import java.util.Arrays; import java.util.Objects; -import java.io.IOException; - public class CloudEventCustom extends CloudEvent { diff --git a/sdk/src/test/java/io/dapr/client/CloudEventCustomTest.java b/sdk/src/test/java/io/dapr/client/CloudEventCustomTest.java index 3d62fcfbd..803203a34 100644 --- a/sdk/src/test/java/io/dapr/client/CloudEventCustomTest.java +++ b/sdk/src/test/java/io/dapr/client/CloudEventCustomTest.java @@ -13,16 +13,15 @@ limitations under the License. package io.dapr.client; +import io.dapr.serializer.DaprObjectSerializer; +import io.dapr.serializer.DefaultObjectSerializer; +import io.dapr.utils.TypeRef; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import io.dapr.serializer.DaprObjectSerializer; -import io.dapr.serializer.DefaultObjectSerializer; -import io.dapr.utils.TypeRef; - public class CloudEventCustomTest { private DaprObjectSerializer serializer = new DefaultObjectSerializer(); diff --git a/sdk/src/test/java/io/dapr/client/DaprClientBuilderTest.java b/sdk/src/test/java/io/dapr/client/DaprClientBuilderTest.java index 2b31a8879..bd94043bc 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientBuilderTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientBuilderTest.java @@ -16,7 +16,6 @@ package io.dapr.client; import io.dapr.serializer.DaprObjectSerializer; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; diff --git a/sdk/src/test/java/io/dapr/client/DaprClientGrpcTelemetryTest.java b/sdk/src/test/java/io/dapr/client/DaprClientGrpcTelemetryTest.java index ae62a5923..4b8b80317 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientGrpcTelemetryTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientGrpcTelemetryTest.java @@ -15,10 +15,10 @@ package io.dapr.client; import io.dapr.client.domain.HttpExtension; import io.dapr.client.domain.InvokeMethodRequest; -import io.dapr.serializer.DefaultObjectSerializer; -import io.dapr.utils.TypeRef; +import io.dapr.internal.grpc.DaprClientGrpcInterceptors; import io.dapr.v1.CommonProtos; import io.dapr.v1.DaprGrpc; +import io.dapr.v1.DaprProtos; import io.grpc.ManagedChannel; import io.grpc.Metadata; import io.grpc.ServerCall; @@ -28,6 +28,7 @@ import io.grpc.ServerInterceptors; import io.grpc.ServerServiceDefinition; import io.grpc.inprocess.InProcessChannelBuilder; import io.grpc.inprocess.InProcessServerBuilder; +import io.grpc.stub.StreamObserver; import io.grpc.testing.GrpcCleanupRule; import org.junit.Rule; import org.junit.jupiter.api.AfterEach; @@ -36,15 +37,16 @@ import org.junit.jupiter.migrationsupport.rules.EnableRuleMigrationSupport; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.mockito.Mockito; import reactor.core.publisher.Mono; +import reactor.core.publisher.MonoSink; import reactor.util.context.Context; +import reactor.util.context.ContextView; import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.function.Consumer; import java.util.stream.Stream; -import reactor.util.context.ContextView; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -67,6 +69,8 @@ public class DaprClientGrpcTelemetryTest { @Rule public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); + private DaprGrpc.DaprStub daprStub; + private DaprClient client; @AfterEach @@ -144,10 +148,7 @@ null, // Create a client channel and register for automatic graceful shutdown. ManagedChannel channel = InProcessChannelBuilder.forName(serverName).directExecutor().build(); - DaprGrpc.DaprStub asyncStub = DaprGrpc.newStub(channel); - DaprHttp daprHTTP = Mockito.mock(DaprHttp.class); - client = new DaprClientGrpc( - new GrpcChannelFacade(channel, daprHTTP), asyncStub, new DefaultObjectSerializer(), new DefaultObjectSerializer()); + daprStub = DaprGrpc.newStub(channel); } public void setup() throws IOException { @@ -184,11 +185,7 @@ null, // Create a client channel and register for automatic graceful shutdown. ManagedChannel channel = InProcessChannelBuilder.forName(serverName).directExecutor().build(); - DaprGrpc.DaprStub asyncStub = DaprGrpc.newStub(channel); - - DaprHttp daprHTTP = Mockito.mock(DaprHttp.class); - client = new DaprClientGrpc( - new GrpcChannelFacade(channel, daprHTTP), asyncStub, new DefaultObjectSerializer(), new DefaultObjectSerializer()); + this.daprStub = DaprGrpc.newStub(channel); } @@ -214,10 +211,7 @@ null, } final Context contextCopy = context; - InvokeMethodRequest req = new InvokeMethodRequest("appId", "method") - .setBody("request") - .setHttpExtension(HttpExtension.NONE); - Mono result = this.client.invokeMethod(req, TypeRef.get(Void.class)) + Mono result = this.invoke() .contextWrite(it -> it.putAll(contextCopy)); result.block(); } @@ -233,8 +227,42 @@ null, InvokeMethodRequest req = new InvokeMethodRequest("appId", "method") .setBody("request") .setHttpExtension(HttpExtension.NONE); - Mono result = this.client.invokeMethod(req, TypeRef.get(Void.class)) + Mono result = this.invoke() .contextWrite(it -> it.putAll(contextCopy == null ? (ContextView) Context.empty() : contextCopy)); result.block(); } + + private Mono invoke() { + DaprProtos.InvokeServiceRequest req = + DaprProtos.InvokeServiceRequest.newBuilder() + .build(); + return Mono.deferContextual( + context -> this.createMono( + it -> DaprClientGrpcInterceptors.intercept(daprStub, context).invokeService(req, it) + ) + ).then(); + } + + private Mono createMono(Consumer> consumer) { + return Mono.create(sink -> consumer.accept(createStreamObserver(sink))); + } + + 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(new ExecutionException(t)); + } + + @Override + public void onCompleted() { + sink.success(); + } + }; + } } diff --git a/sdk/src/test/java/io/dapr/client/DaprClientGrpcTest.java b/sdk/src/test/java/io/dapr/client/DaprClientGrpcTest.java index 33be4e32a..7d71939a1 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientGrpcTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientGrpcTest.java @@ -21,7 +21,6 @@ import io.dapr.client.domain.DeleteStateRequest; import io.dapr.client.domain.ExecuteStateTransactionRequest; import io.dapr.client.domain.GetBulkStateRequest; import io.dapr.client.domain.GetStateRequest; -import io.dapr.client.domain.HttpExtension; import io.dapr.client.domain.PublishEventRequest; import io.dapr.client.domain.State; import io.dapr.client.domain.StateOptions; @@ -45,7 +44,6 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; import org.mockito.ArgumentMatchers; -import org.mockito.Mockito; import org.mockito.stubbing.Answer; import reactor.core.publisher.Mono; @@ -63,7 +61,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; import static io.dapr.utils.TestUtils.assertThrowsDaprException; -import static io.dapr.utils.TestUtils.findFreePort; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -72,7 +69,12 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.argThat; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class DaprClientGrpcTest { @@ -84,6 +86,7 @@ public class DaprClientGrpcTest { private GrpcChannelFacade channel; private DaprGrpc.DaprStub daprStub; + private DaprHttp daprHttp; private DaprClient client; private ObjectSerializer serializer; @@ -91,10 +94,10 @@ public class DaprClientGrpcTest { public void setup() throws IOException { channel = mock(GrpcChannelFacade.class); daprStub = mock(DaprGrpc.DaprStub.class); + daprHttp = mock(DaprHttp.class); when(daprStub.withInterceptors(any())).thenReturn(daprStub); - DaprClient grpcClient = new DaprClientGrpc( - channel, daprStub, new DefaultObjectSerializer(), new DefaultObjectSerializer()); - client = new DaprClientProxy(grpcClient); + client = new DaprClientImpl( + channel, daprStub, daprHttp, new DefaultObjectSerializer(), new DefaultObjectSerializer()); serializer = new ObjectSerializer(); doNothing().when(channel).close(); } @@ -105,18 +108,6 @@ public class DaprClientGrpcTest { verify(channel).close(); } - @Test - public void waitForSidecarTimeout() { - Mockito.doReturn(Mono.error(new RuntimeException())).when(channel).waitForChannelReady(1); - assertThrows(RuntimeException.class, () -> client.waitForSidecar(1).block()); - } - - @Test - public void waitForSidecarOK() { - Mockito.doReturn(Mono.empty()).when(channel).waitForChannelReady(10000); - client.waitForSidecar(10000).block(); - } - @Test public void publishEventExceptionThrownTest() { doAnswer((Answer) invocation -> { @@ -150,7 +141,7 @@ public class DaprClientGrpcTest { @Test public void publishEventSerializeException() throws IOException { DaprObjectSerializer mockSerializer = mock(DaprObjectSerializer.class); - client = new DaprClientGrpc(channel, daprStub, mockSerializer, new DefaultObjectSerializer()); + client = new DaprClientImpl(channel, daprStub, daprHttp, mockSerializer, new DefaultObjectSerializer()); doAnswer((Answer) invocation -> { StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; observer.onNext(Empty.getDefaultInstance()); @@ -268,7 +259,7 @@ public class DaprClientGrpcTest { @Test public void invokeBindingSerializeException() throws IOException { DaprObjectSerializer mockSerializer = mock(DaprObjectSerializer.class); - client = new DaprClientGrpc(channel, daprStub, mockSerializer, new DefaultObjectSerializer()); + client = new DaprClientImpl(channel, daprStub, daprHttp, mockSerializer, new DefaultObjectSerializer()); doAnswer((Answer) invocation -> { StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; observer.onNext(Empty.getDefaultInstance()); @@ -419,440 +410,6 @@ public class DaprClientGrpcTest { assertFalse(called.get()); } - @Test - public void invokeServiceVoidExceptionThrownTest() { - 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, - "UNKNOWN", - "UNKNOWN: ", - () -> result.block()); - } - - @Test - public void invokeServiceIllegalArgumentExceptionThrownTest() { - 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 = client.invokeMethod("appId", "method", "request", null); - - assertThrows(IllegalArgumentException.class, () -> result.block()); - } - - @Test - public void invokeServiceEmptyRequestVoidExceptionThrownTest() { - 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, - "UNKNOWN", - "UNKNOWN: ", - () -> result.block()); - } - - @Test - public void invokeServiceVoidCallbackExceptionThrownTest() { - RuntimeException ex = new RuntimeException("An Exception"); - 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, - "UNKNOWN", - "UNKNOWN: java.lang.RuntimeException: An Exception", - () -> result.block()); - } - - @Test - 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()); - - Mono result = client.invokeMethod("appId", "method", "request", HttpExtension.NONE); - result.block(); - } - - @Test - 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()); - - MyObject request = new MyObject(1, "Event"); - Mono result = client.invokeMethod("appId", "method", request, HttpExtension.NONE); - result.block(); - } - - @Test - public void invokeServiceExceptionThrownTest() { - 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, - "UNKNOWN", - "UNKNOWN: ", - () -> result.block()); - } - - @Test - public void invokeServiceNoRequestClassExceptionThrownTest() { - 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, - "UNKNOWN", - "UNKNOWN: ", - () -> result.block()); - } - - @Test - public void invokeServiceNoRequestTypeRefExceptionThrownTest() { - 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, - "UNKNOWN", - "UNKNOWN: ", - () -> result.block()); - } - - @Test - public void invokeServiceCallbackExceptionThrownTest() { - RuntimeException ex = new RuntimeException("An Exception"); - 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, - "UNKNOWN", - "UNKNOWN: java.lang.RuntimeException: An Exception", - () -> result.block()); - } - - @Test - public void invokeServiceWithHttpExtensionTest() throws IOException { - HttpExtension httpExtension = new HttpExtension( - DaprHttp.HttpMethods.GET, Collections.singletonMap("test", Arrays.asList("1", "ab/c")), null); - CommonProtos.InvokeRequest message = CommonProtos.InvokeRequest.newBuilder() - .setMethod("method") - .setData(getAny("request")) - .setContentType("application/json") - .setHttpExtension(CommonProtos.HTTPExtension.newBuilder() - .setVerb(CommonProtos.HTTPExtension.Verb.GET) - .setQuerystring("test=1&test=ab%2Fc").build()) - .build(); - DaprProtos.InvokeServiceRequest request = DaprProtos.InvokeServiceRequest.newBuilder() - .setId("appId") - .setMessage(message) - .build(); - String expected = "Value"; - - doAnswer(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() { - String expected = "Value"; - 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"); - 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() { - 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, - "UNKNOWN", - "UNKNOWN: ", - () -> result.block()); - } - - @Test - public void invokeServiceNoRequestCallbackExceptionThrownTest() { - RuntimeException ex = new RuntimeException("An Exception"); - 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, - "UNKNOWN", - "UNKNOWN: java.lang.RuntimeException: An Exception", - () -> result.block()); - } - - @Test - public void invokeServiceNoRequestBodyTest() throws Exception { - String expected = "Value"; - 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"); - 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 { - doAnswer((Answer) invocation -> { - throw new RuntimeException(); - }).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any()); - String request = "Request"; - byte[] byteRequest = serializer.serialize(request); - - Mono result = client.invokeMethod("appId", "method", byteRequest, HttpExtension.NONE, byte[].class); - - assertThrowsDaprException( - RuntimeException.class, - "UNKNOWN", - "UNKNOWN: ", - () -> result.block()); - } - - @Test - public void invokeServiceByteRequestCallbackExceptionThrownTest() throws IOException { - RuntimeException ex = new RuntimeException("An Exception"); - 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 = - client.invokeMethod("appId", "method", byteRequest, HttpExtension.NONE,(HashMap) null); - - assertThrowsDaprException( - ExecutionException.class, - "UNKNOWN", - "UNKNOWN: java.lang.RuntimeException: An Exception", - () -> result.block()); - } - - @Test - public void invokeByteRequestServiceTest() throws Exception { - String expected = "Value"; - 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 = client.invokeMethod( - "appId", "method", byteRequest, HttpExtension.NONE, (HashMap) null); - byte[] byteOutput = result.block(); - - String strOutput = serializer.deserialize(byteOutput, String.class); - assertEquals(expected, strOutput); - } - - @Test - public void invokeServiceByteRequestObjectTest() throws Exception { - MyObject resultObj = new MyObject(1, "Value"); - 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 = client.invokeMethod("appId", "method", byteRequest, HttpExtension.NONE, byte[].class); - byte[] byteOutput = result.block(); - - assertEquals(resultObj, serializer.deserialize(byteOutput, MyObject.class)); - } - - @Test - public void invokeServiceNoRequestNoClassBodyExceptionThrownTest() { - 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, - "UNKNOWN", - "UNKNOWN: ", - () -> result.block()); - } - - @Test - public void invokeServiceNoRequestNoClassCallbackExceptionThrownTest() { - RuntimeException ex = new RuntimeException("An Exception"); - 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, - "UNKNOWN", - "UNKNOWN: java.lang.RuntimeException: An Exception", - () -> result.block()); - } - - @Test - public void invokeServiceNoRequestNoClassBodyTest() { - String expected = "Value"; - 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(); - } - - @Test - public void invokeServiceNoRequestNoHotMono() { - AtomicBoolean called = new AtomicBoolean(false); - String expected = "Value"; - 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(called.get()); - } - - @Test - public void invokeServiceNoRequestNoClassBodyObjectTest() throws Exception { - MyObject resultObj = new MyObject(1, "Value"); - 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(); - } - @Test public void getStateIllegalArgumentExceptionTest() { State key = buildStateKey(null, "Key1", "ETag1", null); @@ -1429,7 +986,7 @@ public class DaprClientGrpcTest { @Test public void executeTransactionSerializerExceptionTest() throws IOException { DaprObjectSerializer mockSerializer = mock(DaprObjectSerializer.class); - client = new DaprClientGrpc(channel, daprStub, mockSerializer, mockSerializer); + client = new DaprClientImpl(channel, daprStub, daprHttp, mockSerializer, mockSerializer); String etag = "ETag1"; String key = "key1"; String data = "my data"; diff --git a/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java index 9592377a2..0604e2129 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java @@ -15,76 +15,52 @@ package io.dapr.client; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.dataformat.xml.XmlMapper; -import io.dapr.client.domain.ConfigurationItem; -import io.dapr.client.domain.DeleteStateRequest; -import io.dapr.client.domain.GetBulkStateRequest; -import io.dapr.client.domain.GetStateRequest; import io.dapr.client.domain.HttpExtension; import io.dapr.client.domain.InvokeMethodRequest; -import io.dapr.client.domain.PublishEventRequest; -import io.dapr.client.domain.State; -import io.dapr.client.domain.StateOptions; -import io.dapr.client.domain.SubscribeConfigurationResponse; -import io.dapr.client.domain.TransactionalStateOperation; -import io.dapr.client.domain.UnsubscribeConfigurationRequest; -import io.dapr.client.domain.UnsubscribeConfigurationResponse; import io.dapr.config.Properties; -import io.dapr.exceptions.DaprError; import io.dapr.exceptions.DaprException; import io.dapr.serializer.DaprObjectSerializer; +import io.dapr.serializer.DefaultObjectSerializer; import io.dapr.utils.TypeRef; +import io.dapr.v1.DaprGrpc; import okhttp3.MediaType; import okhttp3.OkHttpClient; -import okhttp3.Request; import okhttp3.ResponseBody; import okhttp3.mock.Behavior; import okhttp3.mock.MediaTypes; import okhttp3.mock.MockInterceptor; -import okhttp3.mock.matchers.Matcher; -import okio.Buffer; -import okio.BufferedSink; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; -import reactor.test.scheduler.VirtualTimeScheduler; import reactor.util.context.Context; +import reactor.util.context.ContextView; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.time.Duration; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Base64; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; - -import reactor.util.context.ContextView; -import uk.org.webcompere.systemstubs.stream.SystemOut; import static io.dapr.utils.TestUtils.assertThrowsDaprException; import static io.dapr.utils.TestUtils.findFreePort; import static io.dapr.utils.TestUtils.formatIpAddress; - -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class DaprClientHttpTest { - private static final String STATE_STORE_NAME = "MyStateStore"; - - private static final String CONFIG_STORE_NAME = "MyConfigStore"; - - private static final String SECRET_STORE_NAME = "MySecretStore"; - private final String EXPECTED_RESULT = "{\"data\":\"ewoJCSJwcm9wZXJ0eUEiOiAidmFsdWVBIiwKCQkicHJvcGVydHlCIjogInZhbHVlQiIKCX0=\"}"; @@ -92,8 +68,6 @@ public class DaprClientHttpTest { private DaprClient daprClientHttp; - private DaprClient daprClientHttpXML; - private DaprHttp daprHttp; private OkHttpClient okHttpClient; @@ -106,14 +80,25 @@ public class DaprClientHttpTest { mockInterceptor = new MockInterceptor(Behavior.UNORDERED); okHttpClient = new OkHttpClient.Builder().addInterceptor(mockInterceptor).build(); daprHttp = new DaprHttp(sidecarIp, 3000, okHttpClient); - daprClientHttp = new DaprClientProxy(new DaprClientHttp(daprHttp)); - daprClientHttpXML = new DaprClientProxy(new DaprClientHttp(daprHttp, new XmlSerializer(), new XmlSerializer())); + daprClientHttp = buildDaprClient(daprHttp); + } + + private static DaprClient buildDaprClient(DaprHttp daprHttp) { + GrpcChannelFacade channel = mock(GrpcChannelFacade.class); + DaprGrpc.DaprStub daprStub = mock(DaprGrpc.DaprStub.class); + when(daprStub.withInterceptors(any())).thenReturn(daprStub); + try { + doNothing().when(channel).close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + return new DaprClientImpl(channel, daprStub, daprHttp, new DefaultObjectSerializer(), new DefaultObjectSerializer()); } @Test public void waitForSidecarTimeOutHealthCheck() throws Exception { daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - DaprClientHttp daprClientHttp = new DaprClientHttp(daprHttp); + DaprClient daprClientHttp = buildDaprClient(daprHttp); mockInterceptor.addRule() .get() @@ -138,7 +123,7 @@ public class DaprClientHttpTest { 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); + DaprClient daprClientHttp = buildDaprClient(daprHttp); mockInterceptor.addRule() .get() @@ -163,7 +148,7 @@ public class DaprClientHttpTest { 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); + DaprClient daprClientHttp = buildDaprClient(daprHttp); // Simulate a slow response mockInterceptor.addRule() @@ -192,7 +177,7 @@ public class DaprClientHttpTest { int port = findFreePort(); System.setProperty(Properties.HTTP_PORT.getName(), Integer.toString(port)); daprHttp = new DaprHttp(sidecarIp, port, okHttpClient); - DaprClientHttp daprClientHttp = new DaprClientHttp(daprHttp); + DaprClient daprClientHttp = buildDaprClient(daprHttp); mockInterceptor.addRule() .get() @@ -223,96 +208,11 @@ public class DaprClientHttpTest { }); t.start(); daprHttp = new DaprHttp(sidecarIp, port, okHttpClient); - DaprClientHttp daprClientHttp = new DaprClientHttp(daprHttp); + DaprClient daprClientHttp = buildDaprClient(daprHttp); daprClientHttp.waitForSidecar(10000).block(); } } - @Test - public void publishEventInvocation() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/publish/mypubsubname/A") - .respond(EXPECTED_RESULT); - String event = "{ \"message\": \"This is a test\" }"; - daprHttp = new DaprHttp(sidecarIp, 3000, okHttpClient); - DaprClientHttp daprClientHttp = new DaprClientHttp(daprHttp); - Mono mono = daprClientHttp.publishEvent("mypubsubname", "A", event, null); - assertNull(mono.block()); - } - - @Test - public void publishEventInvocationIPv6() { - String prevSidecarIp = sidecarIp; - System.setProperty(Properties.SIDECAR_IP.getName(), "2001:db8:3333:4444:5555:6666:7777:8888"); - sidecarIp = formatIpAddress(Properties.SIDECAR_IP.get()); - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/publish/mypubsubname/A") - .respond(EXPECTED_RESULT); - String event = "{ \"message\": \"This is a test\" }"; - daprHttp = new DaprHttp(sidecarIp, 3000, okHttpClient); - daprClientHttp = new DaprClientHttp(daprHttp); - System.setProperty(Properties.SIDECAR_IP.getName(), prevSidecarIp); - Mono mono = daprClientHttp.publishEvent("mypubsubname", "A", event, null); - assertNull(mono.block()); - } - - @Test - public void publishEvent() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/publish/mypubsubname/A") - .header("content-type", "application/json") - .respond(EXPECTED_RESULT); - String event = "{ \"message\": \"This is a test\" }"; - - Mono mono = daprClientHttp.publishEvent("mypubsubname","A", event); - assertNull(mono.block()); - } - - @Test - public void publishEventContentTypeOverride() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/publish/mypubsubname/A") - .header("content-type", "text/plain") - .respond(EXPECTED_RESULT); - String event = "{ \"message\": \"This is a test\" }"; - - Mono mono = daprClientHttp.publishEvent( - new PublishEventRequest("mypubsubname","A", event) - .setContentType("text/plain")); - assertNull(mono.block()); - } - - @Test - public void publishEventIfTopicIsNullOrEmpty() { - String event = "{ \"message\": \"This is a test\" }"; - - assertThrows(IllegalArgumentException.class, () -> - daprClientHttp.publishEvent("mypubsubname", null, event).block()); - assertThrows(IllegalArgumentException.class, () -> - daprClientHttp.publishEvent("mypubsubname", "", event).block()); - } - - @Test - public void publishEventIfPubsubIsNullOrEmpty() { - String event = "{ \"message\": \"This is a test\" }"; - - assertThrows(IllegalArgumentException.class, () -> - daprClientHttp.publishEvent(null, "A", event).block()); - assertThrows(IllegalArgumentException.class, () -> - daprClientHttp.publishEvent("", "A", event).block()); - } - - @Test - public void publishEventNoHotMono() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/publish/mypubsubname/A") - .respond(EXPECTED_RESULT); - String event = "{ \"message\": \"This is a test\" }"; - - daprClientHttp.publishEvent("mypubsubname", "", event); - // Should not throw exception because did not call block() on mono above. - } - @Test public void invokeServiceVerbNull() { mockInterceptor.addRule() @@ -552,1004 +452,13 @@ public class DaprClientHttpTest { result.block(); } - @Test - public void invokeBinding() { - Map map = new HashMap<>(); - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/bindings/sample-topic") - .respond(""); - - Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", ""); - assertNull(mono.block()); - } - - @Test - public void invokeBindingNullData() { - Map map = new HashMap<>(); - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/bindings/sample-topic") - .respond(""); - - Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", null); - assertNull(mono.block()); - } - - @Test - public void invokeBindingErrors() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/bindings/sample-topic") - .respond("NOT VALID JSON"); - - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.invokeBinding(null, "myoperation", "").block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.invokeBinding("", "myoperation", "").block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.invokeBinding("topic", null, "").block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.invokeBinding("topic", "", "").block(); - }); - assertThrowsDaprException(JsonParseException.class, () -> { - daprClientHttp.invokeBinding("sample-topic", "op", "data", String.class).block(); - }); - } - - @Test - public void invokeBindingResponseNull() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/bindings/sample-topic") - .respond(new byte[0]); - - Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", null, String.class); - assertNull(mono.block()); - } - - @Test - public void invokeBindingResponseObject() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/bindings/sample-topic") - .respond("\"OK\""); - - Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", null, String.class); - assertEquals("OK", mono.block()); - } - - @Test - public void invokeBindingResponseDouble() { - Map map = new HashMap<>(); - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/bindings/sample-topic") - .respond("1.5"); - - Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", map, double.class); - assertEquals(1.5, mono.block(), 0.0001); - } - - @Test - public void invokeBindingResponseFloat() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/bindings/sample-topic") - .respond("1.5"); - - Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", null, float.class); - assertEquals(1.5, mono.block(), 0.0001); - } - - @Test - public void invokeBindingResponseChar() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/bindings/sample-topic") - .respond("\"a\""); - - Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", null, char.class); - assertEquals('a', (char)mono.block()); - } - - @Test - public void invokeBindingResponseByte() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/bindings/sample-topic") - .respond("\"2\""); - - Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", null, byte.class); - assertEquals((byte)0x2, (byte)mono.block()); - } - - @Test - public void invokeBindingResponseLong() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/bindings/sample-topic") - .respond("1"); - - Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", null, long.class); - assertEquals(1, (long)mono.block()); - } - - @Test - public void invokeBindingResponseInt() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/bindings/sample-topic") - .respond("1"); - - Mono mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", null, int.class); - assertEquals(1, (int)mono.block()); - } - - @Test - public void invokeBindingNullName() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/bindings/sample-topic") - .respond(EXPECTED_RESULT); - - assertThrows(IllegalArgumentException.class, () -> - daprClientHttp.invokeBinding(null, "myoperation", "").block()); - } - - @Test - public void invokeBindingNullOpName() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/bindings/sample-topic") - .respond(EXPECTED_RESULT); - - assertThrows(IllegalArgumentException.class, () -> - daprClientHttp.invokeBinding("sample-topic", null, "").block()); - } - - @Test - public void bindingNoHotMono() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/bindings/sample-topic") - .respond(EXPECTED_RESULT); - - daprClientHttp.invokeBinding(null, "", ""); - // No exception is thrown because did not call block() on mono above. - } - - @Test - public void getStatesErrors() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/bulk") - .respond("NOT VALID JSON"); - - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.getBulkState(STATE_STORE_NAME, null, String.class).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.getBulkState(STATE_STORE_NAME, new ArrayList<>(), String.class).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.getBulkState(null, Arrays.asList("100", "200"), String.class).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.getBulkState("", Arrays.asList("100", "200"), String.class).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.getBulkState( - new GetBulkStateRequest(STATE_STORE_NAME, Collections.singletonList("100")).setParallelism(-1), - TypeRef.get(String.class)).block(); - }); - assertThrowsDaprException(JsonParseException.class, () -> { - daprClientHttp.getBulkState( - new GetBulkStateRequest(STATE_STORE_NAME, Collections.singletonList("100")), - TypeRef.get(String.class)).block(); - }); - } - - @Test - public void getStatesString() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/bulk") - .respond("[{\"key\": \"100\", \"data\": \"hello world\", \"etag\": \"1\"}," + - "{\"key\": \"200\", \"error\": \"not found\"}]"); - - List> result = - 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()); - assertEquals("1", 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 - public void getStatesInteger() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/bulk") - .respond("[{\"key\": \"100\", \"data\": 1234, \"etag\": \"1\"}," + - "{\"key\": \"200\", \"error\": \"not found\"}]"); - - List> result = - 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()); - assertEquals("1", 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()); - } - - @SuppressWarnings("OptionalGetWithoutIsPresent") - @Test - public void getStatesBoolean() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/bulk") - .respond("[{\"key\": \"100\", \"data\": true, \"etag\": \"1\"}," + - "{\"key\": \"200\", \"error\": \"not found\"}]"); - - List> result = - 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()); - assertTrue((boolean) result.stream().findFirst().get().getValue()); - assertEquals("1", 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 - public void getStatesByteArray() { - byte[] value = new byte[]{1, 2, 3}; - String base64Value = Base64.getEncoder().encodeToString(value); - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/bulk") - .respond("[{\"key\": \"100\", \"data\": \"" + base64Value + "\", \"etag\": \"1\"}," + - "{\"key\": \"200\", \"error\": \"not found\"}]"); - - // 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.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()); - assertEquals("1", 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 - public void getStatesObject() { - MyObject object = new MyObject(1, "Event"); - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/bulk") - .respond("[{\"key\": \"100\", \"data\": " + - "{ \"id\": \"" + object.id + "\", \"value\": \"" + object.value + "\"}, \"etag\": \"1\"}," + - "{\"key\": \"200\", \"error\": \"not found\"}]"); - - // 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.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("1", 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 - public void getState() { - StateOptions stateOptions = mock(StateOptions.class); - State stateKeyValue = new State<>("key", "value", "etag", stateOptions); - State stateKeyNull = new State<>(null, "value", "etag", stateOptions); - State stateKeyEmpty = new State<>("", "value", "etag", stateOptions); - State stateKeyBadPayload = new State<>("keyBadPayload", "value", "etag", stateOptions); - mockInterceptor.addRule() - .get("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/key") - .respond("\"" + EXPECTED_RESULT + "\""); - mockInterceptor.addRule() - .get("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/keyBadPayload") - .respond("NOT VALID"); - - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.getState(STATE_STORE_NAME, stateKeyNull, String.class).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.getState(STATE_STORE_NAME, stateKeyEmpty, String.class).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.getState(null, stateKeyValue, String.class).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.getState("", stateKeyValue, String.class).block(); - }); - assertThrowsDaprException(JsonParseException.class, () -> { - daprClientHttp.getState(STATE_STORE_NAME, stateKeyBadPayload, String.class).block(); - }); - Mono> mono = daprClientHttp.getState(STATE_STORE_NAME, stateKeyValue, String.class); - State result = mono.block(); - assertNotNull(result); - assertEquals(result.getKey(), "key"); - } - - @Test - public void getStatesEmptyEtag() { - State stateEmptyEtag = new State<>("key", "value", "", null); - mockInterceptor.addRule() - .get("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/key") - .respond("\"" + EXPECTED_RESULT + "\""); - - State monoEmptyEtag = daprClientHttp.getState(STATE_STORE_NAME, stateEmptyEtag, String.class).block(); - assertEquals(monoEmptyEtag.getKey(), "key"); - assertNull(monoEmptyEtag.getEtag()); - } - - @Test - public void getStateWithMetadata() { - Map metadata = new HashMap<>(); - metadata.put("key_1", "val_1"); - mockInterceptor.addRule() - .get("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/key?metadata.key_1=val_1") - .respond("\"" + EXPECTED_RESULT + "\""); - - GetStateRequest request = new GetStateRequest(STATE_STORE_NAME, "key"); - request.setMetadata(metadata); - Mono> monoMetadata = daprClientHttp.getState(request, TypeRef.get(String.class)); - assertEquals(monoMetadata.block().getKey(), "key"); - } - - @Test - public void getStateWithStateOptions() { - StateOptions stateOptions = new StateOptions(StateOptions.Consistency.STRONG, StateOptions.Concurrency.FIRST_WRITE); - mockInterceptor.addRule() - .get("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/key?consistency=strong&concurrency=first-write") - .respond("\"" + EXPECTED_RESULT + "\""); - - GetStateRequest request = new GetStateRequest(STATE_STORE_NAME, "key"); - request.setStateOptions(stateOptions); - Mono> monoOptions = daprClientHttp.getState(request, TypeRef.get(String.class)); - assertEquals(monoOptions.block().getKey(), "key"); - } - - @Test - public void getStatesNullEtag() { - State stateNullEtag = new State<>("key", "value", null, null); - mockInterceptor.addRule() - .get("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/key") - .respond("\"" + EXPECTED_RESULT + "\""); - - State monoNullEtag = daprClientHttp.getState(STATE_STORE_NAME, stateNullEtag, String.class).block(); - assertEquals(monoNullEtag.getKey(), "key"); - assertNull(monoNullEtag.getEtag()); - } - - @Test - public void getStatesNoHotMono() { - State stateNullEtag = new State<>("key", "value", null, null); - mockInterceptor.addRule() - .get("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/key") - .respond(500); - - daprClientHttp.getState(STATE_STORE_NAME, stateNullEtag, String.class); - // No exception should be thrown since did not call block() on mono above. - } - - @Test - public void saveStates() { - State stateKeyValue = new State<>("key", "value", "etag", null); - List> stateKeyValueList = Collections.singletonList(stateKeyValue); - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore") - .respond(EXPECTED_RESULT); - - Mono mono = daprClientHttp.saveBulkState(STATE_STORE_NAME, stateKeyValueList); - assertNull(mono.block()); - } - - @Test - public void saveStatesErrors() { - - assertThrows(IllegalArgumentException.class, () -> - daprClientHttp.saveBulkState(null, null).block()); - assertThrows(IllegalArgumentException.class, () -> - daprClientHttp.saveBulkState("", null).block()); - } - - @Test - public void saveStatesNull() { - List> stateKeyValueList = new ArrayList<>(); - - Mono mono = daprClientHttp.saveBulkState(STATE_STORE_NAME, null); - assertNull(mono.block()); - Mono mono1 = daprClientHttp.saveBulkState(STATE_STORE_NAME, stateKeyValueList); - assertNull(mono1.block()); - } - - @Test - public void saveStatesNullState() { - List> stateKeyValueList = new ArrayList<>(); - stateKeyValueList.add(null); - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore") - .respond(EXPECTED_RESULT); - - Mono mono1 = daprClientHttp.saveBulkState(STATE_STORE_NAME, stateKeyValueList); - assertNull(mono1.block()); - } - - @Test - public void saveStatesEtagNull() { - State stateKeyValue = new State<>("key", "value", null, null); - List> stateKeyValueList = Collections.singletonList(stateKeyValue); - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore") - .respond(EXPECTED_RESULT); - - Mono mono = daprClientHttp.saveBulkState(STATE_STORE_NAME, stateKeyValueList); - assertNull(mono.block()); - } - - @Test - public void saveStatesEtagEmpty() { - State stateKeyValue = new State<>("key", "value", "", null); - List> stateKeyValueList = Collections.singletonList(stateKeyValue); - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore") - .respond(EXPECTED_RESULT); - - Mono mono = daprClientHttp.saveBulkState(STATE_STORE_NAME, stateKeyValueList); - assertNull(mono.block()); - } - - @Test - public void simpleSaveStates() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore") - .respond(EXPECTED_RESULT); - StateOptions stateOptions = mock(StateOptions.class); - - Mono mono = daprClientHttp.saveState(STATE_STORE_NAME, "key", "etag", "value", stateOptions); - assertNull(mono.block()); - } - - @Test - public void saveStatesNoHotMono() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore") - .respond(500); - StateOptions stateOptions = mock(StateOptions.class); - - daprClientHttp.saveState(STATE_STORE_NAME, "key", "etag", "value", stateOptions); - // No exception should be thrown because we did not call block() on the mono above. - } - - @Test - public void simpleExecuteTransaction() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/transaction") - .matches(new BodyMatcher( - "{\"operations\":[{\"operation\":\"upsert\",\"request\":{\"value\":\"my data\",\"key\":\"key1\"," + - "\"etag\":\"ETag1\",\"options\":{}}},{\"operation\":\"delete\",\"request\":{\"key\":\"deleteKey\"}}]}" - )) - .respond(EXPECTED_RESULT); - String etag = "ETag1"; - String key = "key1"; - String data = "my data"; - StateOptions stateOptions = mock(StateOptions.class); - - - State stateKey = new State<>(key, data, etag, stateOptions); - TransactionalStateOperation upsertOperation = new TransactionalStateOperation<>( - TransactionalStateOperation.OperationType.UPSERT, - stateKey); - TransactionalStateOperation deleteOperation = new TransactionalStateOperation<>( - TransactionalStateOperation.OperationType.DELETE, - new State<>("deleteKey")); - Mono mono = daprClientHttp.executeStateTransaction(STATE_STORE_NAME, Arrays.asList(upsertOperation, - deleteOperation)); - assertNull(mono.block()); - } - - @Test - public void simpleExecuteTransactionXMLData() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/transaction") - .matches(new BodyMatcher("{\"operations\":[{\"operation\":\"upsert\"," + - "\"request\":{\"value\":\"PFN0cmluZz5teSBkYXRhPC9TdHJpbmc+\",\"key\":\"key1\",\"etag\":\"ETag1\"," + - "\"options\":{}}},{\"operation\":\"delete\",\"request\":{\"value\":\"PG51bGwvPg==\"," + - "\"key\":\"deleteKey\"}}]}")) - .respond(EXPECTED_RESULT); - String etag = "ETag1"; - String key = "key1"; - String data = "my data"; - StateOptions stateOptions = mock(StateOptions.class); - - - State stateKey = new State<>(key, data, etag, stateOptions); - TransactionalStateOperation upsertOperation = new TransactionalStateOperation<>( - TransactionalStateOperation.OperationType.UPSERT, - stateKey); - TransactionalStateOperation deleteOperation = new TransactionalStateOperation<>( - TransactionalStateOperation.OperationType.DELETE, - new State<>("deleteKey")); - Mono mono = daprClientHttpXML.executeStateTransaction(STATE_STORE_NAME, Arrays.asList(upsertOperation, - deleteOperation)); - assertNull(mono.block()); - } - - @Test - public void simpleExecuteTransactionNullEtag() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/transaction") - .respond(EXPECTED_RESULT); - String etag = null; - String key = "key1"; - String data = "my data"; - StateOptions stateOptions = mock(StateOptions.class); - - - State stateKey = new State<>(key, data, etag, stateOptions); - TransactionalStateOperation upsertOperation = new TransactionalStateOperation<>( - TransactionalStateOperation.OperationType.UPSERT, - stateKey); - TransactionalStateOperation deleteOperation = new TransactionalStateOperation<>( - TransactionalStateOperation.OperationType.DELETE, - new State<>("deleteKey")); - Mono mono = daprClientHttp.executeStateTransaction(STATE_STORE_NAME, Arrays.asList(upsertOperation, - deleteOperation)); - assertNull(mono.block()); - } - - @Test - public void simpleExecuteTransactionEmptyEtag() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/transaction") - .respond(EXPECTED_RESULT); - String etag = "empty"; - String key = "key1"; - String data = "my data"; - StateOptions stateOptions = mock(StateOptions.class); - - - State stateKey = new State<>(key, data, etag, stateOptions); - TransactionalStateOperation upsertOperation = new TransactionalStateOperation<>( - TransactionalStateOperation.OperationType.UPSERT, - stateKey); - TransactionalStateOperation deleteOperation = new TransactionalStateOperation<>( - TransactionalStateOperation.OperationType.DELETE, - new State<>("deleteKey")); - Mono mono = daprClientHttp.executeStateTransaction(STATE_STORE_NAME, Arrays.asList(upsertOperation, - deleteOperation)); - assertNull(mono.block()); - } - - @Test - public void simpleExecuteTransactionNullOperationAndNullState() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/transaction") - .respond(EXPECTED_RESULT); - String etag = null; - String key = "key1"; - String data = "my data"; - StateOptions stateOptions = mock(StateOptions.class); - - - State stateKey = new State<>(key, data, etag, stateOptions); - TransactionalStateOperation upsertOperation = new TransactionalStateOperation<>( - TransactionalStateOperation.OperationType.UPSERT, - stateKey); - TransactionalStateOperation deleteOperation = new TransactionalStateOperation<>( - TransactionalStateOperation.OperationType.DELETE, - new State<>("deleteKey")); - TransactionalStateOperation nullStateOperation = new TransactionalStateOperation<>( - TransactionalStateOperation.OperationType.DELETE, - null); - Mono mono = daprClientHttp.executeStateTransaction(STATE_STORE_NAME, Arrays.asList( - null, - nullStateOperation, - upsertOperation, - deleteOperation)); - assertNull(mono.block()); - } - - @Test - public void executeTransactionErrors() { - - assertThrows(IllegalArgumentException.class, () -> - daprClientHttp.executeStateTransaction(null, null).block()); - assertThrows(IllegalArgumentException.class, () -> - daprClientHttp.executeStateTransaction("", null).block()); - } - - @Test - public void simpleExecuteTransactionNull() { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/transaction") - .respond(EXPECTED_RESULT); - - Mono mono = daprClientHttp.executeStateTransaction(STATE_STORE_NAME, null); - assertNull(mono.block()); - mono = daprClientHttp.executeStateTransaction(STATE_STORE_NAME, Collections.emptyList()); - assertNull(mono.block()); - } - - @Test - public void deleteState() { - StateOptions stateOptions = mock(StateOptions.class); - State stateKeyValue = new State<>("key", "value", "etag", stateOptions); - mockInterceptor.addRule() - .delete("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/key") - .respond(EXPECTED_RESULT); - - Mono mono = daprClientHttp.deleteState(STATE_STORE_NAME, stateKeyValue.getKey(), stateKeyValue.getEtag(), stateOptions); - assertNull(mono.block()); - } - - @Test - public void deleteStateWithMetadata() { - Map metadata = new HashMap<>(); - metadata.put("key_1", "val_1"); - StateOptions stateOptions = mock(StateOptions.class); - State stateKeyValue = new State<>("key", "value", "etag", stateOptions); - mockInterceptor.addRule() - .delete("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/key?metadata.key_1=val_1") - .respond(EXPECTED_RESULT); - - DeleteStateRequest request = new DeleteStateRequest(STATE_STORE_NAME, stateKeyValue.getKey()); - request.setMetadata(metadata) - .setEtag(stateKeyValue.getEtag()) - .setStateOptions(stateOptions); - Mono monoMetadata = daprClientHttp.deleteState(request); - assertNull(monoMetadata.block()); - } - - @Test - public void deleteStateNoHotMono() { - StateOptions stateOptions = mock(StateOptions.class); - State stateKeyValue = new State<>("key", "value", "etag", stateOptions); - mockInterceptor.addRule() - .delete("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/key") - .respond(500); - - 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. - } - - @Test - public void deleteStateNullEtag() { - State stateKeyValue = new State<>("key", "value", null, null); - mockInterceptor.addRule() - .delete("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/key") - .respond(EXPECTED_RESULT); - - Mono mono = daprClientHttp.deleteState(STATE_STORE_NAME, stateKeyValue.getKey(), stateKeyValue.getEtag(), null); - assertNull(mono.block()); - } - - @Test - public void deleteStateEmptyEtag() { - State stateKeyValue = new State<>("key", "value", "", null); - mockInterceptor.addRule() - .delete("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/key") - .respond(EXPECTED_RESULT); - - Mono mono = daprClientHttp.deleteState(STATE_STORE_NAME, stateKeyValue.getKey(), stateKeyValue.getEtag(), null); - assertNull(mono.block()); - } - - @Test - public void deleteStateIllegalArgumentException() { - State stateKeyValueNull = new State<>(null, "value", "etag", null); - State stateKeyValueEmpty = new State<>("", "value", "etag", null); - mockInterceptor.addRule() - .delete("http://" + sidecarIp + ":3000/v1.0/state/MyStateStore/key") - .respond(EXPECTED_RESULT); - - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.deleteState(STATE_STORE_NAME, null, null, null).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.deleteState(STATE_STORE_NAME, "", null, null).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.deleteState(STATE_STORE_NAME, " ", null, null).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.deleteState(null, "key", null, null).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.deleteState("", "key", null, null).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.deleteState(" ", "key", null, null).block(); - }); - } - - @Test - public void getSecrets() { - mockInterceptor.addRule() - .get("http://" + sidecarIp + ":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(); - - assertEquals(1, secret.size()); - assertEquals("mysecretvalue", secret.get("mysecretkey")); - } - - @Test - public void getSecretsSpecialCharsInKey() { - mockInterceptor.addRule() - .get("http://" + sidecarIp + ":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://" + sidecarIp + ":3000/v1.0/secrets/MySecretStore/key") - .respond(""); - - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.getSecret(SECRET_STORE_NAME, null).block(); - }); - Map secret = daprClientHttp.getSecret(SECRET_STORE_NAME, "key").block(); - - assertTrue(secret.isEmpty()); - } - - @Test - public void getSecrets404() { - mockInterceptor.addRule() - .get("http://" + sidecarIp + ":3000/v1.0/secrets/MySecretStore/key") - .respond(404); - - assertThrowsDaprException("UNKNOWN", () -> - daprClientHttp.getSecret(SECRET_STORE_NAME, "key").block() - ); - } - - @Test - public void getSecrets404WithErrorCode() { - mockInterceptor.addRule() - .get("http://" + sidecarIp + ":3000/v1.0/secrets/MySecretStore/key") - .respond(404, - ResponseBody.create("" + - "{\"errorCode\":\"ERR_SECRET_STORE_NOT_FOUND\"," + - "\"message\":\"error message\"}", MediaTypes.MEDIATYPE_JSON)); - - assertThrowsDaprException("ERR_SECRET_STORE_NOT_FOUND", "ERR_SECRET_STORE_NOT_FOUND: error message", () -> - daprClientHttp.getSecret(SECRET_STORE_NAME, "key").block() - ); - } - - @Test - public void getSecretsErrors() { - mockInterceptor.addRule() - .get("http://" + sidecarIp + ":3000/v1.0/secrets/MySecretStore/key") - .respond("INVALID JSON"); - - assertThrows(IllegalArgumentException.class, () -> - daprClientHttp.getSecret(null, "key").block()); - assertThrows(IllegalArgumentException.class, () -> - daprClientHttp.getSecret("", "key").block()); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.getSecret(SECRET_STORE_NAME, null).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.getSecret(SECRET_STORE_NAME, "").block(); - }); - assertThrowsDaprException(JsonParseException.class, () -> { - daprClientHttp.getSecret(SECRET_STORE_NAME, "key").block(); - }); - } - - @Test - public void getSecretsWithMetadata() { - mockInterceptor.addRule() - .get("http://" + sidecarIp + ":3000/v1.0/secrets/MySecretStore/key") - .respond("{ \"mysecretkey\": \"mysecretvalue\"}"); - mockInterceptor.addRule() - .get("http://" + sidecarIp + ":3000/v1.0/secrets/MySecretStore/key?metadata.metakey=metavalue") - .respond("{ \"mysecretkey2\": \"mysecretvalue2\"}"); - - { - Map secret = daprClientHttp.getSecret( - SECRET_STORE_NAME, - "key", - null).block(); - - assertEquals(1, secret.size()); - assertEquals("mysecretvalue", secret.get("mysecretkey")); - } - - { - Map secret = daprClientHttp.getSecret( - SECRET_STORE_NAME, - "key", - Collections.singletonMap("metakey", "metavalue")).block(); - - assertEquals(1, secret.size()); - assertEquals("mysecretvalue2", secret.get("mysecretkey2")); - } - } - - @Test - public void getBulkSecrets() { - mockInterceptor.addRule() - .get("http://" + sidecarIp + ":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://" + sidecarIp + ":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 getConfigurationTestErrorScenario() { - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.getConfiguration("", "key").block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.getConfiguration(" ", "key").block(); - }); - } - - @Test - public void getConfigurationTest() { - mockInterceptor.addRule() - .get() - .path("/v1.0/configuration/MyConfigStore") - .param("key","configkey1") - .respond("{\"configkey1\" : {\"value\" : \"configvalue1\",\"version\" : \"1\"}}"); - - ConfigurationItem ci = daprClientHttp.getConfiguration(CONFIG_STORE_NAME, "configkey1").block(); - assertNotNull(ci); - assertEquals("configkey1", ci.getKey()); - assertEquals("configvalue1", ci.getValue()); - assertEquals("1", ci.getVersion()); - } - - @Test - public void getAllConfigurationTest() { - mockInterceptor.addRule() - .get() - .path("/v1.0/configuration/MyConfigStore") - .respond("{\"configkey1\" : {\"value\" : \"configvalue1\",\"version\" : \"1\"}}"); - - ConfigurationItem ci = daprClientHttp.getConfiguration(CONFIG_STORE_NAME, "configkey1").block(); - assertNotNull(ci); - assertEquals("configkey1", ci.getKey()); - assertEquals("configvalue1", ci.getValue()); - assertEquals("1", ci.getVersion()); - } - - @Test - public void subscribeConfigurationTest() { - mockInterceptor.addRule() - .get() - .path("/v1.0/configuration/MyConfigStore/subscribe") - .param("key", "configkey1") - .respond("{\"id\":\"1234\"}"); - - Iterator itr = daprClientHttp.subscribeConfiguration(CONFIG_STORE_NAME, "configkey1").toIterable().iterator(); - assertTrue(itr.hasNext()); - SubscribeConfigurationResponse res = itr.next(); - assertEquals("1234", res.getSubscriptionId()); - assertFalse(itr.hasNext()); - } - - @Test - public void subscribeAllConfigurationTest() { - mockInterceptor.addRule() - .get() - .path("/v1.0/configuration/MyConfigStore/subscribe") - .respond("{\"id\":\"1234\"}"); - - Iterator itr = daprClientHttp.subscribeConfiguration(CONFIG_STORE_NAME, "configkey1").toIterable().iterator(); - assertTrue(itr.hasNext()); - SubscribeConfigurationResponse res = itr.next(); - assertEquals("1234", res.getSubscriptionId()); - assertFalse(itr.hasNext()); - } - - @Test - public void unsubscribeConfigurationTest() { - mockInterceptor.addRule() - .get() - .path("/v1.0/configuration/MyConfigStore/1234/unsubscribe") - .respond("{\"ok\": true}"); - - UnsubscribeConfigurationResponse res = daprClientHttp.unsubscribeConfiguration("1234", CONFIG_STORE_NAME).block(); - assertTrue(res.getIsUnsubscribed()); - } - - @Test - public void unsubscribeConfigurationTestWithError() { - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.unsubscribeConfiguration("", CONFIG_STORE_NAME).block(); - }); - - UnsubscribeConfigurationRequest req = new UnsubscribeConfigurationRequest("subscription_id", ""); - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.unsubscribeConfiguration(req).block(); - }); - - mockInterceptor.addRule() - .get() - .path("/v1.0/configuration/MyConfigStore/1234/unsubscribe") - .respond("{\"ok\": false, \"message\": \"some error while unsubscribing\"}"); - UnsubscribeConfigurationResponse res = daprClientHttp.unsubscribeConfiguration("1234", CONFIG_STORE_NAME).block(); - assertFalse(res.getIsUnsubscribed()); - } - - @Test - public void subscribeConfigurationTestWithError() { - assertThrows(IllegalArgumentException.class, () -> { - daprClientHttp.subscribeConfiguration("", "key1").blockFirst(); - }); - - mockInterceptor.addRule() - .get() - .path("/v1.0/configuration/MyConfigStore/subscribe") - .param("key", "configkey1") - .respond(500); - assertThrows(DaprException.class, () -> { - daprClientHttp.subscribeConfiguration(CONFIG_STORE_NAME, "configkey1").blockFirst(); - }); - } - @Test public void closeException() { DaprHttp daprHttp = Mockito.mock(DaprHttp.class); Mockito.doThrow(new RuntimeException()).when(daprHttp).close(); // This method does not throw DaprException because it already throws RuntimeException and does not call Dapr. - daprClientHttp = new DaprClientHttp(daprHttp); + daprClientHttp = buildDaprClient(daprHttp); assertThrows(RuntimeException.class, () -> daprClientHttp.close()); } @@ -1559,53 +468,10 @@ public class DaprClientHttpTest { Mockito.doNothing().when(daprHttp).close(); // This method does not throw DaprException because IOException is expected by the Closeable interface. - daprClientHttp = new DaprClientHttp(daprHttp); + daprClientHttp = buildDaprClient(daprHttp); daprClientHttp.close(); } - @Test - public void shutdown() throws Exception { - mockInterceptor.addRule() - .post("http://" + sidecarIp + ":3000/v1.0/shutdown") - .respond(204); - - final Mono mono = daprClientHttp.shutdown(); - assertNull(mono.block()); - } - - private static final class BodyMatcher implements Matcher { - - private final String expected; - - private BodyMatcher(String expected) { - this.expected = expected; - } - - @Override - public boolean matches(Request request) { - BufferedSink sink = new Buffer(); - try { - request.body().writeTo(sink); - } catch (IOException e) { - return false; - } - String body = sink.getBuffer().readByteString().utf8(); - return expected.equals(body); - } - - @Override - public String failReason(Request request) { - BufferedSink sink = new Buffer(); - try { - request.body().writeTo(sink); - } catch (IOException e) { - throw new RuntimeException(e); - } - String body = sink.getBuffer().readByteString().utf8(); - return String.format("Body does not match expected:\n%s\nvs actual\n%s", expected, body); - } - } - private static class XmlSerializer implements DaprObjectSerializer { private static final XmlMapper XML_MAPPER = new XmlMapper(); @@ -1625,53 +491,4 @@ public class DaprClientHttpTest { return "application/xml"; } } - - public static class MyObject { - private Integer id; - private String value; - - public MyObject() { - } - - public MyObject(Integer id, String value) { - this.id = id; - this.value = value; - } - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof MyObject)) return false; - - MyObject myObject = (MyObject) o; - - if (!getId().equals(myObject.getId())) return false; - if (getValue() != null ? !getValue().equals(myObject.getValue()) : myObject.getValue() != null) return false; - - return true; - } - - @Override - public int hashCode() { - int result = getId().hashCode(); - result = 31 * result + (getValue() != null ? getValue().hashCode() : 0); - return result; - } - } } \ No newline at end of file diff --git a/sdk/src/test/java/io/dapr/client/DaprClientProxyTest.java b/sdk/src/test/java/io/dapr/client/DaprClientProxyTest.java deleted file mode 100644 index 375e8b083..000000000 --- a/sdk/src/test/java/io/dapr/client/DaprClientProxyTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2021 The Dapr Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and -limitations under the License. -*/ -package io.dapr.client; - -import io.dapr.client.domain.HttpExtension; -import org.junit.jupiter.api.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(); - } - -} diff --git a/sdk/src/test/java/io/dapr/client/DaprClientTestBuilder.java b/sdk/src/test/java/io/dapr/client/DaprClientTestBuilder.java index b0984bac4..ef9e9788f 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientTestBuilder.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientTestBuilder.java @@ -13,17 +13,19 @@ limitations under the License. package io.dapr.client; +import io.dapr.serializer.DefaultObjectSerializer; + /** * Builder for DaprClient used in tests only. */ public class DaprClientTestBuilder { /** - * Builds a DaprClient. + * Builds a DaprClient only for HTTP calls. * @param client DaprHttp used for http calls (can be mocked or stubbed) * @return New instance of DaprClient. */ - public static DaprClient buildHttpClient(DaprHttp client) { - return new DaprClientHttp(client); + public static DaprClient buildClientForHttpOnly(DaprHttp client) { + return new DaprClientImpl(null, null, client, new DefaultObjectSerializer(), new DefaultObjectSerializer()); } } diff --git a/sdk/src/test/java/io/dapr/client/DaprExceptionTest.java b/sdk/src/test/java/io/dapr/client/DaprExceptionTest.java index 7310480d8..4abb10186 100644 --- a/sdk/src/test/java/io/dapr/client/DaprExceptionTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprExceptionTest.java @@ -40,16 +40,17 @@ import static org.mockito.Mockito.when; public class DaprExceptionTest { private GrpcChannelFacade channel; private DaprGrpc.DaprStub daprStub; + private DaprHttp daprHttp; private DaprClient client; @BeforeEach public void setup() throws IOException { channel = mock(GrpcChannelFacade.class); daprStub = mock(DaprGrpc.DaprStub.class); + daprHttp = mock(DaprHttp.class); when(daprStub.withInterceptors(any())).thenReturn(daprStub); - DaprClient grpcClient = new DaprClientGrpc( - channel, daprStub, new DefaultObjectSerializer(), new DefaultObjectSerializer()); - client = new DaprClientProxy(grpcClient); + client = new DaprClientImpl( + channel, daprStub, daprHttp, new DefaultObjectSerializer(), new DefaultObjectSerializer()); doNothing().when(channel).close(); } diff --git a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java index ceac55587..e976e41b4 100644 --- a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java @@ -16,17 +16,17 @@ import io.dapr.config.Properties; import io.dapr.exceptions.DaprErrorDetails; import io.dapr.exceptions.DaprException; import io.dapr.utils.TypeRef; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.extension.ExtendWith; -import reactor.test.StepVerifier; -import reactor.util.context.Context; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.ResponseBody; import okhttp3.mock.Behavior; import okhttp3.mock.MockInterceptor; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; +import reactor.util.context.Context; import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; import uk.org.webcompere.systemstubs.jupiter.SystemStub; import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; diff --git a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java index 1292de68c..200b4cae6 100644 --- a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java @@ -17,8 +17,8 @@ package io.dapr.client; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.protobuf.ByteString; -import io.dapr.client.domain.BulkPublishRequest; import io.dapr.client.domain.BulkPublishEntry; +import io.dapr.client.domain.BulkPublishRequest; import io.dapr.client.domain.BulkPublishResponse; import io.dapr.client.domain.QueryStateItem; import io.dapr.client.domain.QueryStateRequest; @@ -74,15 +74,17 @@ public class DaprPreviewClientGrpcTest { private GrpcChannelFacade channel; private DaprGrpc.DaprStub daprStub; + private DaprHttp daprHttp; private DaprPreviewClient previewClient; @BeforeEach public void setup() throws IOException { channel = mock(GrpcChannelFacade.class); daprStub = mock(DaprGrpc.DaprStub.class); + daprHttp = mock(DaprHttp.class); when(daprStub.withInterceptors(any())).thenReturn(daprStub); - previewClient = new DaprClientGrpc( - channel, daprStub, new DefaultObjectSerializer(), new DefaultObjectSerializer()); + previewClient = new DaprClientImpl( + channel, daprStub, daprHttp, new DefaultObjectSerializer(), new DefaultObjectSerializer()); doNothing().when(channel).close(); } @@ -147,7 +149,7 @@ public class DaprPreviewClientGrpcTest { @Test public void publishEventsSerializeException() throws IOException { DaprObjectSerializer mockSerializer = mock(DaprObjectSerializer.class); - previewClient = new DaprClientGrpc(channel, daprStub, mockSerializer, new DefaultObjectSerializer()); + previewClient = new DaprClientImpl(channel, daprStub, daprHttp, mockSerializer, new DefaultObjectSerializer()); doAnswer((Answer) invocation -> { StreamObserver observer = (StreamObserver) invocation.getArguments()[1]; diff --git a/sdk/src/test/java/io/dapr/client/DaprPreviewClientHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprPreviewClientHttpTest.java deleted file mode 100644 index c96e8260d..000000000 --- a/sdk/src/test/java/io/dapr/client/DaprPreviewClientHttpTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2021 The Dapr Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io.dapr.client; - -import io.dapr.client.domain.LockRequest; -import io.dapr.client.domain.QueryStateRequest; -import io.dapr.client.domain.QueryStateResponse; -import io.dapr.client.domain.UnlockRequest; -import io.dapr.client.domain.UnlockResponseStatus; -import io.dapr.client.domain.query.Query; -import io.dapr.config.Properties; -import io.dapr.utils.TypeRef; -import okhttp3.OkHttpClient; -import okhttp3.mock.Behavior; -import okhttp3.mock.MockInterceptor; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Mono; - - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; - -public class DaprPreviewClientHttpTest { - - private static final String LOCK_STORE_NAME = "MyLockStore"; - - private DaprPreviewClient daprPreviewClientHttp; - - private DaprHttp daprHttp; - - private OkHttpClient okHttpClient; - - private MockInterceptor mockInterceptor; - - @BeforeEach - public void setUp() { - mockInterceptor = new MockInterceptor(Behavior.UNORDERED); - okHttpClient = new OkHttpClient.Builder().addInterceptor(mockInterceptor).build(); - daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); - daprPreviewClientHttp = new DaprClientHttp(daprHttp); - } - - @Test - public void queryStateExceptionsTest() { - assertThrows(IllegalArgumentException.class, () -> { - daprPreviewClientHttp.queryState("", "query", TypeRef.BOOLEAN).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprPreviewClientHttp.queryState("", "query", String.class).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprPreviewClientHttp.queryState("storeName", "", TypeRef.BOOLEAN).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprPreviewClientHttp.queryState("storeName", "", String.class).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprPreviewClientHttp.queryState("storeName", (Query) null, TypeRef.BOOLEAN).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprPreviewClientHttp.queryState("storeName", (Query) null, String.class).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprPreviewClientHttp.queryState("storeName", (String) null, TypeRef.BOOLEAN).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprPreviewClientHttp.queryState("storeName", (String) null, String.class).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprPreviewClientHttp.queryState(null, TypeRef.BOOLEAN).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprPreviewClientHttp.queryState(new QueryStateRequest("storeName"), TypeRef.BOOLEAN).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - daprPreviewClientHttp.queryState(null, String.class).block(); - }); - } - - @Test - public void queryStateTest() { - mockInterceptor.addRule() - .post() - .path("/v1.0-alpha1/state/testStore/query") - .respond("{\"results\": [{\"key\": \"1\",\"data\": \"testData\"," - + "\"etag\": \"6f54ad94-dfb9-46f0-a371-e42d550adb7d\"}]}"); - QueryStateResponse response = daprPreviewClientHttp.queryState("testStore", "query", String.class).block(); - assertNotNull(response); - assertEquals(1, response.getResults().size(), "result size must be 1"); - assertEquals( "1", response.getResults().get(0).getKey(), "result must be same"); - assertEquals("testData", response.getResults().get(0).getValue(), "result must be same"); - assertEquals( "6f54ad94-dfb9-46f0-a371-e42d550adb7d", response.getResults().get(0).getEtag(), "result must be same"); - } - - @Test - public void tryLock() { - mockInterceptor.addRule() - .post("http://127.0.0.1:3000/v1.0-alpha1/lock/MyLockStore") - .respond("{ \"success\": true}"); - - LockRequest lockRequest = new LockRequest(LOCK_STORE_NAME,"1","owner",10); - - Mono mono = daprPreviewClientHttp.tryLock(lockRequest); - assertEquals(Boolean.TRUE, mono.block()); - } - - @Test - public void unLock() { - mockInterceptor.addRule() - .post("http://127.0.0.1:3000/v1.0-alpha1/unlock/MyLockStore") - .respond("{ \"status\": 0}"); - - UnlockRequest unLockRequest = new UnlockRequest(LOCK_STORE_NAME,"1","owner"); - - Mono mono = daprPreviewClientHttp.unlock(unLockRequest); - assertEquals(UnlockResponseStatus.SUCCESS, mono.block()); - } -} diff --git a/sdk/src/test/java/io/dapr/client/GrpcChannelFacadeTest.java b/sdk/src/test/java/io/dapr/client/GrpcChannelFacadeTest.java deleted file mode 100644 index 206c0bc5d..000000000 --- a/sdk/src/test/java/io/dapr/client/GrpcChannelFacadeTest.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2023 The Dapr Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io.dapr.client; - -import io.dapr.config.Properties; -import io.dapr.utils.NetworkUtils; -import io.dapr.v1.DaprGrpc; -import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; -import io.grpc.Server; -import io.grpc.ServerBuilder; -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.inprocess.InProcessServerBuilder; -import io.grpc.testing.GrpcCleanupRule; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.ResponseBody; -import okhttp3.mock.Behavior; -import okhttp3.mock.MockInterceptor; -import org.junit.Before; -import org.junit.Rule; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import reactor.test.StepVerifier; -import reactor.test.scheduler.VirtualTimeScheduler; - -import java.io.IOException; -import java.time.Duration; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import static io.dapr.utils.TestUtils.findFreePort; -import static org.junit.jupiter.api.Assertions.assertThrows; - -public class GrpcChannelFacadeTest { - - private static int port; - - public static Server server; - - private MockInterceptor mockInterceptor; - - private OkHttpClient okHttpClient; - - private static DaprHttp daprHttp; - - @Rule - public static final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); - - /** - * Enable the waitForSidecar to allow the gRPC to check the http endpoint for the health check - */ - @BeforeEach - public void setUp() { - mockInterceptor = new MockInterceptor(Behavior.UNORDERED); - okHttpClient = new OkHttpClient.Builder().addInterceptor(mockInterceptor).build(); - } - - @BeforeAll - public static void setup() throws IOException { - port = findFreePort(); - - // Create a server, add service, start, and register for automatic graceful shutdown. - grpcCleanup.register(ServerBuilder.forPort(port) - .addService(new DaprGrpc.DaprImplBase() { - }) - .build().start()); - } - - @AfterAll - public static void teardown() throws InterruptedException { - if (daprHttp != null) { - daprHttp.close(); - } - } - - @Test - public void waitForSidecarTimeoutHealthCheck() throws Exception { - OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(mockInterceptor).build(); - DaprHttp daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3500, okHttpClient); - - ManagedChannel channel = InProcessChannelBuilder.forName("waitForSidecarTimeoutHealthCheck").build(); - grpcCleanup.register(channel); - final GrpcChannelFacade channelFacade = new GrpcChannelFacade(channel, daprHttp); - - mockInterceptor.addRule() - .get() - .path("/v1.0/healthz/outbound") - .times(6) - .respond(404, ResponseBody.create("Not Found", MediaType.get("application/json"))); - - StepVerifier.create(channelFacade.waitForChannelReady(1000)) - .expectSubscription() - .expectError(TimeoutException.class) - .verify(Duration.ofSeconds(20)); - } - - @Test - public void waitForSidecarOK() { - OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(mockInterceptor).build(); - - DaprHttp daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3500, okHttpClient); - - ManagedChannel channel = ManagedChannelBuilder.forAddress("127.0.0.1", port) - .usePlaintext().build(); - - grpcCleanup.register(channel); - - final GrpcChannelFacade channelFacade = new GrpcChannelFacade(channel, daprHttp); - - // added since this is doing a check against the http health check endpoint - // for parity with dotnet - mockInterceptor.addRule() - .get() - .path("/v1.0/healthz/outbound") - .respond(204); - - StepVerifier.create(channelFacade.waitForChannelReady(10000)) - .expectSubscription() - .expectComplete() - .verify(); - } -} diff --git a/sdk/src/test/java/io/dapr/client/domain/BulkPublishRequestTest.java b/sdk/src/test/java/io/dapr/client/domain/BulkPublishRequestTest.java index e4932c4e9..5211cec48 100644 --- a/sdk/src/test/java/io/dapr/client/domain/BulkPublishRequestTest.java +++ b/sdk/src/test/java/io/dapr/client/domain/BulkPublishRequestTest.java @@ -16,10 +16,8 @@ package io.dapr.client.domain; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertNull; diff --git a/sdk/src/test/java/io/dapr/client/domain/DeleteStateRequestTest.java b/sdk/src/test/java/io/dapr/client/domain/DeleteStateRequestTest.java index a22b51005..d90494a8d 100644 --- a/sdk/src/test/java/io/dapr/client/domain/DeleteStateRequestTest.java +++ b/sdk/src/test/java/io/dapr/client/domain/DeleteStateRequestTest.java @@ -3,7 +3,6 @@ package io.dapr.client.domain; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.util.Collections; import java.util.HashMap; import java.util.Map; diff --git a/sdk/src/test/java/io/dapr/client/domain/GetBulkStateRequestTest.java b/sdk/src/test/java/io/dapr/client/domain/GetBulkStateRequestTest.java index 55e7d1ea3..f7ccb51f8 100644 --- a/sdk/src/test/java/io/dapr/client/domain/GetBulkStateRequestTest.java +++ b/sdk/src/test/java/io/dapr/client/domain/GetBulkStateRequestTest.java @@ -7,10 +7,8 @@ import java.util.HashMap; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; public class GetBulkStateRequestTest { diff --git a/sdk/src/test/java/io/dapr/client/domain/GetSecretRequestTest.java b/sdk/src/test/java/io/dapr/client/domain/GetSecretRequestTest.java index e37640344..9280ffd3d 100644 --- a/sdk/src/test/java/io/dapr/client/domain/GetSecretRequestTest.java +++ b/sdk/src/test/java/io/dapr/client/domain/GetSecretRequestTest.java @@ -2,14 +2,11 @@ package io.dapr.client.domain; import org.junit.jupiter.api.Test; -import java.util.Collections; import java.util.HashMap; import java.util.Map; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertSame; public class GetSecretRequestTest { diff --git a/sdk/src/test/java/io/dapr/client/domain/query/QueryTest.java b/sdk/src/test/java/io/dapr/client/domain/query/QueryTest.java index 957fea929..688785e3c 100644 --- a/sdk/src/test/java/io/dapr/client/domain/query/QueryTest.java +++ b/sdk/src/test/java/io/dapr/client/domain/query/QueryTest.java @@ -2,7 +2,11 @@ package io.dapr.client.domain.query; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import io.dapr.client.domain.query.filters.*; +import io.dapr.client.domain.query.filters.AndFilter; +import io.dapr.client.domain.query.filters.EqFilter; +import io.dapr.client.domain.query.filters.Filter; +import io.dapr.client.domain.query.filters.InFilter; +import io.dapr.client.domain.query.filters.OrFilter; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/sdk/src/test/java/io/dapr/runtime/DaprRuntimeTest.java b/sdk/src/test/java/io/dapr/runtime/DaprRuntimeTest.java index 8ae30b412..2343ca059 100644 --- a/sdk/src/test/java/io/dapr/runtime/DaprRuntimeTest.java +++ b/sdk/src/test/java/io/dapr/runtime/DaprRuntimeTest.java @@ -127,24 +127,8 @@ public class DaprRuntimeTest { generateSingleMetadata()) }; - DaprHttpStub daprHttp = mock(DaprHttpStub.class); - DaprClient client = DaprClientTestBuilder.buildHttpClient(daprHttp); - DaprObjectSerializer serializer = new DefaultObjectSerializer(); - for (Message message : messages) { - when(daprHttp.invokeApi( - eq("POST"), - eq((PUBLISH_PATH + "/" + PUBSUB_NAME + "/" + TOPIC_NAME).split("/")), - any(), - eq(serializer.serialize(message.data)), - any(), - any())) - .thenAnswer(invocationOnMock -> this.daprRuntime.handleInvocation( - TOPIC_NAME, - this.serialize(message), - message.metadata).then()); - - client.publishEvent(PUBSUB_NAME, TOPIC_NAME, message.data).block(); + this.daprRuntime.handleInvocation(TOPIC_NAME, this.serialize(message), message.metadata); CloudEvent envelope = new CloudEvent( message.id, @@ -212,7 +196,7 @@ public class DaprRuntimeTest { }; DaprHttpStub daprHttp = mock(DaprHttpStub.class); - DaprClient client = DaprClientTestBuilder.buildHttpClient(daprHttp); + DaprClient client = DaprClientTestBuilder.buildClientForHttpOnly(daprHttp); DaprObjectSerializer serializer = new DefaultObjectSerializer(); for (Message message : messages) { diff --git a/sdk/src/test/java/io/dapr/utils/DurationUtilsTest.java b/sdk/src/test/java/io/dapr/utils/DurationUtilsTest.java index dd75781f7..02aa5b1a7 100644 --- a/sdk/src/test/java/io/dapr/utils/DurationUtilsTest.java +++ b/sdk/src/test/java/io/dapr/utils/DurationUtilsTest.java @@ -14,7 +14,6 @@ limitations under the License. package io.dapr.utils; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.time.Duration;