Update state, secrets examples. Fix state toString. Ignore sdk-autogen in code coverage. (#340)

* Update state, secrets example. Fix state toString. Ignore sdk-autogen in code coverage.

* Update StateClient.java

* Update README.md

* Update Readme.md

Co-authored-by: Nghia Tran <tcnghia@gmail.com>

Co-authored-by: Artur Souza <artursouza.ms@outlook.com>
Co-authored-by: Nghia Tran <tcnghia@gmail.com>
This commit is contained in:
Mukundan Sundararajan 2020-09-21 15:06:46 -07:00 committed by GitHub
parent 9240ae81db
commit fb8580f71b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 258 additions and 27 deletions

View File

@ -1,6 +1,7 @@
ignore:
- examples
- sdk-tests
- sdk-autogen
comment:
# Delete old comment and post new one for new coverage information.
behavior: new

View File

@ -17,7 +17,7 @@ jobs:
build:
runs-on: ubuntu-latest
env:
GOVER: 1.14.0
GOVER: 1.15.0
GOOS: linux
GOARCH: amd64
GOPROXY: https://proxy.golang.org

View File

@ -41,7 +41,7 @@ mvn install
```
### Setting Vault locally
Before getting into the application code, follow these steps in order to setup a local instance of Vault. This is needed for the local instances. Steps are:
Before getting into the application code, follow these steps in order to set up a local instance of Vault. This is needed for the local instances. Steps are:
1. navigate to the [examples] with `cd examples`
2. Run `docker-compose -f ./src/main/java/io/dapr/examples/secrets/docker-compose-vault.yml up -d` to run the container locally
@ -61,18 +61,23 @@ Dapr's API for secret store only support read operations. For this sample to run
vault login myroot
```
> Note: If you get `http: server gave HTTP response to HTTPS client` make sure the local vault address is set `export VAULT_ADDR=http://127.0.0.1:8200/`
> Note: If you get `http: server gave HTTP response to HTTPS client` make sure to set the local vault address as `export VAULT_ADDR=http://127.0.0.1:8200/`
2. Create secret (replace `[my favorite movie]` with a title of our choice):
```bash
vault kv put secret/dapr/movie title="[my favorite movie]"
```
3. Create random secret:
```bash
vault kv put secret/dapr/randomKey testVal="value"
```
In the command above, `secret` means the secret engine in Hashicorp's Vault.
Then, `dapr` is the prefix as defined in `< repo dir >/examples/components/hashicorp_vault.yaml`.
Finally, `movie` is the secret name and then a `key=value` pair.
Finally, `movie` and `randomKey` are the secret names with the value set in the form of `key=value` pair.
A secret in dapr is a dictionary. In this sample, only one key-value pair is used but more can be added as an exercise for the reader.
A secret in Dapr is a dictionary.
### Running the secret store sample
@ -101,6 +106,13 @@ public class SecretClient {
try (DaprClient client = (new DaprClientBuilder()).build()) {
Map<String, String> secret = client.getSecret(SECRET_STORE_NAME, secretKey).block();
System.out.println(JSON_SERIALIZER.writeValueAsString(secret));
try {
secret = client.getSecret(SECRET_STORE_NAME, "randomKey").block();
System.out.println(JSON_SERIALIZER.writeValueAsString(secret));
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}
///...
@ -111,7 +123,7 @@ After identifying the key to be fetched, it will retrieve it from the pre-define
The secret store's name **must** match the component's name defined in `< repo dir >/examples/components/hashicorp_vault.yaml`.
The Dapr client is also within a try-with-resource block to properly close the client at the end.
Execute the follow script in order to run the example:
Execute the following script in order to run the example:
```sh
cd to [repo-root]/examples
dapr run --components-path ./components -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.secrets.SecretClient movie
@ -121,11 +133,44 @@ Once running, the program should print the output as follows:
```
== APP == {"title":"[my favorite movie]"}
== APP == {"testVal":"value"}
```
To close the app, press CTRL+c.
To cleanup and bring the vault container down, run
The example's `config.yaml` is as follows:
```yaml
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: daprConfig
spec:
secrets:
scopes:
- storeName: "vault"
defaultAccess: "deny"
allowedSecrets: ["movie",]
```
The configuration defines, that the only allowed secret is `movie` and all other secrets are denied.
Execute the following script in order to run this example with additional secret scoping:
```sh
cd to [repo-root]/examples
dapr run --components-path ./components --config ./src/main/java/io/dapr/examples/secrets/config.yaml -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.secrets.SecretClient movie
```
Once running, the program should print the output as follows:
```
== APP == {"title":"[my favorite movie]"}
== APP == java.util.concurrent.ExecutionException: io.grpc.StatusRuntimeException: PERMISSION_DENIED: Access denied by policy to get randomKey from vault
```
To close the app, press CTRL+c.
To clean up and bring the vault container down, run
```sh
docker-compose -f ./src/main/java/io/dapr/examples/secrets/docker-compose-vault.yml down
```

View File

@ -48,6 +48,13 @@ public class SecretClient {
try (DaprClient client = (new DaprClientBuilder()).build()) {
Map<String, String> secret = client.getSecret(SECRET_STORE_NAME, secretKey).block();
System.out.println(JSON_SERIALIZER.writeValueAsString(secret));
try {
secret = client.getSecret(SECRET_STORE_NAME, "randomKey").block();
System.out.println(JSON_SERIALIZER.writeValueAsString(secret));
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}
}

View File

@ -0,0 +1,10 @@
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: daprConfig
spec:
secrets:
scopes:
- storeName: "vault"
defaultAccess: "deny"
allowedSecrets: ["movie",]

View File

@ -37,7 +37,9 @@ public class StateClient {
///...
private static final String STATE_STORE_NAME = "statestore";
private static final String KEY_NAME = "mykey";
private static final String FIRST_KEY_NAME = "myKey";
private static final String SECOND_KEY_NAME = "myKey2";
///...
public static void main(String[] args) throws IOException {
try (DaprClient client = new DaprClientBuilder().build()) {
@ -45,19 +47,51 @@ public class StateClient {
MyClass myClass = new MyClass();
myClass.message = message;
MyClass secondState = new MyClass();
secondState.message = "test message";
client.saveState(STATE_STORE_NAME, KEY_NAME, myClass).block();
client.saveState(STATE_STORE_NAME, FIRST_KEY_NAME, myClass).block();
System.out.println("Saving class with message: " + message);
Mono<State<MyClass>> retrievedMessageMono = client.getState(STATE_STORE_NAME, KEY_NAME, MyClass.class);
Mono<State<MyClass>> retrievedMessageMono = client.getState(STATE_STORE_NAME, FIRST_KEY_NAME, MyClass.class);
System.out.println("Retrieved class message from state: " + (retrievedMessageMono.block().getValue()).message);
System.out.println("Deleting state...");
Mono<Void> mono = client.deleteState(STATE_STORE_NAME, KEY_NAME);
System.out.println("Updating previous state and adding another state 'test state'... ");
myClass.message = message + " updated";
System.out.println("Saving updated class with message: " + myClass.message);
// execute transaction
List<TransactionalStateOperation<?>> operationList = new ArrayList<>();
operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT,
new State<>(myClass, FIRST_KEY_NAME, "")));
operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT,
new State<>(secondState, SECOND_KEY_NAME, "")));
client.executeTransaction(STATE_STORE_NAME, operationList).block();
// get multiple states
Mono<List<State<MyClass>>> retrievedMessagesMono = client.getStates(STATE_STORE_NAME,
Arrays.asList(FIRST_KEY_NAME, SECOND_KEY_NAME), MyClass.class);
System.out.println("Retrieved messages using bulk get:");
retrievedMessagesMono.block().forEach(System.out::println);
System.out.println("Deleting states...");
// delete state API
Mono<Void> mono = client.deleteState(STATE_STORE_NAME, FIRST_KEY_NAME);
mono.block();
Mono<State<MyClass>> retrievedDeletedMessageMono = client.getState(STATE_STORE_NAME, KEY_NAME, MyClass.class);
System.out.println("Trying to retrieve deleted state: " + retrievedDeletedMessageMono.block().getValue());
// Delete operation using transaction API
operationList.clear();
operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.DELETE,
new State<>(SECOND_KEY_NAME)));
mono = client.executeTransaction(STATE_STORE_NAME, operationList);
mono.block();
Mono<List<State<MyClass>>> retrievedDeletedMessageMono = client.getStates(STATE_STORE_NAME,
Arrays.asList(FIRST_KEY_NAME, SECOND_KEY_NAME), MyClass.class);
System.out.println("Trying to retrieve deleted states: ");
retrievedDeletedMessageMono.block().forEach(System.out::println);
// This is an example, so for simplicity we are just exiting here.
// Normally a dapr app would be a web service and not exit main.
@ -66,7 +100,19 @@ public class StateClient {
}
}
```
The code uses the `DaprClient` created by the `DaprClientBuilder`. Notice that this builder uses default settings. Internally, it is using `DefaultObjectSerializer` for two properties: `objectSerializer` is for Dapr's sent and received objects, and `stateSerializer` is for objects to be persisted. This client performs three operations: `client.saveState(...)` for persisting an instance of `MyClass`, then uses the `client.getState(...)` operation in order to retrieve back the persisted state using the same key. `client.deleteState(...)` operation is used to remove the persisted state. Finally, the code tries to retrieve the deleted state, which should not be found. The Dapr client is also within a try-with-resource block to properly close the client at the end.
The code uses the `DaprClient` created by the `DaprClientBuilder`. Notice that this builder uses default settings. Internally, it is using `DefaultObjectSerializer` for two properties: `objectSerializer` is for Dapr's sent and received objects, and `stateSerializer` is for objects to be persisted.
This example performs multiple operations:
* `client.saveState(...)` for persisting an instance of `MyClass`.
* `client.getState(...)` operation in order to retrieve back the persisted state using the same key.
* `client.executeTransaction(...)` operation in order to update existing state and add new state.
* `client.getStates(...)` operation in order to retrieve back the persisted states using the same keys.
* `client.deleteState(...)` operation to remove one of the persisted states.
* `client.executeTransaction(...)` operation in order to remove the other persisted state.
Finally, the code tries to retrieve the deleted states, which should not be found.
The Dapr client is also within a try-with-resource block to properly close the client at the end.
### Running the example

View File

@ -8,9 +8,13 @@ package io.dapr.examples.state;
import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;
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;
/**
* 1. Build and install jars:
@ -24,11 +28,18 @@ public class StateClient {
public static class MyClass {
public String message;
@Override
public String toString() {
return message;
}
}
private static final String STATE_STORE_NAME = "statestore";
private static final String KEY_NAME = "myKey";
private static final String FIRST_KEY_NAME = "myKey";
private static final String SECOND_KEY_NAME = "myKey2";
/**
* Executes the sate actions.
@ -40,19 +51,51 @@ public class StateClient {
MyClass myClass = new MyClass();
myClass.message = message;
MyClass secondState = new MyClass();
secondState.message = "test message";
client.saveState(STATE_STORE_NAME, KEY_NAME, myClass).block();
client.saveState(STATE_STORE_NAME, FIRST_KEY_NAME, myClass).block();
System.out.println("Saving class with message: " + message);
Mono<State<MyClass>> retrievedMessageMono = client.getState(STATE_STORE_NAME, KEY_NAME, MyClass.class);
Mono<State<MyClass>> retrievedMessageMono = client.getState(STATE_STORE_NAME, FIRST_KEY_NAME, MyClass.class);
System.out.println("Retrieved class message from state: " + (retrievedMessageMono.block().getValue()).message);
System.out.println("Deleting state...");
Mono<Void> mono = client.deleteState(STATE_STORE_NAME, KEY_NAME);
System.out.println("Updating previous state and adding another state 'test state'... ");
myClass.message = message + " updated";
System.out.println("Saving updated class with message: " + myClass.message);
// execute transaction
List<TransactionalStateOperation<?>> operationList = new ArrayList<>();
operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT,
new State<>(myClass, FIRST_KEY_NAME, "")));
operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT,
new State<>(secondState, SECOND_KEY_NAME, "")));
client.executeTransaction(STATE_STORE_NAME, operationList).block();
// get multiple states
Mono<List<State<MyClass>>> retrievedMessagesMono = client.getStates(STATE_STORE_NAME,
Arrays.asList(FIRST_KEY_NAME, SECOND_KEY_NAME), MyClass.class);
System.out.println("Retrieved messages using bulk get:");
retrievedMessagesMono.block().forEach(System.out::println);
System.out.println("Deleting states...");
// delete state API
Mono<Void> mono = client.deleteState(STATE_STORE_NAME, FIRST_KEY_NAME);
mono.block();
Mono<State<MyClass>> retrievedDeletedMessageMono = client.getState(STATE_STORE_NAME, KEY_NAME, MyClass.class);
System.out.println("Trying to retrieve deleted state: " + retrievedDeletedMessageMono.block().getValue());
// Delete operation using transaction API
operationList.clear();
operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.DELETE,
new State<>(SECOND_KEY_NAME)));
mono = client.executeTransaction(STATE_STORE_NAME, operationList);
mono.block();
Mono<List<State<MyClass>>> retrievedDeletedMessageMono = client.getStates(STATE_STORE_NAME,
Arrays.asList(FIRST_KEY_NAME, SECOND_KEY_NAME), MyClass.class);
System.out.println("Trying to retrieve deleted states: ");
retrievedDeletedMessageMono.block().forEach(System.out::println);
// This is an example, so for simplicity we are just exiting here.
// Normally a dapr app would be a web service and not exit main.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 150 KiB

View File

@ -214,8 +214,8 @@ public class State<T> {
+ "value=" + value
+ ", key='" + key + "'"
+ ", etag='" + etag + "'"
+ ", etag='" + error + "'"
+ ", options={'" + (options != null ? options.toString() : null) + "}"
+ ", error='" + error + "'"
+ ", options={'" + (options != null ? options.toString() : null) + "'}"
+ "}";
}
}

View File

@ -45,6 +45,7 @@ import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertThrows;
@ -662,7 +663,9 @@ public class DaprClientGrpcTest {
State<String> keyRequest = buildStateKey(null, key, etag, null);
Mono<State<String>> result = adapter.getState(STATE_STORE_NAME, keyRequest, String.class);
settableFuture.set(responseEnvelope);
assertEquals(expectedState, result.block());
State<String> res = result.block();
assertNotNull(res);
assertEquals(expectedState, res);
}
@Test
@ -705,7 +708,9 @@ public class DaprClientGrpcTest {
.thenReturn(settableFuture);
Mono<State<MyObject>> result = adapter.getState(STATE_STORE_NAME, keyRequest, MyObject.class);
settableFuture.set(responseEnvelope);
assertEquals(expectedState, result.block());
State<MyObject> res = result.block();
assertNotNull(res);
assertEquals(expectedState, res);
}
@Test
@ -731,7 +736,9 @@ public class DaprClientGrpcTest {
.thenReturn(settableFuture);
Mono<Response<State<MyObject>>> result = adapter.getState(request, TypeRef.get(MyObject.class));
settableFuture.set(responseEnvelope);
assertEquals(expectedState, result.block().getObject());
Response<State<MyObject>> res = result.block();
assertNotNull(res);
assertEquals(expectedState, res.getObject());
}
@Test

View File

@ -0,0 +1,72 @@
package io.dapr.client.domain;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
public class StateTest {
private static final String KEY = "key";
private static final String ETAG = "111";
private static final StateOptions OPTIONS = new StateOptions(StateOptions.Consistency.STRONG,
StateOptions.Concurrency.FIRST_WRITE);
@Test
public void testSimpleStringState() {
State<String> state = new State<>("value", KEY, ETAG);
assertNotNull(state);
assertNull(state.getError());
assertNull(state.getOptions());
assertEquals(KEY, state.getKey());
assertEquals(ETAG, state.getEtag());
assertEquals("value", state.getValue());
String expected = "StateKeyValue{"
+ "value=value"
+ ", key='" + KEY + "'"
+ ", etag='" + ETAG + "'"
+ ", error='null'"
+ ", options={'null'}"
+ "}";;
assertEquals(expected, state.toString());
}
@Test
public void testStringState() {
State<String> state = new State<>(KEY, ETAG, OPTIONS);
assertNotNull(state);
assertNull(state.getError());
assertNull(state.getValue());
assertEquals(OPTIONS, state.getOptions());
assertEquals(KEY, state.getKey());
assertEquals(ETAG, state.getEtag());
String expected = "StateKeyValue{"
+ "value=null"
+ ", key='" + KEY + "'"
+ ", etag='" + ETAG + "'"
+ ", error='null'"
+ ", options={'" + OPTIONS.toString() + "'}"
+ "}";;
assertEquals(expected, state.toString());
}
@Test
public void testSimpleStringStateWithOptions() {
State<String> state = new State<>("value", KEY, ETAG, OPTIONS);
assertNotNull(state);
assertNull(state.getError());
assertEquals(OPTIONS, state.getOptions());
assertEquals(KEY, state.getKey());
assertEquals(ETAG, state.getEtag());
String expected = "StateKeyValue{"
+ "value=value"
+ ", key='" + KEY + "'"
+ ", etag='" + ETAG + "'"
+ ", error='null'"
+ ", options={'" + OPTIONS.toString() + "'}"
+ "}";;
assertEquals(expected, state.toString());
assertEquals("value", state.getValue());
}
}