Throw DaprException consistently + doc + example. (#403)

This commit is contained in:
Artur Souza 2020-12-08 15:58:07 -08:00 committed by GitHub
parent 16faa43795
commit adce91f743
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 1210 additions and 357 deletions

View File

@ -26,7 +26,7 @@ jobs:
DAPR_RUNTIME_VER: 1.0.0-rc.1
DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/a60221e96406a145ab22e454eec6642961725f5c/install/install.sh
DAPR_CLI_REF:
DAPR_REF: 83f5c45362b0c577139b1887276d7cf1b7308506
DAPR_REF: 79688c8ce802b3b31382da97422db63a27821599
OSSRH_USER_TOKEN: ${{ secrets.OSSRH_USER_TOKEN }}
OSSRH_PWD_TOKEN: ${{ secrets.OSSRH_PWD_TOKEN }}
GPG_KEY: ${{ secrets.GPG_KEY }}

View File

@ -144,6 +144,7 @@ Try the following examples to learn more about Dapr's Java SDK:
* [Actors over Http](./examples/src/main/java/io/dapr/examples/actors/http)
* [Secrets management](./examples/src/main/java/io/dapr/examples/secrets)
* [Distributed tracing with OpenTelemetry SDK](./examples/src/main/java/io/dapr/examples/tracing)
* [Exception handling](./examples/src/main/java/io/dapr/examples/exception)
#### API Documentation
@ -221,30 +222,12 @@ Now you can go to your IDE (like Eclipse, for example) and debug your Java appli
Calls to Dapr's APIs on `http://127.0.0.1:3500/*` should work now and trigger breakpoints in your code.
#### Creating and publishing the artifacts to Nexus Repository
In case you need to publish Dapr's SDK to a private Nexus repo, run the command below from the project's root directory:
#### Exception handling
```sh
mvn package
mvn deploy:deploy-file -DgeneratePom=false -DrepositoryId=nexus -Durl=http://localhost:8081/repository/maven-releases -DpomFile=pom.xml -Dfile=target/dapr-sdk-0.3.0.jar
```
For more documentation reference:
https://maven.apache.org/plugins/maven-deploy-plugin
https://help.sonatype.com/repomanager3/user-interface/uploading-components
All exceptions thrown from the SDK are instances of `DaprException`. `DaprException` extends from `RuntimeException`, making it compatible with Project Reactor. See [example](./examples/src/main/java/io/dapr/examples/exception) for more details.
### Development
#### Maven Module version management
When releasing a new version of this SDK you must increase the version of all modules and pom files, so run the following commands:
```sh
mvn versions:set -DnewVersion="0.1.0-preview02"
mvn versions:commit
```
#### Update proto files
Change the properties below in [pom.xml](./pom.xml) to point to the desired reference URL in Git. Avoid pointing to master branch since it can change over time and create unpredictable behavior in the build.

View File

@ -8,8 +8,6 @@ package io.dapr.examples.bindings.http;
import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;
import java.io.IOException;
/**
* Service for output binding example.
* 1. From your repo root, build and install jars:
@ -38,7 +36,7 @@ public class OutputBindingExample {
* @param args Not used.
*/
@SuppressWarnings("checkstyle:AbbreviationAsWordInName")
public static void main(String[] args) throws IOException {
public static void main(String[] args) throws Exception {
try (DaprClient client = new DaprClientBuilder().build()) {
int count = 0;

View File

@ -109,7 +109,7 @@ public class OutputBindingExample{
static final String BINDING_OPERATION = "create";
///...
public static void main(String[] args) throws IOException {
public static void main(String[] args) throws Exception {
try (DaprClient client = new DaprClientBuilder().build()) {
int count = 0;

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*/
package io.dapr.examples.exception;
import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;
import io.dapr.exceptions.DaprException;
/**
* 1. Build and install jars:
* mvn clean install
* 2. Go into examples:
* cd examples
* 3. send a message to be saved as state:
* dapr run --components-path ./components --dapr-http-port 3006 -- \
* java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.exception.Client
*/
public class Client {
/**
* Executes the sate actions.
* @param args messages to be sent as state value.
*/
public static void main(String[] args) throws Exception {
try (DaprClient client = new DaprClientBuilder().build()) {
try {
client.getState("Unknown state store", "myKey", String.class).block();
} catch (DaprException exception) {
System.out.println("Error code: " + exception.getErrorCode());
System.out.println("Error message: " + exception.getMessage());
exception.printStackTrace();
}
System.out.println("Done");
}
}
}

View File

@ -0,0 +1,68 @@
## Exception handling sample
This sample illustrates how to handle exceptions in Dapr.
## Pre-requisites
* [Dapr and Dapr Cli](https://docs.dapr.io/getting-started/install-dapr/).
* Java JDK 11 (or greater): [Oracle JDK](https://www.oracle.com/technetwork/java/javase/downloads/index.html#JDK11) or [OpenJDK](https://jdk.java.net/13/).
* [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
```
### Running the StateClient
This example uses the Java SDK Dapr client in order perform an invalid operartion, causing Dapr runtime to return an error. See the code snippet bellow:
```java
public class Client {
public static void main(String[] args) throws Exception {
try (DaprClient client = new DaprClientBuilder().build()) {
try {
client.getState("Unknown state store", "myKey", String.class).block();
} catch (DaprException exception) {
System.out.println("Error code: " + exception.getErrorCode());
System.out.println("Error message: " + exception.getMessage());
exception.printStackTrace();
}
System.out.println("Done");
}
}
}
```
The code uses the `DaprClient` created by the `DaprClientBuilder`. It tries to get a state from state store but provides an unknown state store. It causes Dapr sidecar to return error, which is converted to a `DaprException` to the application. To be compatible with Project Reactor, `DaprException` extends from `RuntimeException` - making it an unchecked exception.
The Dapr client is also within a try-with-resource block to properly close the client at the end.
### Running the example
Run this example with the following command:
```sh
dapr run --components-path ./components --dapr-http-port 3006 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.exception.Client
```
Once running, the OutputBindingExample should print the output as follows:
![stateouput](../../../../../resources/img/exception.png)

View File

@ -9,8 +9,6 @@ import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;
import io.dapr.client.domain.HttpExtension;
import java.io.IOException;
/**
* 1. Build and install jars:
* mvn clean install
@ -25,7 +23,7 @@ public class HelloWorldClient {
*
* @param args Array of messages to be sent.
*/
public static void main(String[] args) throws InterruptedException, IOException {
public static void main(String[] args) throws Exception {
try (DaprClient client = new DaprClientBuilder().build()) {
String serviceAppId = "hellogrpc";

View File

@ -86,7 +86,7 @@ The other component is the client. It will send one message per second to the se
```java
private static class HelloWorldClient {
///...
public static void main(String[] args) {
public static void main(String[] args) throws Exception {
try (DaprClient client = new DaprClientBuilder().build()) {
String serviceAppId = "hellogrpc";

View File

@ -9,8 +9,6 @@ import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;
import io.dapr.client.domain.HttpExtension;
import java.io.IOException;
/**
* 1. Build and install jars:
* mvn clean install
@ -31,7 +29,7 @@ public class InvokeClient {
*
* @param args Messages to be sent as request for the invoke API.
*/
public static void main(String[] args) throws IOException {
public static void main(String[] args) throws Exception {
try (DaprClient client = (new DaprClientBuilder()).build()) {
for (String message : args) {
byte[] response = client.invokeService(SERVICE_APP_ID, "say", message, HttpExtension.POST, null,

View File

@ -110,7 +110,7 @@ public class InvokeClient {
private static final String SERVICE_APP_ID = "invokedemo";
///...
public static void main(String[] args) throws IOException {
public static void main(String[] args) throws Exception {
try (DaprClient client = (new DaprClientBuilder()).build()) {
for (String message : args) {
byte[] response = client.invokeService(SERVICE_APP_ID, "say", message, HttpExtension.POST, null,

View File

@ -41,7 +41,7 @@ public class StateClient {
private static final String SECOND_KEY_NAME = "myKey2";
///...
public static void main(String[] args) throws IOException {
public static void main(String[] args) throws Exception {
try (DaprClient client = new DaprClientBuilder().build()) {
String message = args.length == 0 ? " " : args[0];

View File

@ -11,7 +11,6 @@ import io.dapr.client.domain.State;
import io.dapr.client.domain.TransactionalStateOperation;
import reactor.core.publisher.Mono;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -45,7 +44,7 @@ public class StateClient {
* Executes the sate actions.
* @param args messages to be sent as state value.
*/
public static void main(String[] args) throws IOException {
public static void main(String[] args) throws Exception {
try (DaprClient client = new DaprClientBuilder().build()) {
String message = args.length == 0 ? " " : args[0];

View File

@ -18,8 +18,6 @@ import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import java.io.IOException;
/**
* 1. Build and install jars:
* mvn clean install
@ -40,7 +38,7 @@ public class InvokeClient {
*
* @param args Messages to be sent as request for the invoke API.
*/
public static void main(String[] args) throws IOException {
public static void main(String[] args) throws Exception {
Tracer tracer = OpenTelemetryConfig.createTracer(InvokeClient.class.getCanonicalName());
Span span = tracer.spanBuilder("Example's Main").setSpanKind(Span.Kind.CLIENT).startSpan();

View File

@ -140,7 +140,7 @@ public class InvokeClient {
private static final String SERVICE_APP_ID = "invokedemo";
///...
public static void main(String[] args) throws IOException {
public static void main(String[] args) throws Exception {
Tracer tracer = OpenTelemetryConfig.createTracer(InvokeClient.class.getCanonicalName());
Span span = tracer.spanBuilder("Example's Main").setSpanKind(Span.Kind.CLIENT).startSpan();

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

View File

@ -18,6 +18,8 @@ import io.grpc.ManagedChannelBuilder;
import java.io.Closeable;
import java.lang.reflect.Proxy;
import static io.dapr.exceptions.DaprException.throwIllegalArgumentException;
/**
* Builder to generate an ActorProxy instance. Builder can be reused for multiple instances.
*/
@ -74,10 +76,10 @@ public class ActorProxyBuilder<T> implements Closeable {
*/
public ActorProxyBuilder(String actorType, Class<T> actorTypeClass) {
if ((actorType == null) || actorType.isEmpty()) {
throw new IllegalArgumentException("ActorType is required.");
throwIllegalArgumentException("ActorType is required.");
}
if (actorTypeClass == null) {
throw new IllegalArgumentException("ActorTypeClass is required.");
throwIllegalArgumentException("ActorTypeClass is required.");
}
this.useGrpc = Properties.USE_GRPC.get();
@ -96,7 +98,7 @@ public class ActorProxyBuilder<T> implements Closeable {
*/
public ActorProxyBuilder<T> withObjectSerializer(DaprObjectSerializer objectSerializer) {
if (objectSerializer == null) {
throw new IllegalArgumentException("Serializer is required.");
throwIllegalArgumentException("Serializer is required.");
}
this.objectSerializer = objectSerializer;
@ -111,7 +113,7 @@ public class ActorProxyBuilder<T> implements Closeable {
*/
public T build(ActorId actorId) {
if (actorId == null) {
throw new IllegalArgumentException("Cannot instantiate an Actor without Id.");
throwIllegalArgumentException("Cannot instantiate an Actor without Id.");
}
ActorProxyImpl proxy = new ActorProxyImpl(
@ -167,7 +169,7 @@ public class ActorProxyBuilder<T> implements Closeable {
int port = Properties.GRPC_PORT.get();
if (port <= 0) {
throw new IllegalStateException("Invalid port.");
throwIllegalArgumentException("Invalid port.");
}
return ManagedChannelBuilder.forAddress(Properties.SIDECAR_IP.get(), port).usePlaintext().build();

View File

@ -7,6 +7,7 @@ package io.dapr.actors.client;
import io.dapr.actors.ActorId;
import io.dapr.actors.ActorMethod;
import io.dapr.exceptions.DaprException;
import io.dapr.serializer.DaprObjectSerializer;
import io.dapr.utils.TypeRef;
import reactor.core.publisher.Mono;
@ -173,7 +174,8 @@ class ActorProxyImpl implements ActorProxy, InvocationHandler {
try {
return this.serializer.deserialize(response, type);
} catch (IOException e) {
throw new RuntimeException(e);
DaprException.wrap(e);
return null;
}
}
@ -188,7 +190,8 @@ class ActorProxyImpl implements ActorProxy, InvocationHandler {
try {
return this.serializer.serialize(request);
} catch (IOException e) {
throw new RuntimeException(e);
DaprException.wrap(e);
return null;
}
}
}

View File

@ -7,10 +7,14 @@ package io.dapr.actors.client;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.protobuf.ByteString;
import io.dapr.exceptions.DaprException;
import io.dapr.v1.DaprGrpc;
import io.dapr.v1.DaprProtos;
import io.opentelemetry.context.Context;
import reactor.core.publisher.Mono;
import java.util.concurrent.Callable;
/**
* A DaprClient over GRPC for Actor.
*/
@ -37,7 +41,7 @@ class DaprGrpcClient implements DaprClient {
*/
@Override
public Mono<byte[]> invokeActorMethod(String actorType, String actorId, String methodName, byte[] jsonPayload) {
return Mono.fromCallable(() -> {
return Mono.fromCallable(DaprException.wrap(() -> {
DaprProtos.InvokeActorRequest req =
DaprProtos.InvokeActorRequest.newBuilder()
.setActorType(actorType)
@ -46,8 +50,17 @@ class DaprGrpcClient implements DaprClient {
.setData(jsonPayload == null ? ByteString.EMPTY : ByteString.copyFrom(jsonPayload))
.build();
ListenableFuture<DaprProtos.InvokeActorResponse> futureResponse = client.invokeActor(req);
return futureResponse.get();
}).map(r -> r.getData().toByteArray());
return get(client.invokeActor(req));
})).map(r -> r.getData().toByteArray());
}
private static <V> V get(ListenableFuture<V> future) {
try {
return future.get();
} catch (Exception e) {
DaprException.wrap(e);
}
return null;
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*/
package io.dapr.actors;
import io.dapr.exceptions.DaprException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.function.Executable;
public final class TestUtils {
private TestUtils() {}
public static <T extends Throwable> void assertThrowsDaprException(Class<T> expectedType, Executable executable) {
Throwable cause = Assertions.assertThrows(DaprException.class, executable).getCause();
Assertions.assertNotNull(cause);
Assertions.assertEquals(expectedType, cause.getClass());
}
public static void assertThrowsDaprException(String expectedErrorCode, Executable executable) {
DaprException daprException = Assertions.assertThrows(DaprException.class, executable);
Assertions.assertNull(daprException.getCause());
Assertions.assertEquals(expectedErrorCode, daprException.getErrorCode());
}
public static void assertThrowsDaprException(
String expectedErrorCode,
String expectedErrorMessage,
Executable executable) {
DaprException daprException = Assertions.assertThrows(DaprException.class, executable);
Assertions.assertNull(daprException.getCause());
Assertions.assertEquals(expectedErrorCode, daprException.getErrorCode());
Assertions.assertEquals(expectedErrorMessage, daprException.getMessage());
}
public static <T extends Throwable> void assertThrowsDaprException(
Class<T> expectedType,
String expectedErrorCode,
String expectedErrorMessage,
Executable executable) {
DaprException daprException = Assertions.assertThrows(DaprException.class, executable);
Assertions.assertNotNull(daprException.getCause());
Assertions.assertEquals(expectedType, daprException.getCause().getClass());
Assertions.assertEquals(expectedErrorCode, daprException.getErrorCode());
Assertions.assertEquals(expectedErrorMessage, daprException.getMessage());
}
}

View File

@ -7,33 +7,34 @@ package io.dapr.actors.client;
import io.dapr.actors.ActorId;
import io.dapr.actors.ActorType;
import io.dapr.exceptions.DaprException;
import org.junit.Assert;
import org.junit.Test;
public class ActorProxyBuilderTest {
@Test(expected = IllegalArgumentException.class)
@Test(expected = DaprException.class)
public void buildWithNullActorId() {
new ActorProxyBuilder("test", Object.class)
.build(null);
}
@Test(expected = IllegalArgumentException.class)
@Test(expected = DaprException.class)
public void buildWithEmptyActorType() {
new ActorProxyBuilder("", Object.class)
.build(new ActorId("100"));
}
@Test(expected = IllegalArgumentException.class)
@Test(expected = DaprException.class)
public void buildWithNullActorType() {
new ActorProxyBuilder(null, Object.class)
.build(new ActorId("100"));
}
@Test(expected = IllegalArgumentException.class)
@Test(expected = DaprException.class)
public void buildWithNullSerializer() {
new ActorProxyBuilder("MyActor", Object.class)
.withObjectSerializer(null)

View File

@ -7,6 +7,7 @@ package io.dapr.actors.client;
import io.dapr.actors.ActorId;
import io.dapr.actors.ActorMethod;
import io.dapr.exceptions.DaprException;
import io.dapr.serializer.DaprObjectSerializer;
import io.dapr.serializer.DefaultObjectSerializer;
import org.junit.Assert;
@ -309,7 +310,7 @@ public class ActorProxyImplTest {
}
@Test(expected = RuntimeException.class)
@Test(expected = DaprException.class)
public void invokeActorMethodSavingDataWithIncorrectReturnType() {
final DaprClient daprClient = mock(DaprClient.class);
when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNotNull()))
@ -355,7 +356,7 @@ public class ActorProxyImplTest {
}
@Test(expected = RuntimeException.class)
@Test(expected = DaprException.class)
public void invokeActorMethodSavingDataWithIncorrectInputType() {
final DaprClient daprClient = mock(DaprClient.class);
when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNotNull()))
@ -402,7 +403,7 @@ public class ActorProxyImplTest {
}
@Test(expected = RuntimeException.class)
@Test(expected = DaprException.class)
public void invokeActorMethodWithDataWithVoidIncorrectInputType() {
MyData saveData = new MyData();
saveData.setPropertyA("valueA");

View File

@ -14,6 +14,9 @@ import org.junit.Before;
import org.junit.Test;
import reactor.core.publisher.Mono;
import java.util.concurrent.ExecutionException;
import static io.dapr.actors.TestUtils.assertThrowsDaprException;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
@ -89,8 +92,12 @@ public class DaprGrpcClientTest {
return true;
}))).thenReturn(settableFuture);
Mono<byte[]> result = client.invokeActorMethod(ACTOR_TYPE, ACTOR_ID, methodName, null);
Exception exception = assertThrows(Exception.class, () -> result.block());
assertTrue(exception.getCause().getCause() instanceof ArithmeticException);
assertThrowsDaprException(
ExecutionException.class,
"UNKNOWN",
"UNKNOWN: java.lang.ArithmeticException",
() -> result.block());
}
@Test

View File

@ -8,14 +8,16 @@ 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.Test;
import reactor.core.publisher.Mono;
import static io.dapr.actors.TestUtils.assertThrowsDaprException;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
public class DaprHttpClientTest {
@ -35,15 +37,33 @@ public class DaprHttpClientTest {
@Test
public void invokeActorMethod() {
DaprHttp daprHttpMock = mock(DaprHttp.class);
mockInterceptor.addRule()
.post("http://127.0.0.1:3000/v1.0/actors/DemoActor/1/method/Payment")
.respond(EXPECTED_RESULT);
.post("http://127.0.0.1:3000/v1.0/actors/DemoActor/1/method/Payment")
.respond(EXPECTED_RESULT);
DaprHttp daprHttp = new DaprHttpProxy(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
DaprHttpClient = new DaprHttpClient(daprHttp);
Mono<byte[]> mono =
DaprHttpClient.invokeActorMethod("DemoActor", "1", "Payment", "".getBytes());
DaprHttpClient.invokeActorMethod("DemoActor", "1", "Payment", "".getBytes());
assertEquals(new String(mono.block()), EXPECTED_RESULT);
}
@Test
public void invokeActorMethodError() {
mockInterceptor.addRule()
.post("http://127.0.0.1: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(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
DaprHttpClient = new DaprHttpClient(daprHttp);
Mono<byte[]> mono =
DaprHttpClient.invokeActorMethod("DemoActor", "1", "Payment", "".getBytes());
assertThrowsDaprException(
"ERR_SOMETHING",
"ERR_SOMETHING: error message",
() -> mono.block());
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*/
package io.dapr.it;
import io.dapr.exceptions.DaprException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.function.Executable;
public final class TestUtils {
private TestUtils() {}
public static <T extends Throwable> void assertThrowsDaprException(Class<T> expectedType, Executable executable) {
Throwable cause = Assertions.assertThrows(DaprException.class, executable).getCause();
Assertions.assertNotNull(cause);
Assertions.assertEquals(expectedType, cause.getClass());
}
public static void assertThrowsDaprException(String expectedErrorCode, Executable executable) {
DaprException daprException = Assertions.assertThrows(DaprException.class, executable);
Assertions.assertNull(daprException.getCause());
Assertions.assertEquals(expectedErrorCode, daprException.getErrorCode());
}
public static <T extends Throwable> void assertThrowsDaprException(
String expectedErrorCode,
String expectedErrorMessage,
Executable executable) {
DaprException daprException = Assertions.assertThrows(DaprException.class, executable);
Assertions.assertEquals(expectedErrorCode, daprException.getErrorCode());
Assertions.assertEquals(expectedErrorMessage, daprException.getMessage());
}
}

View File

@ -66,7 +66,7 @@ public class MethodInvokeIT extends BaseIT {
}
@Test
public void testInvoke() throws IOException {
public void testInvoke() throws Exception {
// At this point, it is guaranteed that the service above is running and all ports being listened to.
@ -94,7 +94,7 @@ public class MethodInvokeIT extends BaseIT {
}
@Test
public void testInvokeWithObjects() throws IOException {
public void testInvokeWithObjects() throws Exception {
try (DaprClient client = new DaprClientBuilder().build()) {
for (int i = 0; i < NUM_MESSAGES; i++) {
Person person = new Person();

View File

@ -96,7 +96,7 @@ public class SecretsClientIT extends BaseIT {
}
@After
public void tearDown() throws IOException {
public void tearDown() throws Exception {
daprClient.close();
}

View File

@ -18,9 +18,12 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import static io.dapr.it.TestUtils.assertThrowsDaprException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* Common test cases for Dapr client (GRPC and HTTP).
@ -60,6 +63,22 @@ public abstract class AbstractStateClientIT extends BaseIT {
Assert.assertEquals("data in property B", myDataResponse.getValue().getPropertyB());
}
@Test
public void getStateKeyNotFound() {
final String stateKey = "unknownKey";
DaprClient daprClient = buildDaprClient();
State<String> state = (State<String>)
daprClient.getState(STATE_STORE_NAME, new State(stateKey), String.class).block();
Assert.assertNotNull(state);
Assert.assertEquals("unknownKey", state.getKey());
Assert.assertNull(state.getValue());
// gRPC returns empty eTag while HTTP returns null.
// TODO(artursouza): https://github.com/dapr/java-sdk/issues/405
Assert.assertTrue(state.getEtag() == null || state.getEtag().isEmpty());
}
@Test
public void saveAndGetBulkStates() {
final String stateKeyOne = UUID.randomUUID().toString();

View File

@ -8,12 +8,16 @@ package io.dapr.it.state;
import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;
import io.dapr.client.DaprClientGrpc;
import io.dapr.client.domain.State;
import io.dapr.it.DaprRun;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.IOException;
import java.util.Collections;
import static io.dapr.it.TestUtils.assertThrowsDaprException;
import static org.junit.Assert.assertTrue;
/**
@ -35,7 +39,7 @@ public class GRPCStateClientIT extends AbstractStateClientIT {
}
@AfterClass
public static void tearDown() throws IOException {
public static void tearDown() throws Exception {
daprClient.close();
}
@ -44,7 +48,45 @@ public class GRPCStateClientIT extends AbstractStateClientIT {
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(
"INVALID_ARGUMENT",
"INVALID_ARGUMENT: 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(
"INVALID_ARGUMENT",
"INVALID_ARGUMENT: state store unknown state store is not found",
() -> daprClient.getStates(
"unknown state store",
Collections.singletonList(stateKey),
byte[].class).block());
}
@Test
public void publishPubSubNotFound() {
DaprClient daprClient = buildDaprClient();
// DaprException is guaranteed in the Dapr SDK but getCause() is null in HTTP while present in GRPC implementation.
assertThrowsDaprException(
"NOT_FOUND",
"NOT_FOUND: pubsub 'unknown pubsub' not found",
() -> daprClient.publishEvent("unknown pubsub", "mytopic", "payload").block());
}
}

View File

@ -8,12 +8,16 @@ 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.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.IOException;
import java.util.Collections;
import static io.dapr.it.TestUtils.assertThrowsDaprException;
import static org.junit.Assert.assertTrue;
/**
@ -34,7 +38,7 @@ public class HttpStateClientIT extends AbstractStateClientIT {
}
@AfterClass
public static void tearDown() throws IOException {
public static void tearDown() throws Exception {
daprClient.close();
}
@ -43,4 +47,45 @@ public class HttpStateClientIT extends AbstractStateClientIT {
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%20state%20store 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%20state%20store is not found",
() -> daprClient.getStates(
"unknown state store",
Collections.singletonList(stateKey),
byte[].class).block());
}
@Test
public void publishPubSubNotFound() {
DaprClient daprClient = buildDaprClient();
// DaprException is guaranteed in the Dapr SDK but getCause() is null in HTTP while present in GRPC implementation.
assertThrowsDaprException(
"ERR_PUBSUB_NOT_FOUND",
"ERR_PUBSUB_NOT_FOUND: pubsub 'unknown%20pubsub' not found",
() -> daprClient.publishEvent("unknown pubsub", "mytopic", "payload").block());
}
}

View File

@ -31,7 +31,7 @@ import java.util.Map;
*
* @see io.dapr.client.DaprClientBuilder for information on how to make instance for this interface.
*/
public interface DaprClient extends Closeable {
public interface DaprClient extends AutoCloseable {
/**
* Publish an event.

View File

@ -14,6 +14,8 @@ import io.grpc.ManagedChannelBuilder;
import java.io.Closeable;
import static io.dapr.exceptions.DaprException.throwIllegalArgumentException;
/**
* A builder for the DaprClient,
* Currently only and HTTP Client will be supported.
@ -63,11 +65,11 @@ public class DaprClientBuilder {
*/
public DaprClientBuilder withObjectSerializer(DaprObjectSerializer objectSerializer) {
if (objectSerializer == null) {
throw new IllegalArgumentException("Object serializer is required");
throwIllegalArgumentException("Object serializer is required");
}
if (objectSerializer.getContentType() == null || objectSerializer.getContentType().isEmpty()) {
throw new IllegalArgumentException("Content Type should not be null or empty");
throwIllegalArgumentException("Content Type should not be null or empty");
}
this.objectSerializer = objectSerializer;
@ -83,7 +85,7 @@ public class DaprClientBuilder {
*/
public DaprClientBuilder withStateSerializer(DaprObjectSerializer stateSerializer) {
if (stateSerializer == null) {
throw new IllegalArgumentException("State serializer is required");
throwIllegalArgumentException("State serializer is required");
}
this.stateSerializer = stateSerializer;
@ -113,7 +115,7 @@ public class DaprClientBuilder {
private DaprClient buildDaprClientGrpc() {
int port = Properties.GRPC_PORT.get();
if (port <= 0) {
throw new IllegalStateException("Invalid port.");
throwIllegalArgumentException("Invalid port.");
}
ManagedChannel channel = ManagedChannelBuilder.forAddress(
Properties.SIDECAR_IP.get(), port).usePlaintext().build();

View File

@ -9,7 +9,6 @@ import com.google.common.base.Strings;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.protobuf.Any;
import com.google.protobuf.ByteString;
import com.google.protobuf.Empty;
import io.dapr.client.domain.DeleteStateRequest;
import io.dapr.client.domain.ExecuteStateTransactionRequest;
import io.dapr.client.domain.GetSecretRequest;
@ -25,6 +24,7 @@ import io.dapr.client.domain.State;
import io.dapr.client.domain.StateOptions;
import io.dapr.client.domain.TransactionalStateOperation;
import io.dapr.config.Properties;
import io.dapr.exceptions.DaprException;
import io.dapr.serializer.DaprObjectSerializer;
import io.dapr.utils.TypeRef;
import io.dapr.v1.CommonProtos;
@ -149,12 +149,11 @@ public class DaprClientGrpc extends AbstractDaprClient {
.setData(ByteString.copyFrom(objectSerializer.serialize(data))).build();
return Mono.fromCallable(wrap(context, () -> {
ListenableFuture<Empty> futureEmpty = client.publishEvent(envelope);
futureEmpty.get();
get(client.publishEvent(envelope));
return null;
}));
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
}
@ -178,10 +177,10 @@ public class DaprClientGrpc extends AbstractDaprClient {
ListenableFuture<CommonProtos.InvokeResponse> futureResponse =
client.invokeService(envelope);
return objectSerializer.deserialize(futureResponse.get().getData().getValue().toByteArray(), type);
return objectSerializer.deserialize(get(futureResponse).getData().getValue().toByteArray(), type);
})).map(r -> new Response<>(context, r));
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
}
@ -216,10 +215,10 @@ public class DaprClientGrpc extends AbstractDaprClient {
DaprProtos.InvokeBindingRequest envelope = builder.build();
return Mono.fromCallable(wrap(context, () -> {
ListenableFuture<DaprProtos.InvokeBindingResponse> futureResponse = client.invokeBinding(envelope);
return objectSerializer.deserialize(futureResponse.get().getData().toByteArray(), type);
return objectSerializer.deserialize(get(futureResponse).getData().toByteArray(), type);
})).map(r -> new Response<>(context, r));
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
}
@ -253,16 +252,10 @@ public class DaprClientGrpc extends AbstractDaprClient {
DaprProtos.GetStateRequest envelope = builder.build();
return Mono.fromCallable(wrap(context, () -> {
ListenableFuture<DaprProtos.GetStateResponse> futureResponse = client.getState(envelope);
DaprProtos.GetStateResponse response = null;
try {
response = futureResponse.get();
} catch (NullPointerException npe) {
return null;
}
return buildStateKeyValue(response, key, options, type);
return buildStateKeyValue(get(futureResponse), key, options, type);
})).map(s -> new Response<>(context, s));
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
}
@ -294,12 +287,7 @@ public class DaprClientGrpc extends AbstractDaprClient {
DaprProtos.GetBulkStateRequest envelope = builder.build();
return Mono.fromCallable(wrap(context, () -> {
ListenableFuture<DaprProtos.GetBulkStateResponse> futureResponse = client.getBulkState(envelope);
DaprProtos.GetBulkStateResponse response = null;
try {
response = futureResponse.get();
} catch (NullPointerException npe) {
return null;
}
DaprProtos.GetBulkStateResponse response = get(futureResponse);
return response
.getItemsList()
@ -307,14 +295,15 @@ public class DaprClientGrpc extends AbstractDaprClient {
.map(b -> {
try {
return buildStateKeyValue(b, type);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (Exception e) {
DaprException.wrap(e);
return null;
}
})
.collect(Collectors.toList());
})).map(s -> new Response<>(context, s));
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
}
@ -374,16 +363,10 @@ public class DaprClientGrpc extends AbstractDaprClient {
}
DaprProtos.ExecuteStateTransactionRequest req = builder.build();
return Mono.fromCallable(wrap(context, () -> client.executeStateTransaction(req))).flatMap(f -> {
try {
f.get();
} catch (Exception e) {
return Mono.error(e);
}
return Mono.empty();
}).thenReturn(new Response<>(context, null));
} catch (IOException e) {
return Mono.error(e);
return Mono.fromCallable(wrap(context, () -> client.executeStateTransaction(req))).map(f -> get(f))
.thenReturn(new Response<>(context, null));
} catch (Exception e) {
return DaprException.wrapMono(e);
}
}
@ -406,16 +389,10 @@ public class DaprClientGrpc extends AbstractDaprClient {
}
DaprProtos.SaveStateRequest req = builder.build();
return Mono.fromCallable(wrap(context, () -> client.saveState(req))).flatMap(f -> {
try {
f.get();
} catch (Exception ex) {
return Mono.error(ex);
}
return Mono.empty();
}).thenReturn(new Response<>(context, null));
return Mono.fromCallable(wrap(context, () -> client.saveState(req))).map(f -> get(f))
.thenReturn(new Response<>(context, null));
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
}
@ -492,16 +469,10 @@ public class DaprClientGrpc extends AbstractDaprClient {
}
DaprProtos.DeleteStateRequest req = builder.build();
return Mono.fromCallable(wrap(context, () -> client.deleteState(req))).flatMap(f -> {
try {
f.get();
} catch (Exception ex) {
return Mono.error(ex);
}
return Mono.empty();
}).thenReturn(new Response<>(context, null));
return Mono.fromCallable(wrap(context, () -> client.deleteState(req))).map(f -> get(f))
.thenReturn(new Response<>(context, null));
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
}
@ -563,7 +534,7 @@ public class DaprClientGrpc extends AbstractDaprClient {
throw new IllegalArgumentException("Secret key cannot be null or empty.");
}
} catch (Exception e) {
return Mono.error(e);
return DaprException.wrapMono(e);
}
DaprProtos.GetSecretRequest.Builder requestBuilder = DaprProtos.GetSecretRequest.newBuilder()
@ -576,7 +547,7 @@ public class DaprClientGrpc extends AbstractDaprClient {
return Mono.fromCallable(wrap(context, () -> {
DaprProtos.GetSecretRequest req = requestBuilder.build();
ListenableFuture<DaprProtos.GetSecretResponse> future = client.getSecret(req);
return future.get();
return get(future);
})).map(future -> new Response<>(context, future.getDataMap()));
}
@ -586,9 +557,12 @@ public class DaprClientGrpc extends AbstractDaprClient {
* @throws IOException on exception.
*/
@Override
public void close() throws IOException {
public void close() throws Exception {
if (channel != null) {
channel.close();
DaprException.wrap(() -> {
channel.close();
return true;
}).call();
}
}
@ -658,15 +632,25 @@ public class DaprClientGrpc extends AbstractDaprClient {
}
});
} catch (SpanContextParseException e) {
throw new RuntimeException(e);
throw new DaprException(e);
}
}
private static <V> Callable<V> wrap(Context context, Callable<V> callable) {
if (context == null) {
return callable;
return DaprException.wrap(callable);
}
return context.wrap(callable);
return DaprException.wrap(context.wrap(callable));
}
private static <V> V get(ListenableFuture<V> future) {
try {
return future.get();
} catch (Exception e) {
DaprException.wrap(e);
}
return null;
}
}

View File

@ -23,6 +23,7 @@ import io.dapr.client.domain.StateOptions;
import io.dapr.client.domain.TransactionalStateOperation;
import io.dapr.client.domain.TransactionalStateRequest;
import io.dapr.config.Properties;
import io.dapr.exceptions.DaprException;
import io.dapr.serializer.DaprObjectSerializer;
import io.dapr.serializer.DefaultObjectSerializer;
import io.dapr.utils.TypeRef;
@ -159,7 +160,7 @@ public class DaprClientHttp extends AbstractDaprClient {
DaprHttp.HttpMethods.POST.name(), url.toString(), null, serializedEvent, metadata, context)
.thenReturn(new Response<>(context, null));
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
}
@ -198,11 +199,11 @@ public class DaprClientHttp extends AbstractDaprClient {
return Mono.just(object);
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
}).map(r -> new Response<>(context, r));
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
}
@ -266,11 +267,11 @@ public class DaprClientHttp extends AbstractDaprClient {
return Mono.just(object);
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
}).map(r -> new Response<>(context, r));
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
}
@ -307,13 +308,13 @@ public class DaprClientHttp extends AbstractDaprClient {
try {
return Mono.just(buildStates(s, type));
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
})
.map(r -> new Response<>(context, r));
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
}
@ -358,12 +359,12 @@ public class DaprClientHttp extends AbstractDaprClient {
try {
return Mono.just(buildState(s, key, options, type));
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
})
.map(r -> new Response<>(context, r));
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
}
@ -383,19 +384,12 @@ public class DaprClientHttp extends AbstractDaprClient {
if (operations == null || operations.isEmpty()) {
return Mono.empty();
}
final Map<String, String> headers = new HashMap<>();
final String etag = operations.stream()
.filter(op -> null != op.getRequest().getEtag() && !op.getRequest().getEtag().trim().isEmpty())
.findFirst()
.orElse(new TransactionalStateOperation<>(null, new State<>(null,null, null, null)))
.getRequest()
.getEtag();
if (etag != null && !etag.trim().isEmpty()) {
headers.put(HEADER_HTTP_ETAG_ID, etag);
}
final String url = String.format(TRANSACTION_URL_FORMAT, stateStoreName);
List<TransactionalStateOperation<Object>> internalOperationObjects = new ArrayList<>(operations.size());
for (TransactionalStateOperation operation : operations) {
if (operation == null) {
continue;
}
State<?> state = operation.getRequest();
if (state == null) {
continue;
@ -416,10 +410,10 @@ public class DaprClientHttp extends AbstractDaprClient {
TransactionalStateRequest<Object> req = new TransactionalStateRequest<>(internalOperationObjects, metadata);
byte[] serializedOperationBody = INTERNAL_SERIALIZER.serialize(req);
return this.client.invokeApi(
DaprHttp.HttpMethods.POST.name(), url, null, serializedOperationBody, headers, context)
DaprHttp.HttpMethods.POST.name(), url, null, serializedOperationBody, null, context)
.thenReturn(new Response<>(context, null));
} catch (IOException e) {
return Mono.error(e);
} catch (Exception e) {
return DaprException.wrapMono(e);
}
}
@ -438,12 +432,6 @@ public class DaprClientHttp extends AbstractDaprClient {
if (states == null || states.isEmpty()) {
return Mono.empty();
}
final Map<String, String> headers = new HashMap<>();
final String etag = states.stream().filter(state -> null != state.getEtag() && !state.getEtag().trim().isEmpty())
.findFirst().orElse(new State<>(null, null, null, null)).getEtag();
if (etag != null && !etag.trim().isEmpty()) {
headers.put(HEADER_HTTP_ETAG_ID, etag);
}
final String url = STATE_PATH + "/" + stateStoreName;
List<State<Object>> internalStateObjects = new ArrayList<>(states.size());
for (State state : states) {
@ -466,10 +454,10 @@ public class DaprClientHttp extends AbstractDaprClient {
}
byte[] serializedStateBody = INTERNAL_SERIALIZER.serialize(internalStateObjects);
return this.client.invokeApi(
DaprHttp.HttpMethods.POST.name(), url, null, serializedStateBody, headers, context)
DaprHttp.HttpMethods.POST.name(), url, null, serializedStateBody, null, context)
.thenReturn(new Response<>(context, null));
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
}
@ -506,7 +494,7 @@ public class DaprClientHttp extends AbstractDaprClient {
DaprHttp.HttpMethods.DELETE.name(), url, urlParameters, headers, context)
.thenReturn(new Response<>(context, null));
} catch (Exception ex) {
return Mono.error(ex);
return DaprException.wrapMono(ex);
}
}
@ -581,7 +569,7 @@ public class DaprClientHttp extends AbstractDaprClient {
throw new IllegalArgumentException("Secret key cannot be null or empty.");
}
} catch (Exception e) {
return Mono.error(e);
return DaprException.wrapMono(e);
}
String url = SECRETS_PATH + "/" + secretStoreName + "/" + key;
@ -596,7 +584,7 @@ public class DaprClientHttp extends AbstractDaprClient {
return Mono.just(m);
} catch (IOException e) {
return Mono.error(e);
return DaprException.wrapMono(e);
}
})
.map(m -> (Map<String, String>)m)
@ -604,7 +592,11 @@ public class DaprClientHttp extends AbstractDaprClient {
}
@Override
public void close() throws IOException {
client.close();
public void close() {
try {
client.close();
} catch (Exception e) {
DaprException.wrap(e);
}
}
}

View File

@ -12,7 +12,6 @@ import io.dapr.exceptions.DaprException;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.propagation.HttpTraceContext;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapPropagator;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
@ -22,7 +21,6 @@ import okhttp3.ResponseBody;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono;
import java.io.Closeable;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
@ -32,7 +30,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.UUID;
public class DaprHttp implements Closeable {
public class DaprHttp implements AutoCloseable {
/**
* Dapr API used in this client.
@ -221,7 +219,7 @@ public class DaprHttp implements Closeable {
* @see OkHttpClient
*/
@Override
public void close() throws IOException {
public void close() {
// No code needed
}
@ -297,7 +295,7 @@ public class DaprHttp implements Closeable {
throw new DaprException(error);
}
throw new IllegalStateException("Unknown Dapr error. HTTP status code: " + response.code());
throw new DaprException("UNKNOWN", "HTTP status code: " + response.code());
}
Map<String, String> mapHeaders = new HashMap<>();

View File

@ -26,12 +26,12 @@ public class GetStatesRequestBuilder {
public GetStatesRequestBuilder(String stateStoreName, List<String> keys) {
this.stateStoreName = stateStoreName;
this.keys = Collections.unmodifiableList(keys);
this.keys = keys == null ? null : Collections.unmodifiableList(keys);
}
public GetStatesRequestBuilder(String stateStoreName, String... keys) {
this.stateStoreName = stateStoreName;
this.keys = Collections.unmodifiableList(Arrays.asList(keys));
this.keys = keys == null ? null : Collections.unmodifiableList(Arrays.asList(keys));
}
public GetStatesRequestBuilder withParallelism(int parallelism) {

View File

@ -6,6 +6,7 @@
package io.dapr.client.domain;
import io.dapr.client.DaprHttp;
import io.dapr.exceptions.DaprException;
import java.util.Collections;
import java.util.HashMap;
@ -73,13 +74,18 @@ public final class HttpExtension {
* @throws IllegalArgumentException on null method or queryString.
*/
public HttpExtension(DaprHttp.HttpMethods method, Map<String, String> queryString) {
if (method == null) {
throw new IllegalArgumentException("HttpExtension method cannot be null");
} else if (queryString == null) {
throw new IllegalArgumentException("HttpExtension queryString map cannot be null");
try {
if (method == null) {
throw new IllegalArgumentException("HttpExtension method cannot be null");
} else if (queryString == null) {
throw new IllegalArgumentException("HttpExtension queryString map cannot be null");
}
this.method = method;
this.queryString = Collections.unmodifiableMap(queryString);
} catch (RuntimeException e) {
DaprException.wrap(e);
}
this.method = method;
this.queryString = Collections.unmodifiableMap(queryString);
}
public DaprHttp.HttpMethods getMethod() {

View File

@ -5,6 +5,13 @@
package io.dapr.exceptions;
import io.grpc.StatusRuntimeException;
import reactor.core.publisher.Mono;
import java.lang.reflect.Executable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
/**
* A Dapr's specific exception.
*/
@ -32,10 +39,18 @@ public class DaprException extends RuntimeException {
* permitted, and indicates that the cause is nonexistent or
* unknown.)
*/
public DaprException(DaprError daprError, Throwable cause) {
public DaprException(DaprError daprError, Exception cause) {
this(daprError.getErrorCode(), daprError.getMessage(), cause);
}
/**
* Wraps an exception into a DaprException.
* @param exception the exception to be wrapped.
*/
public DaprException(Exception exception) {
this("UNKNOWN", exception.getMessage(), exception);
}
/**
* New Exception from a client-side generated error code and message.
*
@ -56,8 +71,8 @@ public class DaprException extends RuntimeException {
* permitted, and indicates that the cause is nonexistent or
* unknown.)
*/
public DaprException(String errorCode, String message, Throwable cause) {
super(String.format("%s: %s", errorCode, message), cause);
public DaprException(String errorCode, String message, Exception cause) {
super(String.format("%s: %s", errorCode, emptyIfNull(message)), cause);
this.errorCode = errorCode;
}
@ -69,4 +84,88 @@ public class DaprException extends RuntimeException {
public String getErrorCode() {
return this.errorCode;
}
/**
* Convenience to throw an wrapped IllegalArgumentException.
* @param message Message for exception.
*/
public static void throwIllegalArgumentException(String message) {
try {
throw new IllegalArgumentException(message);
} catch (Exception e) {
wrap(e);
}
}
/**
* Wraps an exception into DaprException (if not already DaprException).
*
* @param exception Exception to be wrapped.
* @return DaprException.
*/
public static DaprException wrap(Exception exception) {
if (exception == null) {
return null;
}
if (exception instanceof DaprException) {
throw (DaprException) exception;
}
Throwable e = exception;
while (e != null) {
if (e instanceof StatusRuntimeException) {
StatusRuntimeException statusRuntimeException = (StatusRuntimeException) e;
throw new DaprException(
statusRuntimeException.getStatus().getCode().toString(),
statusRuntimeException.getStatus().getDescription(),
exception);
}
e = e.getCause();
}
throw new DaprException(exception);
}
/**
* Wraps a callable with a try-catch to throw DaprException.
* @param callable callable to be invoked.
* @param <T> type to be returned
* @return object of type T.
*/
public static <T> Callable<T> wrap(Callable<T> callable) {
return () -> {
try {
return callable.call();
} catch (Exception e) {
return (T) wrap(e);
}
};
}
/**
* Wraps an exception into DaprException (if not already DaprException).
*
* @param exception Exception to be wrapped.
* @param <T> Mono's response type.
* @return Mono containing DaprException.
*/
public static <T> Mono<T> wrapMono(Exception exception) {
try {
wrap(exception);
} catch (Exception e) {
return Mono.error(e);
}
return Mono.empty();
}
private static String emptyIfNull(String str) {
if (str == null) {
return "";
}
return str;
}
}

View File

@ -5,6 +5,7 @@
package io.dapr.client;
import io.dapr.exceptions.DaprException;
import io.dapr.serializer.DaprObjectSerializer;
import org.junit.Test;
@ -26,17 +27,17 @@ public class DaprClientBuilderTest {
assertNotNull(daprClient);
}
@Test(expected = IllegalArgumentException.class)
@Test(expected = DaprException.class)
public void noObjectSerializer() {
new DaprClientBuilder().withObjectSerializer(null);
}
@Test(expected = IllegalArgumentException.class)
@Test(expected = DaprException.class)
public void blankContentTypeInObjectSerializer() {
new DaprClientBuilder().withObjectSerializer(mock(DaprObjectSerializer.class));
}
@Test(expected = IllegalArgumentException.class)
@Test(expected = DaprException.class)
public void noStateSerializer() {
new DaprClientBuilder().withStateSerializer(null);
}

View File

@ -29,6 +29,9 @@ import io.dapr.utils.TypeRef;
import io.dapr.v1.CommonProtos;
import io.dapr.v1.DaprGrpc;
import io.dapr.v1.DaprProtos;
import io.grpc.Status;
import io.grpc.StatusException;
import io.grpc.StatusRuntimeException;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;
import org.junit.After;
import org.junit.Before;
@ -44,9 +47,11 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import static com.google.common.util.concurrent.Futures.addCallback;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static io.dapr.utils.TestUtils.assertThrowsDaprException;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@ -85,34 +90,43 @@ public class DaprClientGrpcTest {
}
@After
public void tearDown() throws IOException {
public void tearDown() throws Exception {
adapter.close();
verify(closeable).close();
verifyNoMoreInteractions(closeable);
}
@Test(expected = RuntimeException.class)
@Test
public void publishEventExceptionThrownTest() {
when(client.publishEvent(any(DaprProtos.PublishEventRequest.class)))
.thenThrow(RuntimeException.class);
Mono<Void> result = adapter.publishEvent("pubsubname","topic", "object");
result.block();
.thenThrow(newStatusRuntimeException("INVALID_ARGUMENT", "bad bad argument"));
assertThrowsDaprException(
StatusRuntimeException.class,
"INVALID_ARGUMENT",
"INVALID_ARGUMENT: bad bad argument",
() -> adapter.publishEvent("pubsubname","topic", "object").block());
}
@Test(expected = RuntimeException.class)
@Test
public void publishEventCallbackExceptionThrownTest() {
SettableFuture<Empty> settableFuture = SettableFuture.create();
RuntimeException ex = new RuntimeException("An Exception");
RuntimeException ex = newStatusRuntimeException("INVALID_ARGUMENT", "bad bad argument");
MockCallback<Empty> callback = new MockCallback<>(ex);
addCallback(settableFuture, callback, directExecutor());
when(client.publishEvent(any(DaprProtos.PublishEventRequest.class)))
.thenReturn(settableFuture);
Mono<Void> result = adapter.publishEvent("pubsubname","topic", "object");
settableFuture.setException(ex);
result.block();
assertThrowsDaprException(
ExecutionException.class,
"INVALID_ARGUMENT",
"INVALID_ARGUMENT: bad bad argument",
() -> result.block());
}
@Test(expected = RuntimeException.class)
@Test
public void publishEventSerializeException() throws IOException {
DaprObjectSerializer mockSerializer = mock(DaprObjectSerializer.class);
adapter = new DaprClientGrpc(closeable, client, mockSerializer, new DefaultObjectSerializer());
@ -121,7 +135,12 @@ public class DaprClientGrpcTest {
.thenReturn(settableFuture);
when(mockSerializer.serialize(any())).thenThrow(IOException.class);
Mono<Void> result = adapter.publishEvent("pubsubname","topic", "{invalid-json");
result.block();
assertThrowsDaprException(
IOException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test
@ -168,25 +187,25 @@ public class DaprClientGrpcTest {
@Test
public void invokeBindingIllegalArgumentExceptionTest() {
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// empty binding name
adapter.invokeBinding("", "MyOperation", "request".getBytes(), Collections.EMPTY_MAP).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// null binding name
adapter.invokeBinding(null, "MyOperation", "request".getBytes(), Collections.EMPTY_MAP).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// null binding operation
adapter.invokeBinding("BindingName", null, "request".getBytes(), Collections.EMPTY_MAP).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// empty binding operation
adapter.invokeBinding("BindingName", "", "request".getBytes(), Collections.EMPTY_MAP).block();
});
}
@Test(expected = RuntimeException.class)
@Test
public void invokeBindingSerializeException() throws IOException {
DaprObjectSerializer mockSerializer = mock(DaprObjectSerializer.class);
adapter = new DaprClientGrpc(closeable, client, mockSerializer, new DefaultObjectSerializer());
@ -195,18 +214,28 @@ public class DaprClientGrpcTest {
.thenReturn(settableFuture);
when(mockSerializer.serialize(any())).thenThrow(IOException.class);
Mono<Void> result = adapter.invokeBinding("BindingName", "MyOperation", "request".getBytes(), Collections.EMPTY_MAP);
result.block();
assertThrowsDaprException(
IOException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test(expected = RuntimeException.class)
@Test
public void invokeBindingExceptionThrownTest() {
when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class)))
when(client.invokeBinding(any(DaprProtos.InvokeBindingRequest.class)))
.thenThrow(RuntimeException.class);
Mono<Void> result = adapter.invokeBinding("BindingName", "MyOperation", "request");
result.block();
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test(expected = RuntimeException.class)
@Test
public void invokeBindingCallbackExceptionThrownTest() {
SettableFuture<DaprProtos.InvokeBindingResponse> settableFuture = SettableFuture.create();
RuntimeException ex = new RuntimeException("An Exception");
@ -217,7 +246,12 @@ public class DaprClientGrpcTest {
when(client.invokeBinding(any(DaprProtos.InvokeBindingRequest.class)))
.thenReturn(settableFuture);
Mono<Void> result = adapter.invokeBinding("BindingName", "MyOperation", "request");
result.block();
assertThrowsDaprException(
ExecutionException.class,
"UNKNOWN",
"UNKNOWN: java.lang.RuntimeException: An Exception",
() -> result.block());
}
@Test
@ -314,33 +348,48 @@ public class DaprClientGrpcTest {
assertFalse(callback.wasCalled);
}
@Test(expected = RuntimeException.class)
@Test
public void invokeServiceVoidExceptionThrownTest() {
when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class)))
.thenThrow(RuntimeException.class);
Mono<Void> result = adapter.invokeService("appId", "method", "request", HttpExtension.NONE);
result.block();
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test(expected = RuntimeException.class)
@Test
public void invokeServiceIllegalArgumentExceptionThrownTest() {
SettableFuture<CommonProtos.InvokeResponse> settableFuture = SettableFuture.create();
when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class)))
.thenReturn(settableFuture);
// HttpExtension cannot be null
Mono<Void> result = adapter.invokeService("appId", "method", "request", null);
result.block();
assertThrowsDaprException(
IllegalArgumentException.class,
"UNKNOWN",
"UNKNOWN: HttpExtension cannot be null. Use HttpExtension.NONE instead.",
() -> result.block());
}
@Test(expected = RuntimeException.class)
@Test
public void invokeServiceEmptyRequestVoidExceptionThrownTest() {
when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class)))
.thenThrow(RuntimeException.class);
Mono<Void> result = adapter.invokeService("appId", "method", HttpExtension.NONE, (Map<String, String>)null);
result.block();
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test(expected = RuntimeException.class)
@Test
public void invokeServiceVoidCallbackExceptionThrownTest() {
SettableFuture<CommonProtos.InvokeResponse> settableFuture = SettableFuture.create();
RuntimeException ex = new RuntimeException("An Exception");
@ -350,7 +399,12 @@ public class DaprClientGrpcTest {
when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class)))
.thenReturn(settableFuture);
Mono<Void> result = adapter.invokeService("appId", "method", "request", HttpExtension.NONE);
result.block();
assertThrowsDaprException(
ExecutionException.class,
"UNKNOWN",
"UNKNOWN: java.lang.RuntimeException: An Exception",
() -> result.block());
}
@Test
@ -384,31 +438,46 @@ public class DaprClientGrpcTest {
assertTrue(callback.wasCalled);
}
@Test(expected = RuntimeException.class)
@Test
public void invokeServiceExceptionThrownTest() {
when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class)))
.thenThrow(RuntimeException.class);
Mono<String> result = adapter.invokeService("appId", "method", "request", HttpExtension.NONE, null, String.class);
result.block();
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test(expected = RuntimeException.class)
@Test
public void invokeServiceNoRequestClassExceptionThrownTest() {
when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class)))
.thenThrow(RuntimeException.class);
Mono<String> result = adapter.invokeService("appId", "method", HttpExtension.NONE, (Map<String, String>)null, String.class);
result.block();
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test(expected = RuntimeException.class)
@Test
public void invokeServiceNoRequestTypeRefExceptionThrownTest() {
when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class)))
.thenThrow(RuntimeException.class);
Mono<String> result = adapter.invokeService("appId", "method", HttpExtension.NONE, (Map<String, String>)null, TypeRef.STRING);
result.block();
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test(expected = RuntimeException.class)
@Test
public void invokeServiceCallbackExceptionThrownTest() {
SettableFuture<CommonProtos.InvokeResponse> settableFuture = SettableFuture.create();
RuntimeException ex = new RuntimeException("An Exception");
@ -418,7 +487,12 @@ public class DaprClientGrpcTest {
.thenReturn(settableFuture);
Mono<String> result = adapter.invokeService("appId", "method", "request", HttpExtension.NONE, null, String.class);
settableFuture.setException(ex);
result.block();
assertThrowsDaprException(
ExecutionException.class,
"UNKNOWN",
"UNKNOWN: java.lang.RuntimeException: An Exception",
() -> result.block());
}
@Test
@ -482,15 +556,20 @@ public class DaprClientGrpcTest {
assertEquals(object.value, resultObject.value);
}
@Test(expected = RuntimeException.class)
@Test
public void invokeServiceNoRequestBodyExceptionThrownTest() {
when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class)))
.thenThrow(RuntimeException.class);
Mono<String> result = adapter.invokeService("appId", "method", (Object)null, HttpExtension.NONE, String.class);
result.block();
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test(expected = RuntimeException.class)
@Test
public void invokeServiceNoRequestCallbackExceptionThrownTest() {
SettableFuture<CommonProtos.InvokeResponse> settableFuture = SettableFuture.create();
RuntimeException ex = new RuntimeException("An Exception");
@ -500,7 +579,12 @@ public class DaprClientGrpcTest {
.thenReturn(settableFuture);
Mono<String> result = adapter.invokeService("appId", "method", (Object)null, HttpExtension.NONE, String.class);
settableFuture.setException(ex);
result.block();
assertThrowsDaprException(
ExecutionException.class,
"UNKNOWN",
"UNKNOWN: java.lang.RuntimeException: An Exception",
() -> result.block());
}
@Test
@ -536,17 +620,22 @@ public class DaprClientGrpcTest {
assertEquals(object.value, resultObject.value);
}
@Test(expected = RuntimeException.class)
@Test
public void invokeServiceByteRequestExceptionThrownTest() throws IOException {
when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class)))
.thenThrow(RuntimeException.class);
String request = "Request";
byte[] byteRequest = serializer.serialize(request);
Mono<byte[]> result = adapter.invokeService("appId", "method", byteRequest, HttpExtension.NONE, byte[].class);
result.block();
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test(expected = RuntimeException.class)
@Test
public void invokeServiceByteRequestCallbackExceptionThrownTest() throws IOException {
SettableFuture<CommonProtos.InvokeResponse> settableFuture = SettableFuture.create();
RuntimeException ex = new RuntimeException("An Exception");
@ -559,7 +648,12 @@ public class DaprClientGrpcTest {
Mono<byte[]> result =
adapter.invokeService("appId", "method", byteRequest, HttpExtension.NONE,(HashMap<String, String>) null);
settableFuture.setException(ex);
result.block();
assertThrowsDaprException(
ExecutionException.class,
"UNKNOWN",
"UNKNOWN: java.lang.RuntimeException: An Exception",
() -> result.block());
}
@Test
@ -598,15 +692,20 @@ public class DaprClientGrpcTest {
assertEquals(resultObj, serializer.deserialize(byteOutput, MyObject.class));
}
@Test(expected = RuntimeException.class)
@Test
public void invokeServiceNoRequestNoClassBodyExceptionThrownTest() {
when(client.invokeService(any(DaprProtos.InvokeServiceRequest.class)))
.thenThrow(RuntimeException.class);
Mono<Void> result = adapter.invokeService("appId", "method", (Object)null, HttpExtension.NONE);
result.block();
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test(expected = RuntimeException.class)
@Test
public void invokeServiceNoRequestNoClassCallbackExceptionThrownTest() {
SettableFuture<CommonProtos.InvokeResponse> settableFuture = SettableFuture.create();
RuntimeException ex = new RuntimeException("An Exception");
@ -616,7 +715,12 @@ public class DaprClientGrpcTest {
.thenReturn(settableFuture);
Mono<Void> result = adapter.invokeService("appId", "method", (Object)null, HttpExtension.NONE);
settableFuture.setException(ex);
result.block();
assertThrowsDaprException(
ExecutionException.class,
"UNKNOWN",
"UNKNOWN: java.lang.RuntimeException: An Exception",
() -> result.block());
}
@Test
@ -670,33 +774,38 @@ public class DaprClientGrpcTest {
@Test
public void getStateIllegalArgumentExceptionTest() {
State<String> key = buildStateKey(null, "Key1", "ETag1", null);
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// empty state store name
adapter.getState("", key, String.class).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// null state store name
adapter.getState(null, key, String.class).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// null key
adapter.getState(STATE_STORE_NAME, (String)null, String.class).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// empty key
adapter.getState(STATE_STORE_NAME, "", String.class).block();
});
}
@Test(expected = RuntimeException.class)
@Test
public void getStateExceptionThrownTest() {
when(client.getState(any(io.dapr.v1.DaprProtos.GetStateRequest.class))).thenThrow(RuntimeException.class);
State<String> key = buildStateKey(null, "Key1", "ETag1", null);
Mono<State<String>> result = adapter.getState(STATE_STORE_NAME, key, String.class);
result.block();
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test(expected = RuntimeException.class)
@Test
public void getStateCallbackExceptionThrownTest() {
SettableFuture<DaprProtos.GetStateResponse> settableFuture = SettableFuture.create();
RuntimeException ex = new RuntimeException("An Exception");
@ -708,7 +817,12 @@ public class DaprClientGrpcTest {
State<String> key = buildStateKey(null, "Key1", "ETag1", null);
Mono<State<String>> result = adapter.getState(STATE_STORE_NAME, key, String.class);
settableFuture.setException(ex);
result.block();
assertThrowsDaprException(
ExecutionException.class,
"UNKNOWN",
"UNKNOWN: java.lang.RuntimeException: An Exception",
() -> result.block());
}
@Test
@ -829,20 +943,20 @@ public class DaprClientGrpcTest {
@Test
public void getStatesIllegalArgumentExceptionTest() {
State<String> key = buildStateKey(null, "Key1", "ETag1", null);
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// empty state store name
adapter.getStates("", Collections.singletonList("100"), String.class).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// null state store name
adapter.getStates(null, Collections.singletonList("100"), String.class).block();
});
assertThrows(NullPointerException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// null key
// null pointer exception due to keys being converted to an unmodifiable list
adapter.getStates(STATE_STORE_NAME, null, String.class).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// empty key list
adapter.getStates(STATE_STORE_NAME, Collections.emptyList(), String.class).block();
});
@ -850,7 +964,7 @@ public class DaprClientGrpcTest {
GetStatesRequest req = new GetStatesRequestBuilder(STATE_STORE_NAME, Collections.singletonList("100"))
.withParallelism(-1)
.build();
assertThrows(IllegalArgumentException.class, () -> adapter.getStates(req, TypeRef.BOOLEAN).block());
assertThrowsDaprException(IllegalArgumentException.class, () -> adapter.getStates(req, TypeRef.BOOLEAN).block());
}
@Test
@ -1029,36 +1143,41 @@ public class DaprClientGrpcTest {
assertEquals("not found", result.stream().skip(1).findFirst().get().getError());
}
@Test(expected = RuntimeException.class)
@Test
public void deleteStateExceptionThrowTest() {
when(client.deleteState(any(io.dapr.v1.DaprProtos.DeleteStateRequest.class))).thenThrow(RuntimeException.class);
State<String> key = buildStateKey(null, "Key1", "ETag1", null);
Mono<Void> result = adapter.deleteState(STATE_STORE_NAME, key.getKey(), key.getEtag(), key.getOptions());
result.block();
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test
public void deleteStateIllegalArgumentExceptionTest() {
State<String> key = buildStateKey(null, "Key1", "ETag1", null);
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// empty state store name
adapter.deleteState("", key.getKey(), "etag", null).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// null state store name
adapter.deleteState(null, key.getKey(), "etag", null).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// null state store name
adapter.deleteState(STATE_STORE_NAME, null, "etag", null).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// null state store name
adapter.deleteState(STATE_STORE_NAME, "", "etag", null).block();
});
}
@Test(expected = RuntimeException.class)
@Test
public void deleteStateCallbackExcpetionThrownTest() {
SettableFuture<Empty> settableFuture = SettableFuture.create();
RuntimeException ex = new RuntimeException("An Exception");
@ -1069,7 +1188,12 @@ public class DaprClientGrpcTest {
State<String> key = buildStateKey(null, "Key1", "ETag1", null);
Mono<Void> result = adapter.deleteState(STATE_STORE_NAME, key.getKey(), key.getEtag(), key.getOptions());
settableFuture.setException(ex);
result.block();
assertThrowsDaprException(
ExecutionException.class,
"UNKNOWN",
"UNKNOWN: java.lang.RuntimeException: An Exception",
() -> result.block());
}
@Test
@ -1190,17 +1314,17 @@ public class DaprClientGrpcTest {
TransactionalStateOperation<String> upsertOperation = new TransactionalStateOperation<>(
TransactionalStateOperation.OperationType.UPSERT,
key);
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// empty state store name
adapter.executeTransaction("", Collections.singletonList(upsertOperation)).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// null state store name
adapter.executeTransaction(null, Collections.singletonList(upsertOperation)).block();
});
}
@Test(expected = RuntimeException.class)
@Test
public void executeTransactionSerializerExceptionTest() throws IOException {
DaprObjectSerializer mockSerializer = mock(DaprObjectSerializer.class);
adapter = new DaprClientGrpc(closeable, client, mockSerializer, mockSerializer);
@ -1220,7 +1344,12 @@ public class DaprClientGrpcTest {
.withTransactionalStates(upsertOperation)
.build();
Mono<Response<Void>> result = adapter.executeTransaction(request);
result.block();
assertThrowsDaprException(
IOException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test
@ -1278,7 +1407,7 @@ public class DaprClientGrpcTest {
assertTrue(callback.wasCalled);
}
@Test(expected = RuntimeException.class)
@Test
public void executeTransactionExceptionThrownTest() {
String etag = "ETag1";
String key = "key1";
@ -1291,10 +1420,15 @@ public class DaprClientGrpcTest {
TransactionalStateOperation.OperationType.UPSERT,
stateKey);
Mono<Void> result = adapter.executeTransaction(STATE_STORE_NAME, Collections.singletonList(operation));
result.block();
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test(expected = RuntimeException.class)
@Test
public void executeTransactionCallbackExceptionTest() {
String etag = "ETag1";
String key = "key1";
@ -1312,32 +1446,42 @@ public class DaprClientGrpcTest {
stateKey);
Mono<Void> result = adapter.executeTransaction(STATE_STORE_NAME, Collections.singletonList(operation));
settableFuture.setException(ex);
result.block();
assertThrowsDaprException(
ExecutionException.class,
"UNKNOWN",
"UNKNOWN: java.lang.RuntimeException: ex",
() -> result.block());
}
@Test
public void saveStatesIllegalArgumentExceptionTest() {
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// empty state store name
adapter.saveStates("", Collections.emptyList()).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// empty state store name
adapter.saveStates(null, Collections.emptyList()).block();
});
}
@Test(expected = RuntimeException.class)
@Test
public void saveStateExceptionThrownTest() {
String key = "key1";
String etag = "ETag1";
String value = "State value";
when(client.saveState(any(io.dapr.v1.DaprProtos.SaveStateRequest.class))).thenThrow(RuntimeException.class);
Mono<Void> result = adapter.saveState(STATE_STORE_NAME, key, etag, value, null);
result.block();
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
@Test(expected = RuntimeException.class)
@Test
public void saveStateCallbackExceptionThrownTest() {
String key = "key1";
String etag = "ETag1";
@ -1349,7 +1493,12 @@ public class DaprClientGrpcTest {
when(client.saveState(any(io.dapr.v1.DaprProtos.SaveStateRequest.class))).thenReturn(settableFuture);
Mono<Void> result = adapter.saveState(STATE_STORE_NAME, key, etag, value, null);
settableFuture.setException(ex);
result.block();
assertThrowsDaprException(
ExecutionException.class,
"UNKNOWN",
"UNKNOWN: java.lang.RuntimeException: An Exception",
() -> result.block());
}
@Test
@ -1478,22 +1627,25 @@ public class DaprClientGrpcTest {
*/
@Test
public void getStateDeleteStateThenBlockDeleteThenBlockGet() throws Exception {
public void getStateThenDelete() throws Exception {
String etag = "ETag1";
String key1 = "key1";
String expectedValue1 = "Expected state 1";
String key2 = "key2";
String expectedValue2 = "Expected state 2";
State<String> expectedState1 = buildStateKey(expectedValue1, key1, etag, new HashMap<>(), null);
State<String> expectedState2 = buildStateKey(expectedValue2, key2, etag, new HashMap<>(), null);
Map<String, SettableFuture<DaprProtos.GetStateResponse>> futuresMap = new HashMap<>();
futuresMap.put(key1, buildFutureGetStateEnvelop(expectedValue1, etag));
futuresMap.put(key2, buildFutureGetStateEnvelop(expectedValue2, etag));
when(client.getState(argThat(new GetStateRequestKeyMatcher(key1)))).thenReturn(futuresMap.get(key1));
when(client.getState(argThat(new GetStateRequestKeyMatcher(key2)))).thenReturn(futuresMap.get(key2));
State<String> keyRequest1 = buildStateKey(null, key1, etag, null);
Mono<State<String>> resultGet1 = adapter.getState(STATE_STORE_NAME, keyRequest1, String.class);
assertEquals(expectedState1, resultGet1.block());
State<String> keyRequest2 = buildStateKey(null, key2, etag, null);
Mono<State<String>> resultGet2 = adapter.getState(STATE_STORE_NAME, keyRequest2, String.class);
assertEquals(expectedState2, resultGet2.block());
SettableFuture<Empty> settableFutureDelete = SettableFuture.create();
MockCallback<Empty> callbackDelete = new MockCallback<>(Empty.newBuilder().build());
@ -1505,11 +1657,6 @@ public class DaprClientGrpcTest {
settableFutureDelete.set(Empty.newBuilder().build());
resultDelete.block();
assertTrue(callbackDelete.wasCalled);
futuresMap.replace(key2, null);
when(client.getState(argThat(new GetStateRequestKeyMatcher(key2)))).thenReturn(futuresMap.get(key2));
State<String> state2 = resultGet2.block();
assertNull(state2);
}
@Test
@ -1575,24 +1722,24 @@ public class DaprClientGrpcTest {
return settableFuture;
});
assertThrows(RuntimeException.class, () -> adapter.getSecret(SECRET_STORE_NAME, "key").block());
assertThrowsDaprException(ExecutionException.class, () -> adapter.getSecret(SECRET_STORE_NAME, "key").block());
}
@Test
public void getSecretsIllegalArgumentException() {
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// empty secret store name
adapter.getSecret("", "key").block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// null secret store name
adapter.getSecret(null, "key").block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// empty key
adapter.getSecret(SECRET_STORE_NAME, "").block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// null key
adapter.getSecret(SECRET_STORE_NAME, null).block();
});
@ -1821,4 +1968,8 @@ public class DaprClientGrpcTest {
return "<Has property of certain value (propName: " + propValue + ") matcher>";
}
}
private static StatusRuntimeException newStatusRuntimeException(String status, String message) {
return new StatusRuntimeException(Status.fromCode(Status.Code.valueOf(status)).withDescription(message));
}
}

View File

@ -4,8 +4,10 @@
*/
package io.dapr.client;
import com.fasterxml.jackson.core.JsonParseException;
import io.dapr.client.domain.DeleteStateRequestBuilder;
import io.dapr.client.domain.GetStateRequestBuilder;
import io.dapr.client.domain.GetStatesRequestBuilder;
import io.dapr.client.domain.HttpExtension;
import io.dapr.client.domain.Response;
import io.dapr.client.domain.State;
@ -14,12 +16,16 @@ import io.dapr.client.domain.TransactionalStateOperation;
import io.dapr.config.Properties;
import io.dapr.utils.TypeRef;
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.Test;
import org.mockito.Mockito;
import reactor.core.publisher.Mono;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
@ -28,6 +34,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static io.dapr.utils.TestUtils.assertThrowsDaprException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@ -53,7 +60,7 @@ public class DaprClientHttpTest {
private MockInterceptor mockInterceptor;
@Before
public void setUp() throws Exception {
public void setUp() {
mockInterceptor = new MockInterceptor(Behavior.UNORDERED);
okHttpClient = new OkHttpClient.Builder().addInterceptor(mockInterceptor).build();
}
@ -82,16 +89,15 @@ public class DaprClientHttpTest {
assertNull(mono.block());
}
@Test(expected = IllegalArgumentException.class)
public void publishEventIfTopicIsNull() {
mockInterceptor.addRule()
.post("http://127.0.0.1:3000/v1.0/publish/mypubsubname/A")
.respond(EXPECTED_RESULT);
@Test
public void publishEventIfTopicIsNullOrEmpty() {
String event = "{ \"message\": \"This is a test\" }";
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
Mono<Void> mono = daprClientHttp.publishEvent("mypubsubname", "", event);
assertNull(mono.block());
assertThrowsDaprException(IllegalArgumentException.class, () ->
daprClientHttp.publishEvent("mypubsubname", null, event).block());
assertThrowsDaprException(IllegalArgumentException.class, () ->
daprClientHttp.publishEvent("mypubsubname", "", event).block());
}
@Test
@ -106,7 +112,7 @@ public class DaprClientHttpTest {
// Should not throw exception because did not call block() on mono above.
}
@Test(expected = IllegalArgumentException.class)
@Test
public void invokeServiceVerbNull() {
mockInterceptor.addRule()
.post("http://127.0.0.1:3000/v1.0/publish/A")
@ -114,46 +120,49 @@ public class DaprClientHttpTest {
String event = "{ \"message\": \"This is a test\" }";
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
Mono<Void> mono = daprClientHttp.invokeService(null, "", "", null, null, (Class)null);
assertNull(mono.block());
assertThrowsDaprException(IllegalArgumentException.class, () ->
daprClientHttp.invokeService(null, "", "", null, null, (Class)null).block());
}
@Test
public void invokeServiceIllegalArgumentException() {
mockInterceptor.addRule()
.post("http://127.0.0.1:3000/v1.0/publish/A")
.respond(EXPECTED_RESULT);
String event = "{ \"message\": \"This is a test\" }";
.get("http://127.0.0.1:3000/v1.0/invoke/41/method/badorder")
.respond("INVALID JSON");
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// null HttpMethod
daprClientHttp.invokeService("1", "2", "3", new HttpExtension(null, null), null, (Class)null).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// null HttpExtension
daprClientHttp.invokeService("1", "2", "3", null, null, (Class)null).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// empty appId
daprClientHttp.invokeService("", "1", null, HttpExtension.GET, null, (Class)null).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// null appId, empty method
daprClientHttp.invokeService(null, "", null, HttpExtension.POST, null, (Class)null).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// empty method
daprClientHttp.invokeService("1", "", null, HttpExtension.PUT, null, (Class)null).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
// null method
daprClientHttp.invokeService("1", null, null, HttpExtension.DELETE, null, (Class)null).block();
});
assertThrowsDaprException(JsonParseException.class, () -> {
// invalid JSON response
daprClientHttp.invokeService("41", "badorder", null, HttpExtension.GET, null, String.class).block();
});
}
@Test(expected = IllegalArgumentException.class)
@Test
public void invokeServiceMethodNull() {
mockInterceptor.addRule()
.post("http://127.0.0.1:3000/v1.0/publish/A")
@ -161,24 +170,34 @@ public class DaprClientHttpTest {
String event = "{ \"message\": \"This is a test\" }";
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
Mono<Void> mono = daprClientHttp.invokeService("1", "", null, HttpExtension.POST, null, (Class)null);
assertNull(mono.block());
assertThrowsDaprException(IllegalArgumentException.class, () ->
daprClientHttp.invokeService("1", "", null, HttpExtension.POST, null, (Class)null).block());
}
@Test
public void invokeService() {
mockInterceptor.addRule()
.get("http://127.0.0.1:3000/v1.0/invoke/41/method/neworder")
.respond("\"hello world\"");
.get("http://127.0.0.1:3000/v1.0/invoke/41/method/neworder")
.respond("\"hello world\"");
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
Mono<String> mono = daprClientHttp.invokeService("41", "neworder", null, HttpExtension.GET, null, String.class);
assertEquals("hello world", mono.block());
}
@Test
public void invokeServiceNullResponse() {
mockInterceptor.addRule()
.get("http://127.0.0.1:3000/v1.0/invoke/41/method/neworder")
.respond(new byte[0]);
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
Mono<String> mono = daprClientHttp.invokeService("41", "neworder", null, HttpExtension.GET, null, String.class);
assertNull(mono.block());
}
@Test
public void simpleInvokeService() {
Map<String, String> map = new HashMap<>();
mockInterceptor.addRule()
.get("http://127.0.0.1:3000/v1.0/invoke/41/method/neworder")
.respond(EXPECTED_RESULT);
@ -256,14 +275,62 @@ public class DaprClientHttpTest {
public void invokeBinding() {
Map<String, String> map = new HashMap<>();
mockInterceptor.addRule()
.post("http://127.0.0.1:3000/v1.0/bindings/sample-topic")
.respond("");
.post("http://127.0.0.1:3000/v1.0/bindings/sample-topic")
.respond("");
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
Mono<Void> mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "");
assertNull(mono.block());
}
@Test
public void invokeBindingNullData() {
Map<String, String> map = new HashMap<>();
mockInterceptor.addRule()
.post("http://127.0.0.1:3000/v1.0/bindings/sample-topic")
.respond("");
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
Mono<Void> mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", null);
assertNull(mono.block());
}
@Test
public void invokeBindingErrors() {
mockInterceptor.addRule()
.post("http://127.0.0.1:3000/v1.0/bindings/sample-topic")
.respond("NOT VALID JSON");
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.invokeBinding(null, "myoperation", "").block();
});
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.invokeBinding("", "myoperation", "").block();
});
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.invokeBinding("topic", null, "").block();
});
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.invokeBinding("topic", "", "").block();
});
assertThrowsDaprException(JsonParseException.class, () -> {
daprClientHttp.invokeBinding("sample-topic", "op", "data", String.class).block();
});
}
@Test
public void invokeBindingResponseNull() {
Map<String, String> map = new HashMap<>();
mockInterceptor.addRule()
.post("http://127.0.0.1:3000/v1.0/bindings/sample-topic")
.respond(new byte[0]);
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
Mono<String> mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", null, String.class);
assertNull(mono.block());
}
@Test
public void invokeBindingResponseObject() {
Map<String, String> map = new HashMap<>();
@ -284,7 +351,7 @@ public class DaprClientHttpTest {
.respond("1.5");
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
Mono<Double> mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", null, double.class);
Mono<Double> mono = daprClientHttp.invokeBinding("sample-topic", "myoperation", "", map, double.class);
assertEquals(1.5, mono.block(), 0.0001);
}
@ -348,7 +415,7 @@ public class DaprClientHttpTest {
assertEquals(1, (int)mono.block());
}
@Test(expected = IllegalArgumentException.class)
@Test
public void invokeBindingNullName() {
Map<String, String> map = new HashMap<>();
mockInterceptor.addRule()
@ -356,11 +423,11 @@ public class DaprClientHttpTest {
.respond(EXPECTED_RESULT);
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
Mono<Void> mono = daprClientHttp.invokeBinding(null, "myoperation", "");
assertNull(mono.block());
assertThrowsDaprException(IllegalArgumentException.class, () ->
daprClientHttp.invokeBinding(null, "myoperation", "").block());
}
@Test(expected = IllegalArgumentException.class)
@Test
public void invokeBindingNullOpName() {
Map<String, String> map = new HashMap<>();
mockInterceptor.addRule()
@ -368,8 +435,8 @@ public class DaprClientHttpTest {
.respond(EXPECTED_RESULT);
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
Mono<Void> mono = daprClientHttp.invokeBinding("sample-topic", null, "");
assertNull(mono.block());
assertThrowsDaprException(IllegalArgumentException.class, () ->
daprClientHttp.invokeBinding("sample-topic", null, "").block());
}
@Test
@ -384,6 +451,37 @@ public class DaprClientHttpTest {
// No exception is thrown because did not call block() on mono above.
}
@Test
public void getStatesErrors() {
mockInterceptor.addRule()
.post("http://127.0.0.1:3000/v1.0/state/MyStateStore/bulk")
.respond("NOT VALID JSON");
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.getStates(STATE_STORE_NAME, null, String.class).block();
});
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.getStates(STATE_STORE_NAME, new ArrayList<>(), String.class).block();
});
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.getStates(null, Arrays.asList("100", "200"), String.class).block();
});
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.getStates("", Arrays.asList("100", "200"), String.class).block();
});
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.getStates(
new GetStatesRequestBuilder(STATE_STORE_NAME, "100").withParallelism(-1).build(),
TypeRef.get(String.class)).block();
});
assertThrowsDaprException(JsonParseException.class, () -> {
daprClientHttp.getStates(
new GetStatesRequestBuilder(STATE_STORE_NAME, "100").build(),
TypeRef.get(String.class)).block();
});
}
@Test
public void getStatesString() {
mockInterceptor.addRule()
@ -504,14 +602,31 @@ public class DaprClientHttpTest {
StateOptions stateOptions = mock(StateOptions.class);
State<String> stateKeyValue = new State<>("value", "key", "etag", stateOptions);
State<String> stateKeyNull = new State<>("value", null, "etag", stateOptions);
State<String> stateKeyEmpty = new State<>("value", "", "etag", stateOptions);
State<String> stateKeyBadPayload = new State<>("value", "keyBadPayload", "etag", stateOptions);
mockInterceptor.addRule()
.get("http://127.0.0.1:3000/v1.0/state/MyStateStore/key")
.respond("\"" + EXPECTED_RESULT + "\"");
.get("http://127.0.0.1:3000/v1.0/state/MyStateStore/key")
.respond("\"" + EXPECTED_RESULT + "\"");
mockInterceptor.addRule()
.get("http://127.0.0.1:3000/v1.0/state/MyStateStore/keyBadPayload")
.respond("NOT VALID");
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.getState(STATE_STORE_NAME, stateKeyNull, String.class).block();
});
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.getState(STATE_STORE_NAME, stateKeyEmpty, String.class).block();
});
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.getState(null, stateKeyValue, String.class).block();
});
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.getState("", stateKeyValue, String.class).block();
});
assertThrowsDaprException(JsonParseException.class, () -> {
daprClientHttp.getState(STATE_STORE_NAME, stateKeyBadPayload, String.class).block();
});
Mono<State<String>> mono = daprClientHttp.getState(STATE_STORE_NAME, stateKeyValue, String.class);
State<String> result = mono.block();
assertNotNull(result);
@ -582,20 +697,19 @@ public class DaprClientHttpTest {
assertNull(mono.block());
}
@Test(expected = IllegalArgumentException.class)
public void saveStateNullStateStoreName() {
@Test
public void saveStatesErrors() {
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
Mono<Void> mono = daprClientHttp.saveStates(null, null);
assertNull(mono.block());
assertThrowsDaprException(IllegalArgumentException.class, () ->
daprClientHttp.saveStates(null, null).block());
assertThrowsDaprException(IllegalArgumentException.class, () ->
daprClientHttp.saveStates("", null).block());
}
@Test
public void saveStatesNull() {
List<State<?>> stateKeyValueList = new ArrayList<>();
mockInterceptor.addRule()
.post("http://127.0.0.1:3000/v1.0/state/MyStateStore")
.respond(EXPECTED_RESULT);
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
Mono<Void> mono = daprClientHttp.saveStates(STATE_STORE_NAME, null);
@ -604,6 +718,19 @@ public class DaprClientHttpTest {
assertNull(mono1.block());
}
@Test
public void saveStatesNullState() {
List<State<?>> stateKeyValueList = new ArrayList<>();
stateKeyValueList.add(null);
mockInterceptor.addRule()
.post("http://127.0.0.1:3000/v1.0/state/MyStateStore")
.respond(EXPECTED_RESULT);
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
Mono<Void> mono1 = daprClientHttp.saveStates(STATE_STORE_NAME, stateKeyValueList);
assertNull(mono1.block());
}
@Test
public void saveStatesEtagNull() {
State<String> stateKeyValue = new State<>("value", "key", null, null);
@ -678,14 +805,94 @@ public class DaprClientHttpTest {
assertNull(mono.block());
}
@Test(expected = IllegalArgumentException.class)
public void executeTransactionNullStateStoreName() {
@Test
public void simpleExecuteTransactionNullEtag() {
mockInterceptor.addRule()
.post("http://127.0.0.1:3000/v1.0/state/MyStateStore/transaction")
.respond(EXPECTED_RESULT);
String etag = null;
String key = "key1";
String data = "my data";
StateOptions stateOptions = mock(StateOptions.class);
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
Mono<Void> mono = daprClientHttp.executeTransaction(null, null);
State<String> stateKey = new State<>(data, key, etag, stateOptions);
TransactionalStateOperation<String> upsertOperation = new TransactionalStateOperation<>(
TransactionalStateOperation.OperationType.UPSERT,
stateKey);
TransactionalStateOperation<String> deleteOperation = new TransactionalStateOperation<>(
TransactionalStateOperation.OperationType.DELETE,
new State<>("deleteKey"));
Mono<Void> mono = daprClientHttp.executeTransaction(STATE_STORE_NAME, Arrays.asList(upsertOperation,
deleteOperation));
assertNull(mono.block());
}
@Test
public void simpleExecuteTransactionEmptyEtag() {
mockInterceptor.addRule()
.post("http://127.0.0.1:3000/v1.0/state/MyStateStore/transaction")
.respond(EXPECTED_RESULT);
String etag = "empty";
String key = "key1";
String data = "my data";
StateOptions stateOptions = mock(StateOptions.class);
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
State<String> stateKey = new State<>(data, key, etag, stateOptions);
TransactionalStateOperation<String> upsertOperation = new TransactionalStateOperation<>(
TransactionalStateOperation.OperationType.UPSERT,
stateKey);
TransactionalStateOperation<String> deleteOperation = new TransactionalStateOperation<>(
TransactionalStateOperation.OperationType.DELETE,
new State<>("deleteKey"));
Mono<Void> mono = daprClientHttp.executeTransaction(STATE_STORE_NAME, Arrays.asList(upsertOperation,
deleteOperation));
assertNull(mono.block());
}
@Test
public void simpleExecuteTransactionNullOperationAndNullState() {
mockInterceptor.addRule()
.post("http://127.0.0.1:3000/v1.0/state/MyStateStore/transaction")
.respond(EXPECTED_RESULT);
String etag = null;
String key = "key1";
String data = "my data";
StateOptions stateOptions = mock(StateOptions.class);
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
State<String> stateKey = new State<>(data, key, etag, stateOptions);
TransactionalStateOperation<String> upsertOperation = new TransactionalStateOperation<>(
TransactionalStateOperation.OperationType.UPSERT,
stateKey);
TransactionalStateOperation<String> deleteOperation = new TransactionalStateOperation<>(
TransactionalStateOperation.OperationType.DELETE,
new State<>("deleteKey"));
TransactionalStateOperation<String> nullStateOperation = new TransactionalStateOperation<>(
TransactionalStateOperation.OperationType.DELETE,
null);
Mono<Void> mono = daprClientHttp.executeTransaction(STATE_STORE_NAME, Arrays.asList(
null,
nullStateOperation,
upsertOperation,
deleteOperation));
assertNull(mono.block());
}
@Test
public void executeTransactionErrors() {
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
assertThrowsDaprException(IllegalArgumentException.class, () ->
daprClientHttp.executeTransaction(null, null).block());
assertThrowsDaprException(IllegalArgumentException.class, () ->
daprClientHttp.executeTransaction("", null).block());
}
@Test
public void simpleExecuteTransactionNull() {
mockInterceptor.addRule()
@ -699,10 +906,6 @@ public class DaprClientHttpTest {
assertNull(mono.block());
}
/*
*/
@Test
public void deleteState() {
StateOptions stateOptions = mock(StateOptions.class);
@ -779,22 +982,22 @@ public class DaprClientHttpTest {
.respond(EXPECTED_RESULT);
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.deleteState(STATE_STORE_NAME, null, null, null).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.deleteState(STATE_STORE_NAME, "", null, null).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.deleteState(STATE_STORE_NAME, " ", null, null).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.deleteState(null, "key", null, null).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.deleteState("", "key", null, null).block();
});
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.deleteState(" ", "key", null, null).block();
});
}
@ -806,7 +1009,7 @@ public class DaprClientHttpTest {
.respond("{ \"mysecretkey\": \"mysecretvalue\"}");
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.getSecret(SECRET_STORE_NAME, null).block();
});
Map<String, String> secret = daprClientHttp.getSecret(SECRET_STORE_NAME, "key").block();
@ -822,7 +1025,7 @@ public class DaprClientHttpTest {
.respond("");
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
assertThrows(IllegalArgumentException.class, () -> {
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.getSecret(SECRET_STORE_NAME, null).block();
});
Map<String, String> secret = daprClientHttp.getSecret(SECRET_STORE_NAME, "key").block();
@ -833,20 +1036,50 @@ public class DaprClientHttpTest {
@Test
public void getSecrets404() {
mockInterceptor.addRule()
.get("http://127.0.0.1:3000/v1.0/secrets/MySecretStore/key")
.respond(404);
.get("http://127.0.0.1:3000/v1.0/secrets/MySecretStore/key")
.respond(404);
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
assertThrows(IllegalStateException.class, () -> {
daprClientHttp.getSecret(SECRET_STORE_NAME, "key").block();
});
assertThrowsDaprException("UNKNOWN", () ->
daprClientHttp.getSecret(SECRET_STORE_NAME, "key").block()
);
}
@Test(expected = IllegalArgumentException.class)
public void getSecretsNullStoreName() {
@Test
public void getSecrets404WithErrorCode() {
mockInterceptor.addRule()
.get("http://127.0.0.1:3000/v1.0/secrets/MySecretStore/key")
.respond(404,
ResponseBody.create("" +
"{\"errorCode\":\"ERR_SECRET_STORE_NOT_FOUND\"," +
"\"message\":\"error message\"}", MediaTypes.MEDIATYPE_JSON));
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
daprClientHttp.getSecret(null, "key").block();
assertThrowsDaprException("ERR_SECRET_STORE_NOT_FOUND", "ERR_SECRET_STORE_NOT_FOUND: error message", () ->
daprClientHttp.getSecret(SECRET_STORE_NAME, "key").block()
);
}
@Test
public void getSecretsErrors() {
mockInterceptor.addRule()
.get("http://127.0.0.1:3000/v1.0/secrets/MySecretStore/key")
.respond("INVALID JSON");
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
assertThrowsDaprException(IllegalArgumentException.class, () ->
daprClientHttp.getSecret(null, "key").block());
assertThrowsDaprException(IllegalArgumentException.class, () ->
daprClientHttp.getSecret("", "key").block());
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.getSecret(SECRET_STORE_NAME, null).block();
});
assertThrowsDaprException(IllegalArgumentException.class, () -> {
daprClientHttp.getSecret(SECRET_STORE_NAME, "").block();
});
assertThrowsDaprException(JsonParseException.class, () -> {
daprClientHttp.getSecret(SECRET_STORE_NAME, "key").block();
});
}
@Test
@ -859,10 +1092,6 @@ public class DaprClientHttpTest {
.respond("{ \"mysecretkey2\": \"mysecretvalue2\"}");
daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient);
daprClientHttp = new DaprClientHttp(daprHttp);
assertThrows(IllegalArgumentException.class, () -> {
daprClientHttp.getSecret(SECRET_STORE_NAME, null).block();
});
{
Map<String, String> secret = daprClientHttp.getSecret(
SECRET_STORE_NAME,
@ -884,6 +1113,26 @@ public class DaprClientHttpTest {
}
}
@Test
public void closeException() {
DaprHttp daprHttp = Mockito.mock(DaprHttp.class);
Mockito.doThrow(new IllegalStateException()).when(daprHttp).close();
// This method does not throw DaprException because IOException is expected by the Closeable interface.
daprClientHttp = new DaprClientHttp(daprHttp);
assertThrowsDaprException(IllegalStateException.class, () -> daprClientHttp.close());
}
@Test
public void close() {
DaprHttp daprHttp = Mockito.mock(DaprHttp.class);
Mockito.doNothing().when(daprHttp).close();
// This method does not throw DaprException because IOException is expected by the Closeable interface.
daprClientHttp = new DaprClientHttp(daprHttp);
daprClientHttp.close();
}
public static class MyObject {
private Integer id;
private String value;

View File

@ -57,6 +57,6 @@ public class DaprHttpStub extends DaprHttp {
* {@inheritDoc}
*/
@Override
public void close() throws IOException {
public void close() {
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*/
package io.dapr.utils;
import io.dapr.exceptions.DaprException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.function.Executable;
public final class TestUtils {
private TestUtils() {}
public static <T extends Throwable> void assertThrowsDaprException(Class<T> expectedType, Executable executable) {
Throwable cause = Assertions.assertThrows(DaprException.class, executable).getCause();
Assertions.assertNotNull(cause);
Assertions.assertEquals(expectedType, cause.getClass());
}
public static void assertThrowsDaprException(String expectedErrorCode, Executable executable) {
DaprException daprException = Assertions.assertThrows(DaprException.class, executable);
Assertions.assertNull(daprException.getCause());
Assertions.assertEquals(expectedErrorCode, daprException.getErrorCode());
}
public static void assertThrowsDaprException(
String expectedErrorCode,
String expectedErrorMessage,
Executable executable) {
DaprException daprException = Assertions.assertThrows(DaprException.class, executable);
Assertions.assertNull(daprException.getCause());
Assertions.assertEquals(expectedErrorCode, daprException.getErrorCode());
Assertions.assertEquals(expectedErrorMessage, daprException.getMessage());
}
public static <T extends Throwable> void assertThrowsDaprException(
Class<T> expectedType,
String expectedErrorCode,
String expectedErrorMessage,
Executable executable) {
DaprException daprException = Assertions.assertThrows(DaprException.class, executable);
Assertions.assertNotNull(daprException.getCause());
Assertions.assertEquals(expectedType, daprException.getCause().getClass());
Assertions.assertEquals(expectedErrorCode, daprException.getErrorCode());
Assertions.assertEquals(expectedErrorMessage, daprException.getMessage());
}
}