Remove HTTP client and add gRPC interceptor helper. (#1051)

* Remove HTTP client and add gRPC interceptor helper.

Signed-off-by: Artur Souza <asouza.pro@gmail.com>

* New design for gRPC interceptor and channel proxy.

Signed-off-by: Artur Souza <asouza.pro@gmail.com>

---------

Signed-off-by: Artur Souza <asouza.pro@gmail.com>
Signed-off-by: Artur Souza <artursouza.ms@outlook.com>
This commit is contained in:
Artur Souza 2024-06-21 06:35:25 -07:00 committed by GitHub
parent 9048bc1a5e
commit 502f7c0638
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
107 changed files with 1147 additions and 5828 deletions

View File

@ -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: |

View File

@ -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)

View File

@ -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

View File

@ -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:
<!-- STEP
name: Setup kafka container

View File

@ -1,4 +1,4 @@
version: '2'
version: '3'
services:
zookeeper:
image: confluentinc/cp-zookeeper:7.4.4

View File

@ -11,7 +11,7 @@
limitations under the License.
*/
package io.dapr.examples.configuration.grpc;
package io.dapr.examples.configuration;
import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;

View File

@ -158,7 +158,7 @@ sleep: 10
-->
```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
```
<!-- END_STEP -->

View File

@ -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<String> keys = new ArrayList<>();
keys.add("myconfig1");
keys.add("myconfig2");
keys.add("myconfig3");
Map<String, String> hmap = new HashMap<>();
hmap.put("meta_key","meta_value");
GetConfigurationRequest req = new GetConfigurationRequest(CONFIG_STORE_NAME, keys);
req.setMetadata(hmap);
try {
Mono<Map<String, ConfigurationItem>> 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<SubscribeConfigurationResponse> 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);
}
}

View File

@ -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);
}
}

View File

@ -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
<!-- STEP
name: Set configuration value
expected_stdout_lines:
- "OK"
timeout_seconds: 20
-->
```bash
docker exec dapr_redis redis-cli MSET myconfig1 "val1||1" myconfig2 "val2||1" myconfig3 "val3||1"
```
<!-- END_STEP -->
### 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<List<ConfigurationItem>> 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<SubscribeConfigurationResponse> 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:
<!-- STEP
name: Run ConfigurationHandler
expected_stdout_lines:
- '== APP == Configuration update received for store: configstore'
- '== APP == Key: myconfig2 Value :updated_val2'
background: true
output_match_mode: substring
background: true
sleep: 5
-->
```bash
dapr run --app-id confighandler -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.configuration.http.ConfigurationHandler -p 3009
```
<!-- END_STEP -->
#### Running the ConfigurationClient app:
Use the following command to run this example-
<!-- STEP
name: Run ConfigurationClient example
expected_stdout_lines:
- "== 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"
background: true
output_match_mode: substring
sleep: 10
-->
```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
<!-- END_STEP -->
<!-- STEP
name: Update configuration value
timeout_seconds: 20
-->
```bash
docker exec dapr_redis redis-cli MSET myconfig2 "updated_val2||1"
```
<!-- END_STEP -->
### 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):
<!-- STEP
name: Cleanup
-->
```bash
dapr stop --app-id confighttp
dapr stop --app-id confighandler
```
<!-- END_STEP -->

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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);
}
}
///...

View File

@ -11,7 +11,7 @@
limitations under the License.
*/
package io.dapr.examples.lock.grpc;
package io.dapr.examples.lock;
import io.dapr.client.DaprClientBuilder;

View File

@ -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
```
<!-- END_STEP -->

View File

@ -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<Boolean> 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<UnlockResponseStatus> result = client.unlock(unlockRequest);
System.out.println("Unlock result ->" + result.block().name());
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}

View File

