diff --git a/sdk-tests/src/test/java/io/dapr/it/state/AbstractStateClientIT.java b/sdk-tests/src/test/java/io/dapr/it/state/AbstractStateClientIT.java index e0edf102d..6a3a4c93a 100644 --- a/sdk-tests/src/test/java/io/dapr/it/state/AbstractStateClientIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/state/AbstractStateClientIT.java @@ -74,13 +74,11 @@ public abstract class AbstractStateClientIT extends BaseIT { 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()); + Assert.assertNull(state.getEtag()); } @Test - public void saveAndGetBulkStates() { + public void saveAndGetBulkState() { final String stateKeyOne = UUID.randomUUID().toString(); final String stateKeyTwo = UUID.randomUUID().toString(); final String stateKeyThree = "NotFound"; @@ -114,8 +112,8 @@ public abstract class AbstractStateClientIT extends BaseIT { assertEquals(stateKeyThree, result.stream().skip(2).findFirst().get().getKey()); assertNull(result.stream().skip(2).findFirst().get().getValue()); - assertEquals("", result.stream().skip(2).findFirst().get().getEtag()); - assertNull("not found", result.stream().skip(2).findFirst().get().getError()); + assertNull(result.stream().skip(2).findFirst().get().getEtag()); + assertNull(result.stream().skip(2).findFirst().get().getError()); } @Test diff --git a/sdk/src/main/java/io/dapr/client/DaprClientGrpc.java b/sdk/src/main/java/io/dapr/client/DaprClientGrpc.java index 061008f3c..5e0ab7d28 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientGrpc.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientGrpc.java @@ -320,6 +320,9 @@ public class DaprClientGrpc extends AbstractDaprClient { byte[] data = payload == null ? null : payload.toByteArray(); T value = stateSerializer.deserialize(data, type); String etag = item.getEtag(); + if (etag.equals("")) { + etag = null; + } return new State<>(value, key, etag, item.getMetadataMap(), null); } @@ -332,6 +335,9 @@ public class DaprClientGrpc extends AbstractDaprClient { byte[] data = payload == null ? null : payload.toByteArray(); T value = stateSerializer.deserialize(data, type); String etag = response.getEtag(); + if (etag.equals("")) { + etag = null; + } return new State<>(value, requestedKey, etag, response.getMetadataMap(), stateOptions); } diff --git a/sdk/src/main/java/io/dapr/client/DaprClientHttp.java b/sdk/src/main/java/io/dapr/client/DaprClientHttp.java index d350e1796..2ee0d3721 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientHttp.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientHttp.java @@ -542,6 +542,9 @@ public class DaprClientHttp extends AbstractDaprClient { } String etag = node.path("etag").asText(); + if (etag.equals("")) { + etag = null; + } // TODO(artursouza): JSON cannot differentiate if data returned is String or byte[], it is ambiguous. // This is not a high priority since GRPC is the default (and recommended) client implementation. byte[] data = node.path("data").toString().getBytes(Properties.STRING_CHARSET.get()); diff --git a/sdk/src/test/java/io/dapr/client/DaprClientGrpcTest.java b/sdk/src/test/java/io/dapr/client/DaprClientGrpcTest.java index e9dca3872..e437e8270 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientGrpcTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientGrpcTest.java @@ -1657,6 +1657,62 @@ public class DaprClientGrpcTest { assertTrue(callbackDelete.wasCalled); } + @Test + public void getStateNullEtag() throws Exception { + String etag = null; + String key1 = "key1"; + String expectedValue1 = "Expected state 1"; + State expectedState1 = buildStateKey(expectedValue1, key1, etag, new HashMap<>(), null); + Map> futuresMap = new HashMap<>(); + DaprProtos.GetStateResponse envelope = DaprProtos.GetStateResponse.newBuilder() + .setData(serialize(expectedValue1)) + .build(); + SettableFuture settableFuture = SettableFuture.create(); + MockCallback callback = new MockCallback<>(envelope); + addCallback(settableFuture, callback, directExecutor()); + settableFuture.set(envelope); + futuresMap.put(key1, settableFuture); + when(client.getState(argThat(new GetStateRequestKeyMatcher(key1)))).thenReturn(futuresMap.get(key1)); + State keyRequest1 = buildStateKey(null, key1, null, null); + Mono> resultGet1 = adapter.getState(STATE_STORE_NAME, keyRequest1, String.class); + assertEquals(expectedState1, resultGet1.block()); + } + + @Test + public void getBulkStateNullEtag() throws Exception { + DaprProtos.GetBulkStateResponse responseEnvelope = DaprProtos.GetBulkStateResponse.newBuilder() + .addItems(DaprProtos.BulkStateItem.newBuilder() + .setData(serialize("hello world")) + .setKey("100") + .build()) + .addItems(DaprProtos.BulkStateItem.newBuilder() + .setKey("200") + .setEtag("") + .setError("not found") + .build()) + .build(); + SettableFuture settableFuture = SettableFuture.create(); + MockCallback callback = new MockCallback<>(responseEnvelope); + addCallback(settableFuture, callback, directExecutor()); + when(client.getBulkState(any(DaprProtos.GetBulkStateRequest.class))) + .thenAnswer(c -> { + settableFuture.set(responseEnvelope); + return settableFuture; + }); + List> result = adapter.getBulkState(STATE_STORE_NAME, Arrays.asList("100", "200"), String.class).block(); + assertTrue(callback.wasCalled); + + assertEquals(2, result.size()); + assertEquals("100", result.stream().findFirst().get().getKey()); + assertEquals("hello world", result.stream().findFirst().get().getValue()); + assertNull(result.stream().findFirst().get().getEtag()); + assertNull(result.stream().findFirst().get().getError()); + assertEquals("200", result.stream().skip(1).findFirst().get().getKey()); + assertNull(result.stream().skip(1).findFirst().get().getValue()); + assertNull(result.stream().skip(1).findFirst().get().getEtag()); + assertEquals("not found", result.stream().skip(1).findFirst().get().getError()); + } + @Test public void getSecrets() { String expectedKey = "attributeKey"; diff --git a/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java index 3971229ea..2bddec72d 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java @@ -640,8 +640,9 @@ public class DaprClientHttpTest { .respond("\"" + EXPECTED_RESULT + "\""); daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); daprClientHttp = new DaprClientHttp(daprHttp); - Mono> monoEmptyEtag = daprClientHttp.getState(STATE_STORE_NAME, stateEmptyEtag, String.class); - assertEquals(monoEmptyEtag.block().getKey(), "key"); + State monoEmptyEtag = daprClientHttp.getState(STATE_STORE_NAME, stateEmptyEtag, String.class).block(); + assertEquals(monoEmptyEtag.getKey(), "key"); + assertNull(monoEmptyEtag.getEtag()); } @Test @@ -667,8 +668,9 @@ public class DaprClientHttpTest { .respond("\"" + EXPECTED_RESULT + "\""); daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), 3000, okHttpClient); daprClientHttp = new DaprClientHttp(daprHttp); - Mono> monoNullEtag = daprClientHttp.getState(STATE_STORE_NAME, stateNullEtag, String.class); - assertEquals(monoNullEtag.block().getKey(), "key"); + State monoNullEtag = daprClientHttp.getState(STATE_STORE_NAME, stateNullEtag, String.class).block(); + assertEquals(monoNullEtag.getKey(), "key"); + assertNull(monoNullEtag.getEtag()); } @Test