clazz) throws IOException {
// Not string, not primitive, not byte[], so it is a complex type: we use JSON for that.
if (value instanceof byte[]) {
+ if (((byte[]) value).length==0) {
+ return null;
+ }
return OBJECT_MAPPER.readValue((byte[]) value, clazz);
}
diff --git a/sdk/src/test/java/io/dapr/it/BaseIT.java b/sdk/src/test/java/io/dapr/it/BaseIT.java
new file mode 100644
index 0000000000..bea550d901
--- /dev/null
+++ b/sdk/src/test/java/io/dapr/it/BaseIT.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) Microsoft Corporation.
+ * Licensed under the MIT License.
+ */
+
+package io.dapr.it;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.contrib.java.lang.system.EnvironmentVariables;
+
+import java.util.Optional;
+
+import static io.dapr.it.DaprIntegrationTestingRunner.DAPR_FREEPORTS;
+
+public class BaseIT {
+
+ protected static DaprIntegrationTestingRunner daprIntegrationTestingRunner;
+
+
+ @ClassRule
+ public static final EnvironmentVariables environmentVariables = new EnvironmentVariables();
+
+ @BeforeClass
+ public static void setEnvironmentVariables(){
+ environmentVariables.set("DAPR_HTTP_PORT", String.valueOf(DAPR_FREEPORTS.getHttpPort()));
+ }
+
+ public static DaprIntegrationTestingRunner createDaprIntegrationTestingRunner(String successMessage, Class serviceClass, Boolean useAppPort, int sleepTime) {
+ return new DaprIntegrationTestingRunner(successMessage, serviceClass, useAppPort, sleepTime);
+ }
+
+ @AfterClass
+ public static void cleanUp() {
+ Optional.ofNullable(daprIntegrationTestingRunner).ifPresent(daprRunner -> daprRunner.destroyDapr());
+ }
+
+ public static class MyData {
+
+ /// Gets or sets the value for PropertyA.
+ private String propertyA;
+
+ /// Gets or sets the value for PropertyB.
+ private String propertyB;
+
+ private MyData myData;
+
+ public String getPropertyB() {
+ return propertyB;
+ }
+
+ public void setPropertyB(String propertyB) {
+ this.propertyB = propertyB;
+ }
+
+ public String getPropertyA() {
+ return propertyA;
+ }
+
+ public void setPropertyA(String propertyA) {
+ this.propertyA = propertyA;
+ }
+
+ @Override
+ public String toString() {
+ return "MyData{" +
+ "propertyA='" + propertyA + '\'' +
+ ", propertyB='" + propertyB + '\'' +
+ '}';
+ }
+
+ public MyData getMyData() {
+ return myData;
+ }
+
+ public void setMyData(MyData myData) {
+ this.myData = myData;
+ }
+ }
+}
diff --git a/sdk/src/test/java/io/dapr/it/DaprIntegrationTestingRunner.java b/sdk/src/test/java/io/dapr/it/DaprIntegrationTestingRunner.java
new file mode 100644
index 0000000000..504b24722f
--- /dev/null
+++ b/sdk/src/test/java/io/dapr/it/DaprIntegrationTestingRunner.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) Microsoft Corporation.
+ * Licensed under the MIT License.
+ */
+
+package io.dapr.it;
+
+import org.junit.Assert;
+
+import java.io.*;
+import java.net.ServerSocket;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.concurrent.*;
+
+
+public class DaprIntegrationTestingRunner {
+
+ public static DaprIntegrationTestingRunner.DaprFreePorts DAPR_FREEPORTS;
+
+ static {
+ try {
+ DAPR_FREEPORTS = new DaprIntegrationTestingRunner.DaprFreePorts().initPorts();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private Runtime rt = Runtime.getRuntime();
+ private Process proc;
+
+ private String successMessage;
+ private Class serviceClass;
+ private Boolean useAppPort;
+ private int sleepTime;
+ private String appName;
+
+ DaprIntegrationTestingRunner(String successMessage, Class serviceClass, Boolean useAppPort, int sleepTime) {
+ this.successMessage = successMessage;
+ this.serviceClass = serviceClass;
+ this.useAppPort = useAppPort;
+ this.sleepTime = sleepTime;
+ this.generateAppName();
+ }
+
+ public DaprFreePorts initializeDapr() throws Exception {
+ String daprCommand=this.buildDaprCommand();
+ System.out.println(daprCommand);
+ proc= rt.exec(daprCommand);
+
+ final Runnable stuffToDo = new Thread(() -> {
+ try {
+ try (InputStream stdin = proc.getInputStream()) {
+ try(InputStreamReader isr = new InputStreamReader(stdin)) {
+ try (BufferedReader br = new BufferedReader(isr)){
+ String line;
+ while ((line = br.readLine()) != null) {
+ System.out.println(line);
+ if (line.contains(successMessage)) {
+ break;
+ }
+ }
+ }
+ }
+
+ }
+ } catch (IOException ex) {
+ Assert.fail(ex.getMessage());
+ }
+ });
+
+ final ExecutorService executor = Executors.newSingleThreadExecutor();
+ final Future future = executor.submit(stuffToDo);
+ executor.shutdown(); // This does not cancel the already-scheduled task.
+ future.get(1, TimeUnit.MINUTES);
+ Thread.sleep(sleepTime);
+ return DAPR_FREEPORTS;
+ }
+
+ private static final String DAPR_RUN = "dapr run --app-id %s ";
+ private static final String DAPR_COMMAND = " -- mvn exec:java -D exec.mainClass=%s -D exec.classpathScope=\"test\" -Dexec.args=\"-p %d -grpcPort %d -httpPort %d\"";
+
+ private String buildDaprCommand(){
+ StringBuilder stringBuilder= new StringBuilder(String.format(DAPR_RUN, this.appName))
+ .append(this.useAppPort ? "--app-port " + this.DAPR_FREEPORTS.appPort : "")
+ .append(" --grpc-port ")
+ .append(this.DAPR_FREEPORTS.grpcPort)
+ .append(" --port ")
+ .append(this.DAPR_FREEPORTS.httpPort)
+ .append(String.format(DAPR_COMMAND, this.serviceClass.getCanonicalName(),this.DAPR_FREEPORTS.appPort, this.DAPR_FREEPORTS.grpcPort, this.DAPR_FREEPORTS.httpPort));
+ return stringBuilder.toString();
+ }
+
+ private void generateAppName(){
+
+ this.appName=UUID.randomUUID().toString();
+ }
+
+ private static Integer findRandomOpenPortOnAllLocalInterfaces() throws Exception {
+ try (
+ ServerSocket socket = new ServerSocket(0)
+ ) {
+ return socket.getLocalPort();
+
+ }
+ }
+
+ public void destroyDapr() {
+ Optional.ofNullable(rt).ifPresent( runtime -> {
+ try {
+ runtime.exec("dapr stop --app-id " + this.appName);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ Optional.ofNullable(proc).ifPresent(process -> process.destroy());
+ }
+
+ public static class DaprFreePorts
+ {
+ public DaprFreePorts initPorts() throws Exception {
+ this.appPort= findRandomOpenPortOnAllLocalInterfaces();
+ this.grpcPort= findRandomOpenPortOnAllLocalInterfaces();
+ this.httpPort= findRandomOpenPortOnAllLocalInterfaces();
+ return this;
+ }
+
+ private int grpcPort;
+
+ public int getGrpcPort() {
+ return grpcPort;
+ }
+
+ public int getHttpPort() {
+ return httpPort;
+ }
+
+ public int getAppPort() {
+ return appPort;
+ }
+
+ private int httpPort;
+
+ private int appPort;
+ }
+}
diff --git a/sdk/src/test/java/io/dapr/client/DaprHttpAsyncClientIT.java b/sdk/src/test/java/io/dapr/it/actor/DaprHttpAsyncClientIT.java
similarity index 87%
rename from sdk/src/test/java/io/dapr/client/DaprHttpAsyncClientIT.java
rename to sdk/src/test/java/io/dapr/it/actor/DaprHttpAsyncClientIT.java
index 9b2ead69e6..d2ac154d0c 100644
--- a/sdk/src/test/java/io/dapr/client/DaprHttpAsyncClientIT.java
+++ b/sdk/src/test/java/io/dapr/it/actor/DaprHttpAsyncClientIT.java
@@ -2,9 +2,12 @@
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*/
-package io.dapr.client;
+package io.dapr.it.actor;
+import io.dapr.client.DaprClient;
+import io.dapr.client.DaprClientBuilder;
import io.dapr.exceptions.DaprException;
+import io.dapr.it.BaseIT;
import org.junit.Assert;
import org.junit.Test;
@@ -13,7 +16,7 @@
*
* Requires Dapr running.
*/
-public class DaprHttpAsyncClientIT {
+public class DaprHttpAsyncClientIT extends BaseIT {
/**
* Checks if the error is correctly parsed when trying to invoke a function on
diff --git a/sdk/src/test/java/io/dapr/it/services/EmptyService.java b/sdk/src/test/java/io/dapr/it/services/EmptyService.java
new file mode 100644
index 0000000000..9f6f6ecee0
--- /dev/null
+++ b/sdk/src/test/java/io/dapr/it/services/EmptyService.java
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) Microsoft Corporation.
+ * Licensed under the MIT License.
+ */
+
+package io.dapr.it.services;
+
+/**
+ * Use this class in order to run DAPR with any needed services, like states.
+ */
+public class EmptyService {
+ public static void main(String[] args) {
+
+ }
+}
diff --git a/sdk/src/test/java/io/dapr/it/services/HelloWorldGrpcStateService.java b/sdk/src/test/java/io/dapr/it/services/HelloWorldGrpcStateService.java
new file mode 100644
index 0000000000..cc8cf63a01
--- /dev/null
+++ b/sdk/src/test/java/io/dapr/it/services/HelloWorldGrpcStateService.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) Microsoft Corporation.
+ * Licensed under the MIT License.
+ */
+
+package io.dapr.it.services;
+
+import com.google.protobuf.Any;
+import com.google.protobuf.ByteString;
+import io.dapr.DaprGrpc;
+import io.dapr.DaprGrpc.DaprBlockingStub;
+import io.dapr.DaprProtos.SaveStateEnvelope;
+import io.dapr.DaprProtos.StateRequest;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import org.apache.commons.cli.*;
+
+
+/**
+ * Simple example, to run:
+ * mvn clean install
+ * dapr run --grpc-port 50001 -- mvn exec:java -pl=examples -Dexec.mainClass=io.dapr.examples.Example
+ */
+public class HelloWorldGrpcStateService {
+
+ public static void main(String[] args) throws ParseException {
+ Options options = new Options();
+ options.addRequiredOption("grpcPort", "grpcPort", true, "Dapr GRPC.");
+ options.addRequiredOption("httpPort", "httpPort", true, "Dapr HTTP port.");
+ options.addRequiredOption("p", "port", true, "Port Dapr will listen to.");
+
+ CommandLineParser parser = new DefaultParser();
+ CommandLine cmd = parser.parse(options, args);
+
+ // If port string is not valid, it will throw an exception.
+ int port = Integer.parseInt(cmd.getOptionValue("grpcPort"));
+ ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", port).usePlaintext().build();
+ DaprBlockingStub client = DaprGrpc.newBlockingStub(channel);
+
+ String key = "mykey";
+ // First, write key-value pair.
+
+ String value = "Hello World";
+ StateRequest req = StateRequest
+ .newBuilder()
+ .setKey(key)
+ .setValue(Any.newBuilder().setValue(ByteString.copyFromUtf8(value)).build())
+ .build();
+ SaveStateEnvelope state = SaveStateEnvelope.newBuilder()
+ .addRequests(req)
+ .build();
+ client.saveState(state);
+ System.out.println("Saved!");
+ channel.shutdown();
+ }
+}
diff --git a/sdk/src/test/java/io/dapr/it/state/HelloWorldClientIT.java b/sdk/src/test/java/io/dapr/it/state/HelloWorldClientIT.java
new file mode 100644
index 0000000000..637e692c4a
--- /dev/null
+++ b/sdk/src/test/java/io/dapr/it/state/HelloWorldClientIT.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) Microsoft Corporation.
+ * Licensed under the MIT License.
+ */
+
+package io.dapr.it.state;
+
+import io.dapr.DaprGrpc;
+import io.dapr.DaprProtos;
+import io.dapr.it.BaseIT;
+import io.dapr.it.DaprIntegrationTestingRunner;
+import io.dapr.it.services.HelloWorldGrpcStateService;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static io.dapr.it.DaprIntegrationTestingRunner.DAPR_FREEPORTS;
+
+public class HelloWorldClientIT extends BaseIT {
+
+ private static DaprIntegrationTestingRunner daprIntegrationTestingRunner;
+
+ @BeforeClass
+ public static void init() throws Exception {
+ daprIntegrationTestingRunner =
+ createDaprIntegrationTestingRunner(
+ "BUILD SUCCESS",
+ HelloWorldGrpcStateService.class,
+ false,
+ 2000
+ );
+ daprIntegrationTestingRunner.initializeDapr();
+ }
+
+ @Test
+ public void testHelloWorldState(){
+ ManagedChannel channel =
+ ManagedChannelBuilder.forAddress("localhost", DAPR_FREEPORTS.getGrpcPort()).usePlaintext().build();
+ DaprGrpc.DaprBlockingStub client = DaprGrpc.newBlockingStub(channel);
+
+ String key = "mykey";
+ {
+ DaprProtos.GetStateEnvelope req = DaprProtos.GetStateEnvelope
+ .newBuilder()
+ .setKey(key)
+ .build();
+ DaprProtos.GetStateResponseEnvelope response = client.getState(req);
+ String value = response.getData().getValue().toStringUtf8();
+ System.out.println("Got: " + value);
+ Assert.assertEquals("Hello World",value);
+ }
+
+ // Then, delete it.
+ {
+ DaprProtos.DeleteStateEnvelope req = DaprProtos.DeleteStateEnvelope
+ .newBuilder()
+ .setKey(key)
+ .build();
+ client.deleteState(req);
+ System.out.println("Deleted!");
+ }
+
+ {
+ DaprProtos.GetStateEnvelope req = DaprProtos.GetStateEnvelope
+ .newBuilder()
+ .setKey(key)
+ .build();
+ DaprProtos.GetStateResponseEnvelope response = client.getState(req);
+ String value = response.getData().getValue().toStringUtf8();
+ System.out.println("Got: " + value);
+ Assert.assertEquals("",value);
+ }
+ }
+}
diff --git a/sdk/src/test/java/io/dapr/it/state/HttpStateClientIT.java b/sdk/src/test/java/io/dapr/it/state/HttpStateClientIT.java
new file mode 100644
index 0000000000..454c01164a
--- /dev/null
+++ b/sdk/src/test/java/io/dapr/it/state/HttpStateClientIT.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) Microsoft Corporation.
+ * Licensed under the MIT License.
+ */
+
+package io.dapr.it.state;
+
+import io.dapr.client.DaprClient;
+import io.dapr.client.DaprClientBuilder;
+import io.dapr.client.domain.StateKeyValue;
+import io.dapr.it.BaseIT;
+import io.dapr.it.services.EmptyService;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import reactor.core.publisher.Mono;
+
+/**
+ * Test State HTTP DAPR capabilities using a DAPR instance with an empty service running
+ */
+public class HttpStateClientIT extends BaseIT {
+
+ @BeforeClass
+ public static void init() throws Exception {
+ daprIntegrationTestingRunner =
+ createDaprIntegrationTestingRunner(
+ "BUILD SUCCESS",
+ EmptyService.class,
+ false,
+ 0
+ );
+ daprIntegrationTestingRunner.initializeDapr();
+ }
+
+ @Test
+ public void saveAndGetState() {
+
+ final String stateKey= "myKey";
+
+ DaprClient daprClient= new DaprClientBuilder().build();
+ MyData data= new MyData();
+ data.setPropertyA("data in property A");
+ data.setPropertyB("data in property B");
+ Mono saveResponse= daprClient.saveState(stateKey,null,data, null);
+ saveResponse.block();
+
+ Mono> response= daprClient.getState( new StateKeyValue(null,stateKey,null),null,MyData.class);
+ StateKeyValue myDataResponse=response.block();
+
+ Assert.assertEquals("data in property A",myDataResponse.getValue().getPropertyA());
+ Assert.assertEquals("data in property B",myDataResponse.getValue().getPropertyB());
+ }
+
+ @Test
+ public void saveUpdateAndGetState() {
+ final String stateKey= "keyToBeUpdated";
+
+ DaprClient daprClient= new DaprClientBuilder().build();
+ MyData data= new MyData();
+ data.setPropertyA("data in property A");
+ data.setPropertyB("data in property B");
+ Mono saveResponse= daprClient.saveState(stateKey,null,data, null);
+ saveResponse.block();
+
+ data.setPropertyA("data in property A");
+ data.setPropertyB("data in property B2");
+ saveResponse= daprClient.saveState(stateKey,null,data, null);
+ saveResponse.block();
+
+ Mono> response= daprClient.getState( new StateKeyValue(null,stateKey,null),null,MyData.class);
+ StateKeyValue myDataResponse=response.block();
+
+ Assert.assertEquals("data in property A",myDataResponse.getValue().getPropertyA());
+ Assert.assertEquals("data in property B2",myDataResponse.getValue().getPropertyB());
+ }
+
+ @Test
+ public void saveAndDeleteState() {
+ final String stateKey= "myeKeyToBeDeleted";
+
+ DaprClient daprClient= new DaprClientBuilder().build();
+ MyData data= new MyData();
+ data.setPropertyA("data in property A");
+ data.setPropertyB("data in property B");
+ Mono saveResponse= daprClient.saveState(stateKey,null,data, null);
+ saveResponse.block();
+
+ Mono> response= daprClient.getState( new StateKeyValue(null,stateKey,null),null,MyData.class);
+ StateKeyValue myDataResponse=response.block();
+
+ Assert.assertEquals("data in property A",myDataResponse.getValue().getPropertyA());
+ Assert.assertEquals("data in property B",myDataResponse.getValue().getPropertyB());
+
+ Mono deleteResponse= daprClient.deleteState( new StateKeyValue(null,stateKey,null),null);
+ deleteResponse.block();
+
+ response= daprClient.getState( new StateKeyValue(null,stateKey,null),null,MyData.class);
+ myDataResponse=response.block();
+
+ Assert.assertNull(myDataResponse.getValue());
+ }
+
+}