@ -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
```
<!-- END_STEP -->
### Running the example
Get into the examples' directory:
```sh
cd examples
```
Use the following command to run this example-
<!-- STEP
name: Run DistributedLockHttpClient example
expected_stdout_lines:
- "== 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"
background: true
sleep: 5
-->
```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
```
<!-- END_STEP -->
### 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):
<!-- STEP
name: Cleanup
-->
```bash
dapr stop --app-id lockhttp
```
<!-- END_STEP -->

View File

@ -36,6 +36,20 @@ cd examples
Run `dapr init` to initialize Dapr in Self-Hosted Mode if it's not already initialized.
### Run MongoDB
<!-- STEP
name: Setup mongo container
sleep: 5
-->
```bash
docker-compose -f ./src/main/java/io/dapr/examples/querystate/docker-compose-single-mongo.yml up -d
```
<!-- END_STEP -->
### 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
```
<!-- END_STEP -->
Then, stop MongoDB container.
<!-- STEP
name: Cleanup MongoDB containers
-->
```bash
docker-compose -f ./src/main/java/io/dapr/examples/querystate/docker-compose-single-mongo.yml down
```
<!-- END_STEP -->

View File

@ -0,0 +1,6 @@
version: '3'
services:
mongo:
image: mongo
ports:
- "27017:27017"

View File

@ -36,6 +36,19 @@ cd examples
Run `dapr init` to initialize Dapr in Self-Hosted Mode if it's not already initialized.
### Run MongoDB
<!-- STEP
name: Setup mongo container
sleep: 5
-->
```bash
docker-compose -f ./src/main/java/io/dapr/examples/state/docker-compose-single-mongo.yml up -d
```
<!-- END_STEP -->
### 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
```
<!-- END_STEP -->
Then, stop MongoDB container.
<!-- STEP
name: Cleanup MongoDB container
-->
```bash
docker-compose -f ./src/main/java/io/dapr/examples/state/docker-compose-single-mongo.yml down
```
<!-- END_STEP -->

View File

@ -0,0 +1,6 @@
version: '3'
services:
mongo:
image: mongo
ports:
- "27017:27017"

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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.<DaprProtos.InvokeActorResponse>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 <T> Mono<T> createMono(Consumer<StreamObserver<T>> consumer) {

View File

@ -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<byte[]> invoke(String actorType, String actorId, String methodName, byte[] jsonPayload) {
String[] pathSegments = new String[] { DaprHttp.API_VERSION, "actors", actorType, actorId, "method", methodName };
Mono<DaprHttp.Response> responseMono =
this.client.invokeApi(DaprHttp.HttpMethods.POST.name(), pathSegments, null, jsonPayload, null, null);
return responseMono.map(r -> r.getBody());
}
}

View File

@ -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.");

View File

@ -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 {

View File

@ -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

View File

@ -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<byte[]> 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<byte[]> 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<byte[]> mono =
DaprHttpClient.invoke("DemoActor", "1", "Payment", "".getBytes());
assertThrowsDaprException(
"ERR_SOMETHING",
"ERR_SOMETHING: error message",
() -> mono.block());
}
}

View File

@ -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;

View File

@ -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 {

View File

@ -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 {

View File

@ -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.

View File

@ -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;

View File

@ -26,7 +26,3 @@ services:
image: mongo
ports:
- "27017:27017"
redis:
image: redis
ports:
- "6379:6379"

View File

@ -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;
}
}

View File

@ -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<AppRun, DaprRun> 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<AppRun, DaprRun> 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<ActorClient> 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);
}
}
}

View File

@ -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<DaprPorts> 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);

View File

@ -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 {

View File

@ -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();

View File

@ -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<Arguments> 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<ActorProxy> 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);

View File

@ -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.

View File

@ -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<T> extends AbstractActor implements MyActor, Remindable<T> {

View File

@ -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()) {

View File

@ -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(() -> {

View File

@ -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) {

View File

@ -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<Void> handleMessage(
@PathVariable Map<String, String> pathVarsMap,
@RequestBody SubscribeConfigurationResponse obj) {
return Mono.fromRunnable(
() -> {
try {
Map<String, ConfigurationItem> items = obj.getItems();
for (Map.Entry<String, ConfigurationItem> 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() {
}
}

View File

@ -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<String> 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<String, ConfigurationItem> 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();
}
}
}

View File

@ -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<String> 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<String> subId= new AtomicReference<>("");
Flux<SubscribeConfigurationResponse> 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();
}
}
}

View File

@ -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));
}
}

View File

@ -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<Integer, String> messages = client.invokeMethod(
daprRun.getAppName(),
"getMessages",
GetMessagesRequest.newBuilder().build(),
HttpExtension.POST, GetMessagesResponse.class).block().getMessagesMap();
Map<Integer, String> 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());
}
}
}

View File

@ -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<Integer, String> 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<CommonProtos.InvokeResponse> 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<io.dapr.it.MethodInvokeServiceProtos.PostMessageResponse> 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<io.dapr.it.MethodInvokeServiceProtos.DeleteMessageResponse> 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<io.dapr.it.MethodInvokeServiceProtos.GetMessagesResponse> 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<io.dapr.it.MethodInvokeServiceProtos.SleepResponse> 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) {

View File

@ -40,7 +40,6 @@ public class MethodInvokeIT extends BaseIT {
MethodInvokeService.class,
true,
30000);
daprRun.switchToHTTP();
daprRun.waitForAppHealth(20000);
}

View File

@ -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<ConvertToLong> values = new HashSet<>();

View File

@ -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;

View File

@ -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

View File

@ -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<String, String> 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<String, Map<String, String>> 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());
}

View File

@ -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();
}

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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");

View File

@ -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

View File

@ -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);

View File

@ -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 {

View File

@ -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
}

View File

@ -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<UnsubscribeConfigurationResponse> 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 <T> the generic type of the service to be invoked.
*/
<T extends AbstractStub<T>> T newGrpcStub(String appId, Function<Channel, T> stubBuilder);
/**
* Gracefully shutdown the dapr runtime.
*

View File

@ -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);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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 extends AbstractStub<T>> T newGrpcStub(String appId, Function<Channel, T> stubBuilder) {
// Adds Dapr interceptors to populate gRPC metadata automatically.
return DaprClientGrpcInterceptors.intercept(appId, stubBuilder.apply(this.channel.getGrpcChannel()), timeoutPolicy);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> 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<DaprHttp.Response> 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 <T> Mono<T> invokeMethod(InvokeMethodRequest invokeMethodRequest, TypeRef<T> 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<String, String> metadata = invokeMethodRequest.getMetadata();
return Mono.deferContextual(
context -> this.<CommonProtos.InvokeResponse>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<String> pathSegments = new ArrayList<>(Arrays.asList(DaprHttp.API_VERSION, "invoke", appId, "method"));
pathSegments.addAll(Arrays.asList(methodSegments));
final Map<String, String> 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<DaprHttp.Response> 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 <T> Mono<T> getMonoForHttpResponse(TypeRef<T> 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 <K> 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 <K> 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.<DaprProtos.SubscribeConfigurationResponse>createFlux(
it -> intercept(asyncStub).subscribeConfiguration(envelope, it)
it -> intercept(null, asyncStub).subscribeConfiguration(envelope, it)
).map(
it -> {
Map<String, ConfigurationItem> configMap = new HashMap<>();
@ -1094,7 +1148,7 @@ public class DaprClientGrpc extends AbstractDaprClient {
DaprProtos.UnsubscribeConfigurationRequest envelope = builder.build();
return this.<DaprProtos.UnsubscribeConfigurationResponse>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 <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> methodDescriptor,
CallOptions options,
Channel channel) {
ClientCall<ReqT, RespT> clientCall = channel.newCall(methodDescriptor, timeoutPolicy.apply(options));
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(clientCall) {
@Override
public void start(final Listener<RespT> 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 <T> Mono<T> createMono(Consumer<StreamObserver<T>> consumer) {

View File

@ -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<Void> waitForSidecar(int timeoutInMilliseconds) {
return client.waitForSidecar(timeoutInMilliseconds);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> publishEvent(String pubsubName, String topicName, Object data) {
return client.publishEvent(pubsubName, topicName, data);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> publishEvent(String pubsubName, String topicName, Object data, Map<String, String> metadata) {
return client.publishEvent(pubsubName, topicName, data, metadata);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> publishEvent(PublishEventRequest request) {
return client.publishEvent(request);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<T> invokeMethod(String appId,
String methodName,
Object data,
HttpExtension httpExtension,
Map<String, String> metadata,
TypeRef<T> type) {
return methodInvocationOverrideClient.invokeMethod(appId, methodName, data, httpExtension, metadata, type);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<T> invokeMethod(String appId,
String methodName,
Object request,
HttpExtension httpExtension,
Map<String, String> metadata,
Class<T> clazz) {
return methodInvocationOverrideClient.invokeMethod(appId, methodName, request, httpExtension, metadata, clazz);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<T> invokeMethod(String appId,
String methodName,
Object request,
HttpExtension httpExtension,
TypeRef<T> type) {
return methodInvocationOverrideClient.invokeMethod(appId, methodName, request, httpExtension, type);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<T> invokeMethod(String appId,
String methodName,
Object request,
HttpExtension httpExtension,
Class<T> clazz) {
return methodInvocationOverrideClient.invokeMethod(appId, methodName, request, httpExtension, clazz);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<T> invokeMethod(String appId,
String methodName,
HttpExtension httpExtension,
Map<String, String> metadata,
TypeRef<T> type) {
return methodInvocationOverrideClient.invokeMethod(appId, methodName, httpExtension, metadata, type);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<T> invokeMethod(String appId,
String methodName,
HttpExtension httpExtension,
Map<String, String> metadata,
Class<T> clazz) {
return methodInvocationOverrideClient.invokeMethod(appId, methodName, httpExtension, metadata, clazz);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> invokeMethod(String appId,
String methodName,
Object request,
HttpExtension httpExtension,
Map<String, String> metadata) {
return methodInvocationOverrideClient.invokeMethod(appId, methodName, request, httpExtension, metadata);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension) {
return methodInvocationOverrideClient.invokeMethod(appId, methodName, request, httpExtension);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> invokeMethod(String appId,
String methodName,
HttpExtension httpExtension,
Map<String, String> metadata) {
return methodInvocationOverrideClient.invokeMethod(appId, methodName, httpExtension, metadata);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<byte[]> invokeMethod(String appId,
String methodName,
byte[] request,
HttpExtension httpExtension,
Map<String, String> metadata) {
return methodInvocationOverrideClient.invokeMethod(appId, methodName, request, httpExtension, metadata);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<T> invokeMethod(InvokeMethodRequest invokeMethodRequest, TypeRef<T> type) {
return methodInvocationOverrideClient.invokeMethod(invokeMethodRequest, type);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> invokeBinding(String bindingName, String operation, Object data) {
return client.invokeBinding(bindingName, operation, data);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<byte[]> invokeBinding(String bindingName, String operation, byte[] data, Map<String, String> metadata) {
return client.invokeBinding(bindingName, operation, data, metadata);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<T> invokeBinding(String bindingName, String operation, Object data, TypeRef<T> type) {
return client.invokeBinding(bindingName, operation, data, type);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<T> invokeBinding(String bindingName, String operation, Object data, Class<T> clazz) {
return client.invokeBinding(bindingName, operation, data, clazz);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<T> invokeBinding(String bindingName,
String operation,
Object data,
Map<String, String> metadata,
TypeRef<T> type) {
return client.invokeBinding(bindingName, operation, data, metadata, type);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<T> invokeBinding(String bindingName,
String operation,
Object data,
Map<String, String> metadata,
Class<T> clazz) {
return client.invokeBinding(bindingName, operation, data, metadata, clazz);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<T> invokeBinding(InvokeBindingRequest request, TypeRef<T> type) {
return client.invokeBinding(request, type);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<State<T>> getState(String storeName, State<T> state, TypeRef<T> type) {
return client.getState(storeName, state, type);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<State<T>> getState(String storeName, State<T> state, Class<T> clazz) {
return client.getState(storeName, state, clazz);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<State<T>> getState(String storeName, String key, TypeRef<T> type) {
return client.getState(storeName, key, type);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<State<T>> getState(String storeName, String key, Class<T> clazz) {
return client.getState(storeName, key, clazz);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<State<T>> getState(String storeName, String key, StateOptions options, TypeRef<T> type) {
return client.getState(storeName, key, options, type);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<State<T>> getState(String storeName, String key, StateOptions options, Class<T> clazz) {
return client.getState(storeName, key, options, clazz);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<State<T>> getState(GetStateRequest request, TypeRef<T> type) {
return client.getState(request, type);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<List<State<T>>> getBulkState(String storeName, List<String> keys, TypeRef<T> type) {
return client.getBulkState(storeName, keys, type);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<List<State<T>>> getBulkState(String storeName, List<String> keys, Class<T> clazz) {
return client.getBulkState(storeName, keys, clazz);
}
/**
* {@inheritDoc}
*/
@Override
public <T> Mono<List<State<T>>> getBulkState(GetBulkStateRequest request, TypeRef<T> type) {
return client.getBulkState(request, type);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> executeStateTransaction(String storeName, List<TransactionalStateOperation<?>> operations) {
return client.executeStateTransaction(storeName, operations);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> executeStateTransaction(ExecuteStateTransactionRequest request) {
return client.executeStateTransaction(request);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> saveBulkState(String storeName, List<State<?>> states) {
return client.saveBulkState(storeName, states);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> saveBulkState(SaveStateRequest request) {
return client.saveBulkState(request);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> saveState(String storeName, String key, Object value) {
return client.saveState(storeName, key, value);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> saveState(String storeName, String key, String etag, Object value, StateOptions options) {
return client.saveState(storeName, key, etag, value, options);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> deleteState(String storeName, String key) {
return client.deleteState(storeName, key);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> deleteState(String storeName, String key, String etag, StateOptions options) {
return client.deleteState(storeName, key, etag, options);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Void> deleteState(DeleteStateRequest request) {
return client.deleteState(request);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Map<String, String>> getSecret(String storeName, String secretName, Map<String, String> metadata) {
return client.getSecret(storeName, secretName, metadata);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Map<String, String>> getSecret(String storeName, String secretName) {
return client.getSecret(storeName, secretName);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Map<String, String>> getSecret(GetSecretRequest request) {
return client.getSecret(request);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Map<String, Map<String, String>>> getBulkSecret(String storeName) {
return client.getBulkSecret(storeName);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Map<String, Map<String, String>>> getBulkSecret(String storeName, Map<String, String> metadata) {
return client.getBulkSecret(storeName, metadata);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Map<String, Map<String, String>>> getBulkSecret(GetBulkSecretRequest request) {
return client.getBulkSecret(request);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<ConfigurationItem> getConfiguration(String storeName, String key) {
return client.getConfiguration(storeName, key);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<ConfigurationItem> getConfiguration(String storeName, String key, Map<String, String> metadata) {
return client.getConfiguration(storeName, key, metadata);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Map<String, ConfigurationItem>> getConfiguration(String storeName, String... keys) {
return client.getConfiguration(storeName, keys);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Map<String, ConfigurationItem>> getConfiguration(String storeName, List<String> keys,
Map<String, String> metadata) {
return client.getConfiguration(storeName, keys, metadata);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<Map<String, ConfigurationItem>> getConfiguration(GetConfigurationRequest request) {
return client.getConfiguration(request);
}
/**
* {@inheritDoc}
*/
@Override
public Flux<SubscribeConfigurationResponse> subscribeConfiguration(String storeName, String... keys) {
return client.subscribeConfiguration(storeName, keys);
}
/**
* {@inheritDoc}
*/
@Override
public Flux<SubscribeConfigurationResponse> subscribeConfiguration(String storeName, List<String> keys,
Map<String, String> metadata) {
return client.subscribeConfiguration(storeName, keys, metadata);
}
/**
* {@inheritDoc}
*/
@Override
public Flux<SubscribeConfigurationResponse> subscribeConfiguration(SubscribeConfigurationRequest request) {
return client.subscribeConfiguration(request);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<UnsubscribeConfigurationResponse> unsubscribeConfiguration(String id, String storeName) {
return client.unsubscribeConfiguration(id, storeName);
}
/**
* {@inheritDoc}
*/
@Override
public Mono<UnsubscribeConfigurationResponse> 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<Void> shutdown() {
return client.shutdown();
}
}

View File

@ -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 {
/**

View File

@ -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 <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> methodDescriptor,
CallOptions callOptions,
Channel channel) {
return this.delegate.interceptCall(methodDescriptor, callOptions, channel);
}
}

View File

@ -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<Void> 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<DaprHttp.Response> 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();
}
}

View File

@ -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;

View File

@ -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;
/**

View File

@ -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<DaprApiProtocol> 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<DaprApiProtocol> 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.
*/

View File

@ -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 <T> async client type
* @return async client instance with interceptors
*/
public static <T extends AbstractStub<T>> 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 <T> async client type
* @return async client instance with interceptors
*/
public static <T extends AbstractStub<T>> 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 <T> async client type
* @return async client instance with interceptors
*/
public static <T extends AbstractStub<T>> 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 <T> async client type
* @return async client instance with interceptors
*/
public static <T extends AbstractStub<T>> 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 <T> async client type
* @return async client instance with interceptors
*/
public static <T extends AbstractStub<T>> 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 <T> async client type
* @return async client instance with interceptors
*/
public static <T extends AbstractStub<T>> 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 <T> async client type
* @return async client instance with interceptors
*/
public static <T extends AbstractStub<T>> 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 <T> async client type
* @return async client instance with interceptors
*/
public static <T extends AbstractStub<T>> 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));
}
}

View File

@ -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 <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> methodDescriptor,
CallOptions options,
Channel channel) {
ClientCall<ReqT, RespT> clientCall = channel.newCall(methodDescriptor, options);
return new ForwardingClientCall.SimpleForwardingClientCall<>(clientCall) {
@Override
public void start(final Listener<RespT> 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);
}
};
}
}

View File

@ -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 <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> methodDescriptor,
CallOptions options,
Channel channel) {
ClientCall<ReqT, RespT> clientCall = channel.newCall(methodDescriptor, options);
final Metadata extraHeaders = this.extraHeaders;
return new ForwardingClientCall.SimpleForwardingClientCall<>(clientCall) {
@Override
public void start(ClientCall.Listener<RespT> responseListener, Metadata headers) {
if (extraHeaders != null) {
headers.merge(extraHeaders);
}
super.start(responseListener, headers);
}
};
}
}

View File

@ -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 <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> methodDescriptor,
CallOptions options,
Channel channel) {
if (timeoutPolicy == null) {
return channel.newCall(methodDescriptor, options);
}
return channel.newCall(methodDescriptor, timeoutPolicy.apply(options));
}
}

View File

@ -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 <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> methodDescriptor,
CallOptions callOptions,
Channel channel) {
ClientCall<ReqT, RespT> clientCall = channel.newCall(methodDescriptor, callOptions);
return new ForwardingClientCall.SimpleForwardingClientCall<>(clientCall) {
@Override
public void start(final Listener<RespT> responseListener, final Metadata metadata) {
if (context != null) {
GrpcHelper.populateMetadata(context, metadata);
}
super.start(responseListener, metadata);
}
};
}
}

View File

@ -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<byte[]> GRPC_TRACE_BIN_KEY =
Metadata.Key.of("grpc-trace-bin", Metadata.BINARY_BYTE_MARSHALLER);
private static final Metadata.Key<String> TRACEPARENT_KEY =
Metadata.Key.of("traceparent", Metadata.ASCII_STRING_MARSHALLER);
private static final Metadata.Key<String> 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<String, Object> 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;
}
}
}

View File

@ -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<byte[]> GRPC_TRACE_BIN_KEY =
Metadata.Key.of("grpc-trace-bin", Metadata.BINARY_BYTE_MARSHALLER);
private static final Metadata.Key<String> TRACEPARENT_KEY =
Metadata.Key.of("traceparent", Metadata.ASCII_STRING_MARSHALLER);
private static final Metadata.Key<String> 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 <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> methodDescriptor,
CallOptions callOptions,
Channel channel) {
ClientCall<ReqT, RespT> clientCall = channel.newCall(methodDescriptor, callOptions);
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(clientCall) {
@Override
public void start(final Listener<RespT> responseListener, final Metadata metadata) {
Map<String, Object> 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;
}
}
}

View File

@ -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;

View File

@ -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<T> extends CloudEvent<T> {

View File

@ -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();

View File

@ -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;

View File

@ -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<Void> result = this.client.invokeMethod(req, TypeRef.get(Void.class))
Mono<Void> 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<Void> result = this.client.invokeMethod(req, TypeRef.get(Void.class))
Mono<Void> result = this.invoke()
.contextWrite(it -> it.putAll(contextCopy == null ? (ContextView) Context.empty() : contextCopy));
result.block();
}
private Mono<Void> invoke() {
DaprProtos.InvokeServiceRequest req =
DaprProtos.InvokeServiceRequest.newBuilder()
.build();
return Mono.deferContextual(
context -> this.<CommonProtos.InvokeResponse>createMono(
it -> DaprClientGrpcInterceptors.intercept(daprStub, context).invokeService(req, it)
)
).then();
}
private <T> Mono<T> createMono(Consumer<StreamObserver<T>> consumer) {
return Mono.create(sink -> consumer.accept(createStreamObserver(sink)));
}
private <T> StreamObserver<T> createStreamObserver(MonoSink<T> sink) {
return new StreamObserver<T>() {
@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();
}
};
}
}

View File

@ -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<Void>) 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<Void>) invocation -> {
StreamObserver<Empty> observer = (StreamObserver<Empty>) 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<Void>) invocation -> {
StreamObserver<Empty> observer = (StreamObserver<Empty>) invocation.getArguments()[1];
observer.onNext(Empty.getDefaultInstance());
@ -419,440 +410,6 @@ public class DaprClientGrpcTest {
assertFalse(called.get());
}
@Test
public void invokeServiceVoidExceptionThrownTest() {
doAnswer((Answer<Void>) invocation -> {
throw new RuntimeException();
}).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any());
Mono<Void> result = client.invokeMethod("appId", "method", "request", HttpExtension.NONE);
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test
public void invokeServiceIllegalArgumentExceptionThrownTest() {
doAnswer((Answer<Void>) invocation -> {
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) 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<Void> result = client.invokeMethod("appId", "method", "request", null);
assertThrows(IllegalArgumentException.class, () -> result.block());
}
@Test
public void invokeServiceEmptyRequestVoidExceptionThrownTest() {
doAnswer((Answer<Void>) invocation -> {
throw new RuntimeException();
}).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any());
Mono<Void> result = client.invokeMethod("appId", "method", HttpExtension.NONE, (Map<String, String>)null);
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test
public void invokeServiceVoidCallbackExceptionThrownTest() {
RuntimeException ex = new RuntimeException("An Exception");
doAnswer((Answer<Void>) invocation -> {
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) invocation.getArguments()[1];
observer.onError(ex);
return null;
}).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any());
Mono<Void> 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<Void>) invocation -> {
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) 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<Void> result = client.invokeMethod("appId", "method", "request", HttpExtension.NONE);
result.block();
}
@Test
public void invokeServiceVoidObjectTest() {
doAnswer((Answer<Void>) invocation -> {
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) 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<Void> result = client.invokeMethod("appId", "method", request, HttpExtension.NONE);
result.block();
}
@Test
public void invokeServiceExceptionThrownTest() {
doAnswer((Answer<Void>) invocation -> {
throw new RuntimeException();
}).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any());
Mono<String> result = client.invokeMethod("appId", "method", "request", HttpExtension.NONE, null, String.class);
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test
public void invokeServiceNoRequestClassExceptionThrownTest() {
doAnswer((Answer<Void>) invocation -> {
throw new RuntimeException();
}).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any());
Mono<String> result = client.invokeMethod("appId", "method", HttpExtension.NONE, (Map<String, String>)null, String.class);
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test
public void invokeServiceNoRequestTypeRefExceptionThrownTest() {
doAnswer((Answer<Void>) invocation -> {
throw new RuntimeException();
}).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any());
Mono<String> result = client.invokeMethod("appId", "method", HttpExtension.NONE, (Map<String, String>)null, TypeRef.STRING);
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test
public void invokeServiceCallbackExceptionThrownTest() {
RuntimeException ex = new RuntimeException("An Exception");
doAnswer((Answer<Void>) invocation -> {
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) invocation.getArguments()[1];
observer.onError(ex);
return null;
}).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any());
Mono<String> 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<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) invocation.getArguments()[1];
observer.onNext(CommonProtos.InvokeResponse.newBuilder().setData(getAny(expected)).build());
observer.onCompleted();
return null;
}).when(daprStub).invokeService(eq(request), any());
Mono<String> 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<Void>) invocation -> {
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) 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<String> 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<Void>) invocation -> {
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) 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<MyObject> 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<Void>) invocation -> {
throw new RuntimeException();
}).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any());
Mono<String> 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<Void>) invocation -> {
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) invocation.getArguments()[1];
observer.onError(ex);
return null;
}).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any());
Mono<String> 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<Void>) invocation -> {
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) 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<String> 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<Void>) invocation -> {
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) 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<MyObject> 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<Void>) invocation -> {
throw new RuntimeException();
}).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any());
String request = "Request";
byte[] byteRequest = serializer.serialize(request);
Mono<byte[]> 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<Void>) invocation -> {
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) 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<byte[]> result =
client.invokeMethod("appId", "method", byteRequest, HttpExtension.NONE,(HashMap<String, String>) null);
assertThrowsDaprException(
ExecutionException.class,
"UNKNOWN",
"UNKNOWN: java.lang.RuntimeException: An Exception",
() -> result.block());
}
@Test
public void invokeByteRequestServiceTest() throws Exception {
String expected = "Value";
doAnswer((Answer<Void>) invocation -> {
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) 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<byte[]> result = client.invokeMethod(
"appId", "method", byteRequest, HttpExtension.NONE, (HashMap<String, String>) 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<Void>) invocation -> {
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) 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<byte[]> 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<Void>) invocation -> {
throw new RuntimeException();
}).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any());
Mono<Void> 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<Void>) invocation -> {
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) invocation.getArguments()[1];
observer.onError(ex);
return null;
}).when(daprStub).invokeService(any(DaprProtos.InvokeServiceRequest.class), any());
Mono<Void> 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<Void>) invocation -> {
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) 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<Void> 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<Void>) invocation -> {
called.set(true);
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) 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<Void>) invocation -> {
StreamObserver<CommonProtos.InvokeResponse> observer = (StreamObserver<CommonProtos.InvokeResponse>) 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<Void> result = client.invokeMethod("appId", "method", (Object)null, HttpExtension.NONE);
result.block();
}
@Test
public void getStateIllegalArgumentExceptionTest() {
State<String> 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";

File diff suppressed because it is too large Load Diff

View File

@ -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();
}
}

View File

@ -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());
}
}

View File

@ -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();
}

View File

@ -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;

View File

@ -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<Void>) invocation -> {
StreamObserver<DaprProtos.BulkPublishResponse> observer =
(StreamObserver<DaprProtos.BulkPublishResponse>) invocation.getArguments()[1];

View File

@ -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<String> 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<Boolean> 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<UnlockResponseStatus> mono = daprPreviewClientHttp.unlock(unLockRequest);
assertEquals(UnlockResponseStatus.SUCCESS, mono.block());
}
}

View File

@ -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();
}
}

Some files were not shown because too many files have changed in this diff Show More