From 02170b295c380dea08a4ccdecd887c512a31da14 Mon Sep 17 00:00:00 2001 From: artur-ciocanu Date: Sat, 7 Sep 2024 13:00:45 +0300 Subject: [PATCH 01/14] Adding Maven Profiles (#1120) * Adding Maven Profiles Signed-off-by: Artur Ciocanu * Simplify profiles setup Signed-off-by: Artur Ciocanu --------- Signed-off-by: Artur Ciocanu Co-authored-by: Artur Ciocanu Signed-off-by: salaboy --- .github/workflows/build.yml | 2 +- pom.xml | 13 +++++++++---- sdk-tests/pom.xml | 18 +++++++----------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ac3d084ee..070f163dc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -119,7 +119,7 @@ jobs: run: ./mvnw install -q -B -DskipTests - name: Integration tests using spring boot version ${{ matrix.spring-boot-version }} id: integration_tests - run: PRODUCT_SPRING_BOOT_VERSION=${{ matrix.spring-boot-version }} ./mvnw -B -f sdk-tests/pom.xml verify + run: PRODUCT_SPRING_BOOT_VERSION=${{ matrix.spring-boot-version }} ./mvnw -B -Pintegration-tests verify - name: Upload test report for sdk uses: actions/upload-artifact@v4 with: diff --git a/pom.xml b/pom.xml index 946c5f2e4..c8cf9699c 100644 --- a/pom.xml +++ b/pom.xml @@ -328,10 +328,15 @@ examples testcontainers-dapr - + + + integration-tests + + sdk-tests + + + + diff --git a/sdk-tests/pom.xml b/sdk-tests/pom.xml index 7c4997024..ce60ce241 100644 --- a/sdk-tests/pom.xml +++ b/sdk-tests/pom.xml @@ -4,9 +4,14 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 - io.dapr + + io.dapr + dapr-sdk-parent + 1.13.0-SNAPSHOT + + dapr-sdk-tests - 0.0.0-SNAPSHOT + 1.13.0-SNAPSHOT dapr-sdk-tests Tests for Dapr's Java SDK - not to be published as a jar. @@ -320,15 +325,6 @@ ${env.PRODUCT_SPRING_BOOT_VERSION} - - - - com.squareup.okhttp3 - okhttp - 4.9.0 - test - - From 47bd0f1debb7edac5b296da0ec5aa69c07ff2cb2 Mon Sep 17 00:00:00 2001 From: salaboy Date: Fri, 13 Sep 2024 13:12:11 +0100 Subject: [PATCH 02/14] initial Otel configuration Signed-off-by: salaboy --- .../it/testcontainers/DaprContainerIT.java | 18 +++++ .../io/dapr/testcontainers/Configuration.java | 45 ++++++++++++ .../io/dapr/testcontainers/DaprContainer.java | 55 ++++++++++++++ .../TracingConfigParameters.java | 72 +++++++++++++++++++ .../testcontainers/DaprComponentTest.java | 34 +++++++++ 5 files changed, 224 insertions(+) create mode 100644 testcontainers-dapr/src/main/java/io/dapr/testcontainers/Configuration.java create mode 100644 testcontainers-dapr/src/main/java/io/dapr/testcontainers/TracingConfigParameters.java diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerIT.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerIT.java index 795227041..66c8e68f3 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerIT.java @@ -20,7 +20,9 @@ import io.dapr.client.domain.State; import io.dapr.config.Properties; +import io.dapr.testcontainers.Configuration; import io.dapr.testcontainers.DaprContainer; +import io.dapr.testcontainers.TracingConfigParameters; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @@ -65,6 +67,9 @@ public class DaprContainerIT { private static final DaprContainer DAPR_CONTAINER = new DaprContainer("daprio/daprd") .withAppName("dapr-app") .withAppPort(8081) + .withConfiguration(new Configuration("my-config", + new TracingConfigParameters("1", true, + "localhost:4317", false, "grpc"))) .withAppChannelAddress("host.testcontainers.internal"); /** @@ -104,6 +109,19 @@ public void testDaprContainerDefaults() { DAPR_CONTAINER.getSubscriptions().size(), "A subscription should be configured by default if none is provided" ); + + assertEquals( + 1, + DAPR_CONTAINER.getConfigurations().size(), + "A configuration should be configured" + ); + + Configuration configuration = DAPR_CONTAINER.getConfigurations().iterator().next(); + assertEquals("1",configuration.getTracing().getSamplingRate()); + assertEquals(true,configuration.getTracing().getStdout()); + assertEquals("localhost:4317",configuration.getTracing().getOtelEndpoint()); + assertEquals("grpc",configuration.getTracing().getOtelProtocol()); + assertEquals(false,configuration.getTracing().getOtelIsSecure()); } @Test diff --git a/testcontainers-dapr/src/main/java/io/dapr/testcontainers/Configuration.java b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/Configuration.java new file mode 100644 index 000000000..5bf1ebc4b --- /dev/null +++ b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/Configuration.java @@ -0,0 +1,45 @@ +/* + * Copyright 2024 The Dapr Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and +limitations under the License. +*/ + +package io.dapr.testcontainers; + +/** + * Represents a Dapr component. + */ +public class Configuration { + private String name; + private TracingConfigParameters tracing; + + //@TODO: add httpPipeline + //@TODO: add secrets + //@TODO: add components + //@TODO: add accessControl + + /** + * Creates a new configuration. + * @param name Configuration name. + * @param tracing TracingConfigParameters tracing configuration parameters. + */ + public Configuration(String name, TracingConfigParameters tracing) { + this.name = name; + this.tracing = tracing; + } + + public String getName() { + return name; + } + + public TracingConfigParameters getTracing() { + return tracing; + } +} diff --git a/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java index 4ddbd7d6b..0ea4c67fa 100644 --- a/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java +++ b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java @@ -45,6 +45,7 @@ public class DaprContainer extends GenericContainer { .forStatusCodeMatching(statusCode -> statusCode >= 200 && statusCode <= 399); private final Set components = new HashSet<>(); + private final Set configurations = new HashSet<>(); private final Set subscriptions = new HashSet<>(); private DaprProtocol protocol = DaprProtocol.HTTP; private String appName; @@ -86,6 +87,10 @@ public Set getSubscriptions() { return subscriptions; } + public Set getConfigurations() { + return configurations; + } + public DaprContainer withAppPort(Integer port) { this.appPort = port; return this; @@ -149,6 +154,11 @@ public DaprContainer withComponent(Path path) { return this; } + public DaprContainer withConfiguration(Configuration configuration) { + configurations.add(configuration); + return this; + } + public int getHttpPort() { return getMappedPort(DAPRD_DEFAULT_HTTP_PORT); } @@ -170,6 +180,41 @@ public DaprContainer withAppChannelAddress(String appChannelAddress) { return this; } + + /** + * Get a map of Dapr component details. + * @param configuration A Dapr Configuration. + * @return Map of component details. + */ + public Map configurationToMap(Configuration configuration) { + Map configurationProps = new HashMap<>(); + configurationProps.put("apiVersion", "dapr.io/v1alpha1"); + configurationProps.put("kind", "Configuration"); + + Map configurationMetadata = new LinkedHashMap<>(); + configurationMetadata.put("name", configuration.getName()); + configurationProps.put("metadata", configurationMetadata); + + Map configurationSpec = new HashMap<>(); + + + Map configurationTracing = new HashMap<>(); + Map configurationTracingOtel = new HashMap<>(); + if (configuration.getTracing() != null) { + configurationTracing.put("samplingRate", configuration.getTracing().getSamplingRate()); + configurationTracing.put("stdout", configuration.getTracing().getStdout()); + configurationTracingOtel.put("endpointAddress", configuration.getTracing().getOtelEndpoint()); + configurationTracingOtel.put("isSecure", configuration.getTracing().getOtelIsSecure()); + configurationTracingOtel.put("protocol", configuration.getTracing().getOtelProtocol()); + } + + configurationTracing.put("otel", configurationTracingOtel); + configurationSpec.put("tracing", configurationTracing); + + configurationProps.put("spec", configurationSpec); + return Collections.unmodifiableMap(configurationProps); + } + /** * Get a map of Dapr component details. * @param component A Dapr Component. @@ -275,6 +320,11 @@ protected void configure() { withCopyToContainer(Transferable.of(componentYaml), "/dapr-resources/" + component.getName() + ".yaml"); } + for (Configuration configuration : configurations) { + String configurationYaml = configurationToYaml(configuration); + withCopyToContainer(Transferable.of(configurationYaml), "/dapr-resources/" + configuration.getName() + ".yaml"); + } + for (Subscription subscription : subscriptions) { String subscriptionYaml = subscriptionToYaml(subscription); withCopyToContainer(Transferable.of(subscriptionYaml), "/dapr-resources/" + subscription.getName() + ".yaml"); @@ -293,6 +343,11 @@ public String componentToYaml(Component component) { return yaml.dumpAsMap(componentMap); } + public String configurationToYaml(Configuration configuration) { + Map configurationMap = configurationToMap(configuration); + return yaml.dumpAsMap(configurationMap); + } + public String getAppName() { return appName; } diff --git a/testcontainers-dapr/src/main/java/io/dapr/testcontainers/TracingConfigParameters.java b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/TracingConfigParameters.java new file mode 100644 index 000000000..1983946d5 --- /dev/null +++ b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/TracingConfigParameters.java @@ -0,0 +1,72 @@ +/* + * Copyright 2024 The Dapr Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and +limitations under the License. +*/ + +package io.dapr.testcontainers; + +/** + * Represents a Dapr tracing configuration parameters . + */ +public class TracingConfigParameters { + + private String samplingRate; + private Boolean stdout; + private String otelEndpoint; + private Boolean otelIsSecure; + private String otelProtocol; + + //@TODO: add zipkin parameters + + + /** + * Creates a new configuration. + */ + public TracingConfigParameters() { + } + + /** + * Creates a new configuration. + * @param samplingRate tracing sampling rate + * @param stdout if it should send traces to the system standard output + * @param otelEndpoint if using OpenTelemetry where the collector endpoint is + * @param otelIsSecure if using OpenTelemetry if the channel is secure + * @param otelProtocol if using OpenTelemetry which protocol is being used http or grpc + */ + public TracingConfigParameters(String samplingRate, Boolean stdout, + String otelEndpoint, Boolean otelIsSecure, String otelProtocol) { + this.samplingRate = samplingRate; + this.stdout = stdout; + this.otelEndpoint = otelEndpoint; + this.otelIsSecure = otelIsSecure; + this.otelProtocol = otelProtocol; + } + + public String getSamplingRate() { + return this.samplingRate; + } + + public Boolean getStdout() { + return this.stdout; + } + + public String getOtelEndpoint() { + return this.otelEndpoint; + } + + public Boolean getOtelIsSecure() { + return this.otelIsSecure; + } + + public String getOtelProtocol() { + return this.otelProtocol; + } +} diff --git a/testcontainers-dapr/src/test/java/io/dapr/testcontainers/DaprComponentTest.java b/testcontainers-dapr/src/test/java/io/dapr/testcontainers/DaprComponentTest.java index 2a5db5967..e91d57c0d 100644 --- a/testcontainers-dapr/src/test/java/io/dapr/testcontainers/DaprComponentTest.java +++ b/testcontainers-dapr/src/test/java/io/dapr/testcontainers/DaprComponentTest.java @@ -95,6 +95,40 @@ public void subscriptionSerializationTest() { assertEquals(expectedSubscriptionYaml, subscriptionYaml); } + + @Test + public void configurationSerializationTest() { + + DaprContainer dapr = new DaprContainer("daprio/daprd") + .withAppName("dapr-app") + .withAppPort(8081) + .withConfiguration(new Configuration("my-config", + new TracingConfigParameters("1", true, + "localhost:4317", false, "grpc"))) + .withAppChannelAddress("host.testcontainers.internal"); + + Set configurations = dapr.getConfigurations(); + assertEquals(1, configurations.size()); + + String configurationYaml = dapr.configurationToYaml(configurations.iterator().next()); + String expectedConfigurationYaml = "metadata:\n" + " name: my-config\n" + + "apiVersion: dapr.io/v1alpha1\n" + + "kind: Configuration\n" + + "spec:\n" + + " tracing:\n" +// + " samplingRate: \"1\"\n" + + " stdout: true\n" + + " samplingRate: '1'\n" + + " otel:\n" +// + " endpointAddress: \"localhost:4317\"\n" + + " endpointAddress: localhost:4317\n" +// + " protocol: \"grpc\"\n" + + " protocol: grpc\n" + + " isSecure: false\n"; + assertEquals(expectedConfigurationYaml, configurationYaml); + } + + @Test public void withComponentFromPath() { URL stateStoreYaml = this.getClass().getClassLoader().getResource("dapr-resources/statestore.yaml"); From 369a5352aeb2e945374653597ea3161bdadc4580 Mon Sep 17 00:00:00 2001 From: salaboy Date: Thu, 26 Sep 2024 11:25:30 +0100 Subject: [PATCH 03/14] updating configuration configs Signed-off-by: salaboy --- .../io/dapr/testcontainers/DaprContainer.java | 58 +++++++++++++++---- .../testcontainers/DaprComponentTest.java | 10 ++-- 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java index 0ea4c67fa..55f86a361 100644 --- a/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java +++ b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java @@ -13,6 +13,8 @@ package io.dapr.testcontainers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.Network; import org.testcontainers.containers.wait.strategy.Wait; @@ -28,6 +30,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -38,6 +41,7 @@ public class DaprContainer extends GenericContainer { + private static final Logger log = LoggerFactory.getLogger(DaprContainer.class); private static final int DAPRD_DEFAULT_HTTP_PORT = 3500; private static final int DAPRD_DEFAULT_GRPC_PORT = 50001; private static final WaitStrategy WAIT_STRATEGY = Wait.forHttp("/v1.0/healthz/outbound") @@ -45,7 +49,7 @@ public class DaprContainer extends GenericContainer { .forStatusCodeMatching(statusCode -> statusCode >= 200 && statusCode <= 399); private final Set components = new HashSet<>(); - private final Set configurations = new HashSet<>(); + private Configuration configuration; private final Set subscriptions = new HashSet<>(); private DaprProtocol protocol = DaprProtocol.HTTP; private String appName; @@ -87,8 +91,8 @@ public Set getSubscriptions() { return subscriptions; } - public Set getConfigurations() { - return configurations; + public Configuration getConfiguration() { + return configuration; } public DaprContainer withAppPort(Integer port) { @@ -155,7 +159,7 @@ public DaprContainer withComponent(Path path) { } public DaprContainer withConfiguration(Configuration configuration) { - configurations.add(configuration); + this.configuration = configuration; return this; } @@ -300,11 +304,21 @@ protected void configure() { cmds.add(Integer.toString(appPort)); } + if (configuration != null) { + cmds.add("--config"); + cmds.add("/dapr-resources/" + configuration.getName() + ".yaml"); + } + cmds.add("--log-level"); cmds.add(daprLogLevel.toString()); - cmds.add("-components-path"); + cmds.add("--resources-path"); cmds.add("/dapr-resources"); - withCommand(cmds.toArray(new String[]{})); + + String[] cmdArray = cmds.toArray(new String[]{}); + log.info("> `daprd` Command: \n"); + log.info("\t" + Arrays.toString(cmdArray) + "\n"); + + withCommand(cmdArray); if (components.isEmpty()) { components.add(new Component("kvstore", "state.in-memory", "v1", Collections.emptyMap())); @@ -320,7 +334,7 @@ protected void configure() { withCopyToContainer(Transferable.of(componentYaml), "/dapr-resources/" + component.getName() + ".yaml"); } - for (Configuration configuration : configurations) { + if (configuration != null) { String configurationYaml = configurationToYaml(configuration); withCopyToContainer(Transferable.of(configurationYaml), "/dapr-resources/" + configuration.getName() + ".yaml"); } @@ -333,19 +347,43 @@ protected void configure() { dependsOn(placementContainer); } + /** + * Get a Yaml representation of a Subscription. + * @param subscription A Dapr Subscription. + * @return String representing the Subscription in Yaml format + */ public String subscriptionToYaml(Subscription subscription) { Map subscriptionMap = subscriptionToMap(subscription); - return yaml.dumpAsMap(subscriptionMap); + String subscriptionYaml = yaml.dumpAsMap(subscriptionMap); + log.info("> Subscription YAML: \n"); + log.info("\t\n" + subscriptionYaml + "\n"); + return subscriptionYaml; } + /** + * Get a Yaml representation of a Component. + * @param component A Dapr Subscription. + * @return String representing the Component in Yaml format + */ public String componentToYaml(Component component) { Map componentMap = componentToMap(component); - return yaml.dumpAsMap(componentMap); + String componentYaml = yaml.dumpAsMap(componentMap); + log.info("> Component YAML: \n"); + log.info("\t\n" + componentYaml + "\n"); + return componentYaml; } + /** + * Get a Yaml representation of a Configuration. + * @param configuration A Dapr Subscription. + * @return String representing the Configuration in Yaml format + */ public String configurationToYaml(Configuration configuration) { Map configurationMap = configurationToMap(configuration); - return yaml.dumpAsMap(configurationMap); + String configurationYaml = yaml.dumpAsMap(configurationMap); + log.info("> Configuration YAML: \n"); + log.info("\t\n" + configurationYaml + "\n"); + return configurationYaml; } public String getAppName() { diff --git a/testcontainers-dapr/src/test/java/io/dapr/testcontainers/DaprComponentTest.java b/testcontainers-dapr/src/test/java/io/dapr/testcontainers/DaprComponentTest.java index e91d57c0d..6196f245b 100644 --- a/testcontainers-dapr/src/test/java/io/dapr/testcontainers/DaprComponentTest.java +++ b/testcontainers-dapr/src/test/java/io/dapr/testcontainers/DaprComponentTest.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.Set; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -107,22 +108,19 @@ public void configurationSerializationTest() { "localhost:4317", false, "grpc"))) .withAppChannelAddress("host.testcontainers.internal"); - Set configurations = dapr.getConfigurations(); - assertEquals(1, configurations.size()); + Configuration configuration = dapr.getConfiguration(); + assertNotNull(configuration); - String configurationYaml = dapr.configurationToYaml(configurations.iterator().next()); + String configurationYaml = dapr.configurationToYaml(configuration); String expectedConfigurationYaml = "metadata:\n" + " name: my-config\n" + "apiVersion: dapr.io/v1alpha1\n" + "kind: Configuration\n" + "spec:\n" + " tracing:\n" -// + " samplingRate: \"1\"\n" + " stdout: true\n" + " samplingRate: '1'\n" + " otel:\n" -// + " endpointAddress: \"localhost:4317\"\n" + " endpointAddress: localhost:4317\n" -// + " protocol: \"grpc\"\n" + " protocol: grpc\n" + " isSecure: false\n"; assertEquals(expectedConfigurationYaml, configurationYaml); From 5c17916fc4b04e519757b2d63134f42561a97089 Mon Sep 17 00:00:00 2001 From: Artur Souza Date: Wed, 18 Sep 2024 11:13:17 -0700 Subject: [PATCH 04/14] Handle HTTP binding error. (#1024) (#1130) Update binding http IT Signed-off-by: Artur Souza Signed-off-by: salaboy --- sdk-tests/components/http_binding.yaml | 27 ++++ sdk-tests/deploy/local-test.yml | 4 +- .../io/dapr/it/binding/http/BindingIT.java | 68 ++++++++-- .../java/io/dapr/client/DaprClientImpl.java | 52 +++++++- .../main/java/io/dapr/client/DaprHttp.java | 27 +++- .../io/dapr/exceptions/DaprException.java | 62 +++++++-- .../exceptions/DaprHttpException.java | 126 ++++++++++++++++++ .../grpc/DaprClientGrpcInterceptors.java | 42 ++++-- .../interceptors/DaprMetadataInterceptor.java | 68 ++++++++++ 9 files changed, 432 insertions(+), 44 deletions(-) create mode 100644 sdk-tests/components/http_binding.yaml create mode 100644 sdk/src/main/java/io/dapr/internal/exceptions/DaprHttpException.java create mode 100644 sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprMetadataInterceptor.java diff --git a/sdk-tests/components/http_binding.yaml b/sdk-tests/components/http_binding.yaml new file mode 100644 index 000000000..5a3ca0a1d --- /dev/null +++ b/sdk-tests/components/http_binding.yaml @@ -0,0 +1,27 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: github-http-binding-404 +spec: + type: bindings.http + version: v1 + metadata: + - name: url + value: https://api.github.com/unknown_path +scopes: + - bindingit-httpoutputbinding-exception +--- +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: github-http-binding-404-success +spec: + type: bindings.http + version: v1 + metadata: + - name: url + value: https://api.github.com/unknown_path + - name: errorIfNot2XX + value: "false" +scopes: + - bindingit-httpoutputbinding-ignore-error \ No newline at end of file diff --git a/sdk-tests/deploy/local-test.yml b/sdk-tests/deploy/local-test.yml index 989757a78..f920f6acc 100644 --- a/sdk-tests/deploy/local-test.yml +++ b/sdk-tests/deploy/local-test.yml @@ -6,14 +6,14 @@ services: ZOOKEEPER_CLIENT_PORT: 2181 ZOOKEEPER_TICK_TIME: 2000 ports: - - 22181:2181 + - 2181:2181 kafka: image: confluentinc/cp-kafka:7.4.4 depends_on: - zookeeper ports: - - 9092:9092 + - "9092:9092" environment: KAFKA_BROKER_ID: 1 KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 diff --git a/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java b/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java index cc83b9b62..610a55820 100644 --- a/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Dapr Authors + * Copyright 2024 The Dapr Authors * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -17,6 +17,7 @@ import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; import io.dapr.client.domain.HttpExtension; +import io.dapr.exceptions.DaprException; import io.dapr.it.BaseIT; import io.dapr.it.DaprRun; import org.junit.jupiter.api.Test; @@ -26,6 +27,7 @@ import static io.dapr.it.Retry.callWithRetry; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; /** @@ -33,15 +35,50 @@ */ public class BindingIT extends BaseIT { - private static final String BINDING_NAME = "sample123"; - - private static final String BINDING_OPERATION = "create"; - - public static class MyClass { - public MyClass() { + @Test + public void httpOutputBindingError() throws Exception { + startDaprApp( + this.getClass().getSimpleName() + "-httpoutputbinding-exception", + 60000); + try(DaprClient client = new DaprClientBuilder().build()) { + // Validate error message + callWithRetry(() -> { + System.out.println("Checking exception handling for output binding ..."); + try { + client.invokeBinding("github-http-binding-404", "get", "").block(); + fail("Should throw an exception"); + } catch (DaprException e) { + assertEquals(404, e.getHttpStatusCode()); + // This HTTP binding did not set `errorIfNot2XX` to false in component metadata, so the error payload is not + // consistent between HTTP and gRPC. + assertTrue(new String(e.getPayload()).contains( + "error invoking output binding github-http-binding-404: received status code 404")); + } + }, 10000); } + } - public String message; + @Test + public void httpOutputBindingErrorIgnoredByComponent() throws Exception { + startDaprApp( + this.getClass().getSimpleName() + "-httpoutputbinding-ignore-error", + 60000); + try(DaprClient client = new DaprClientBuilder().build()) { + // Validate error message + callWithRetry(() -> { + System.out.println("Checking exception handling for output binding ..."); + try { + client.invokeBinding("github-http-binding-404-success", "get", "").block(); + fail("Should throw an exception"); + } catch (DaprException e) { + assertEquals(404, e.getHttpStatusCode()); + // The HTTP binding must set `errorIfNot2XX` to false in component metadata for the error payload to be + // consistent between HTTP and gRPC. + assertTrue(new String(e.getPayload()).contains("\"message\":\"Not Found\"")); + assertTrue(new String(e.getPayload()).contains("\"documentation_url\":\"https://docs.github.com/rest\"")); + } + }, 10000); + } } @Test @@ -53,11 +90,13 @@ public void inputOutputBinding() throws Exception { true, 60000); + var bidingName = "sample123"; + try(DaprClient client = new DaprClientBuilder().build()) { callWithRetry(() -> { System.out.println("Checking if input binding is up before publishing events ..."); client.invokeBinding( - BINDING_NAME, BINDING_OPERATION, "ping").block(); + bidingName, "create", "ping").block(); try { Thread.sleep(1000); @@ -76,14 +115,14 @@ public void inputOutputBinding() throws Exception { System.out.println("sending first message"); client.invokeBinding( - BINDING_NAME, BINDING_OPERATION, myClass, Collections.singletonMap("MyMetadata", "MyValue"), Void.class).block(); + bidingName, "create", myClass, Collections.singletonMap("MyMetadata", "MyValue"), Void.class).block(); // This is an example of sending a plain string. The input binding will receive // cat final String m = "cat"; System.out.println("sending " + m); client.invokeBinding( - BINDING_NAME, BINDING_OPERATION, m, Collections.singletonMap("MyMetadata", "MyValue"), Void.class).block(); + bidingName, "create", m, Collections.singletonMap("MyMetadata", "MyValue"), Void.class).block(); // Metadata is not used by Kafka component, so it is not possible to validate. callWithRetry(() -> { @@ -115,4 +154,11 @@ public void inputOutputBinding() throws Exception { }, 8000); } } + + public static class MyClass { + public MyClass() { + } + + public String message; + } } diff --git a/sdk/src/main/java/io/dapr/client/DaprClientImpl.java b/sdk/src/main/java/io/dapr/client/DaprClientImpl.java index aabc07a60..dc0f75210 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientImpl.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientImpl.java @@ -56,6 +56,7 @@ import io.dapr.client.domain.UnsubscribeConfigurationResponse; import io.dapr.client.resiliency.ResiliencyOptions; import io.dapr.exceptions.DaprException; +import io.dapr.internal.exceptions.DaprHttpException; import io.dapr.internal.grpc.DaprClientGrpcInterceptors; import io.dapr.internal.resiliency.RetryPolicy; import io.dapr.internal.resiliency.TimeoutPolicy; @@ -76,6 +77,7 @@ import io.dapr.v1.DaprProtos.RegisteredComponents; import io.grpc.CallOptions; import io.grpc.Channel; +import io.grpc.Metadata; import io.grpc.stub.AbstractStub; import io.grpc.stub.StreamObserver; import reactor.core.publisher.Flux; @@ -99,6 +101,10 @@ import java.util.function.Function; import java.util.stream.Collectors; +import static io.dapr.internal.exceptions.DaprHttpException.isSuccessfulHttpStatusCode; +import static io.dapr.internal.exceptions.DaprHttpException.isValidHttpStatusCode; +import static io.dapr.internal.exceptions.DaprHttpException.parseHttpStatusCode; + /** * Implementation of the Dapr client combining gRPC and HTTP (when applicable). * @@ -486,12 +492,22 @@ public Mono invokeBinding(InvokeBindingRequest request, TypeRef type) } DaprProtos.InvokeBindingRequest envelope = builder.build(); + Metadata responseMetadata = new Metadata(); return Mono.deferContextual( context -> this.createMono( - it -> intercept(context, asyncStub).invokeBinding(envelope, it) + responseMetadata, + it -> intercept(context, asyncStub, m -> responseMetadata.merge(m)).invokeBinding(envelope, it) ) ).flatMap( it -> { + int httpStatusCode = + parseHttpStatusCode(it.getMetadataMap().getOrDefault("statusCode", "")); + if (isValidHttpStatusCode(httpStatusCode) && !isSuccessfulHttpStatusCode(httpStatusCode)) { + // Exception condition in a successful request. + // This is useful to send an exception due to an error from the HTTP binding component. + throw DaprException.propagate(new DaprHttpException(httpStatusCode, it.getData().toByteArray())); + } + try { return Mono.justOrEmpty(objectSerializer.deserialize(it.getData().toByteArray(), type)); } catch (IOException e) { @@ -1201,17 +1217,39 @@ private DaprGrpc.DaprStub intercept(ContextView context, DaprGrpc.DaprStub clien return DaprClientGrpcInterceptors.intercept(client, this.timeoutPolicy, context); } + /** + * Populates GRPC client with interceptors for telemetry. + * + * @param context Reactor's context. + * @param client GRPC client for Dapr. + * @param metadataConsumer Consumer of gRPC metadata. + * @return Client after adding interceptors. + */ + private DaprGrpc.DaprStub intercept( + ContextView context, DaprGrpc.DaprStub client, Consumer metadataConsumer) { + return DaprClientGrpcInterceptors.intercept(client, this.timeoutPolicy, context, metadataConsumer); + } + private Mono createMono(Consumer> consumer) { + return this.createMono(null, consumer); + } + + private Mono createMono(Metadata metadata, Consumer> consumer) { return retryPolicy.apply( - Mono.create(sink -> DaprException.wrap(() -> consumer.accept(createStreamObserver(sink))).run())); + Mono.create(sink -> DaprException.wrap(() -> consumer.accept( + createStreamObserver(sink, metadata))).run())); } private Flux createFlux(Consumer> consumer) { + return this.createFlux(null, consumer); + } + + private Flux createFlux(Metadata metadata, Consumer> consumer) { return retryPolicy.apply( - Flux.create(sink -> DaprException.wrap(() -> consumer.accept(createStreamObserver(sink))).run())); + Flux.create(sink -> DaprException.wrap(() -> consumer.accept(createStreamObserver(sink, metadata))).run())); } - private StreamObserver createStreamObserver(MonoSink sink) { + private StreamObserver createStreamObserver(MonoSink sink, Metadata grpcMetadata) { return new StreamObserver() { @Override public void onNext(T value) { @@ -1220,7 +1258,7 @@ public void onNext(T value) { @Override public void onError(Throwable t) { - sink.error(DaprException.propagate(new ExecutionException(t))); + sink.error(DaprException.propagate(DaprHttpException.fromGrpcExecutionException(grpcMetadata, t))); } @Override @@ -1230,7 +1268,7 @@ public void onCompleted() { }; } - private StreamObserver createStreamObserver(FluxSink sink) { + private StreamObserver createStreamObserver(FluxSink sink, final Metadata grpcMetadata) { return new StreamObserver() { @Override public void onNext(T value) { @@ -1239,7 +1277,7 @@ public void onNext(T value) { @Override public void onError(Throwable t) { - sink.error(DaprException.propagate(new ExecutionException(t))); + sink.error(DaprException.propagate(DaprHttpException.fromGrpcExecutionException(grpcMetadata, t))); } @Override diff --git a/sdk/src/main/java/io/dapr/client/DaprHttp.java b/sdk/src/main/java/io/dapr/client/DaprHttp.java index 54b64bd77..01485e433 100644 --- a/sdk/src/main/java/io/dapr/client/DaprHttp.java +++ b/sdk/src/main/java/io/dapr/client/DaprHttp.java @@ -18,6 +18,7 @@ import io.dapr.config.Properties; import io.dapr.exceptions.DaprError; import io.dapr.exceptions.DaprException; +import io.dapr.internal.exceptions.DaprHttpException; import io.dapr.utils.Version; import okhttp3.Call; import okhttp3.Callback; @@ -387,17 +388,19 @@ public void onFailure(Call call, IOException e) { @Override public void onResponse(@NotNull Call call, @NotNull okhttp3.Response response) throws IOException { - if (!response.isSuccessful()) { + int httpStatusCode = parseHttpStatusCode(response.header("Metadata.statuscode"), response.code()); + if (!DaprHttpException.isSuccessfulHttpStatusCode(httpStatusCode)) { try { byte[] payload = getBodyBytesOrEmptyArray(response); DaprError error = parseDaprError(payload); + if (error != null) { - future.completeExceptionally(new DaprException(error, payload, response.code())); + future.completeExceptionally(new DaprException(error, payload, httpStatusCode)); return; } future.completeExceptionally( - new DaprException("UNKNOWN", "", payload, response.code())); + new DaprException("UNKNOWN", "", payload, httpStatusCode)); return; } catch (DaprException e) { future.completeExceptionally(e); @@ -410,8 +413,24 @@ public void onResponse(@NotNull Call call, @NotNull okhttp3.Response response) t response.headers().forEach(pair -> { mapHeaders.put(pair.getFirst(), pair.getSecond()); }); - future.complete(new Response(result, mapHeaders, response.code())); + future.complete(new Response(result, mapHeaders, httpStatusCode)); } } + private static int parseHttpStatusCode(String headerValue, int defaultStatusCode) { + if ((headerValue == null) || headerValue.isEmpty()) { + return defaultStatusCode; + } + + // Metadata used to override status code with code received from HTTP binding. + try { + int httpStatusCode = Integer.parseInt(headerValue); + if (DaprHttpException.isValidHttpStatusCode(httpStatusCode)) { + return httpStatusCode; + } + return defaultStatusCode; + } catch (NumberFormatException nfe) { + return defaultStatusCode; + } + } } diff --git a/sdk/src/main/java/io/dapr/exceptions/DaprException.java b/sdk/src/main/java/io/dapr/exceptions/DaprException.java index 0801069e8..9e40298bf 100644 --- a/sdk/src/main/java/io/dapr/exceptions/DaprException.java +++ b/sdk/src/main/java/io/dapr/exceptions/DaprException.java @@ -14,6 +14,7 @@ package io.dapr.exceptions; import com.google.rpc.Status; +import io.dapr.internal.exceptions.DaprHttpException; import io.grpc.StatusRuntimeException; import io.grpc.protobuf.StatusProto; import reactor.core.Exceptions; @@ -170,11 +171,33 @@ public DaprException(String errorCode, String message, Throwable cause) { */ public DaprException( String errorCode, String message, Throwable cause, DaprErrorDetails errorDetails, byte[] payload) { - super(buildErrorMessage(errorCode, 0, message), cause); - this.httpStatusCode = 0; + this(errorCode, message, cause, errorDetails, payload, 0); + } + + /** + * New exception from a server-side generated error code and message. + * @param errorCode Client-side error code. + * @param message Client-side error message. + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A {@code null} value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @param errorDetails the status details for the error. + * @param payload Raw error payload. + * @param httpStatusCode Optional HTTP Status code for the error, 0 if not applicable. + */ + private DaprException( + String errorCode, + String message, + Throwable cause, + DaprErrorDetails errorDetails, + byte[] payload, + int httpStatusCode) { + super(buildErrorMessage(errorCode, httpStatusCode, message), cause); this.errorCode = errorCode; this.errorDetails = errorDetails == null ? DaprErrorDetails.EMPTY_INSTANCE : errorDetails; this.payload = payload; + this.httpStatusCode = httpStatusCode; } /** @@ -305,21 +328,27 @@ public static RuntimeException propagate(Throwable exception) { return (DaprException) exception; } + int httpStatusCode = 0; + byte[] httpPayload = null; Throwable e = exception; while (e != null) { - if (e instanceof StatusRuntimeException) { + if (e instanceof DaprHttpException) { + DaprHttpException daprHttpException = (DaprHttpException) e; + httpStatusCode = daprHttpException.getStatusCode(); + httpPayload = daprHttpException.getPayload(); + } else if (e instanceof StatusRuntimeException) { StatusRuntimeException statusRuntimeException = (StatusRuntimeException) e; Status status = StatusProto.fromThrowable(statusRuntimeException); DaprErrorDetails errorDetails = new DaprErrorDetails(status); return new DaprException( - statusRuntimeException.getStatus().getCode().toString(), - statusRuntimeException.getStatus().getDescription(), - exception, - errorDetails, - status.toByteArray()); - + statusRuntimeException.getStatus().getCode().toString(), + statusRuntimeException.getStatus().getDescription(), + exception, + errorDetails, + httpPayload != null ? httpPayload : status.toByteArray(), + httpStatusCode); } e = e.getCause(); @@ -329,19 +358,30 @@ public static RuntimeException propagate(Throwable exception) { return (IllegalArgumentException) exception; } + if (exception instanceof DaprHttpException) { + DaprHttpException daprHttpException = (DaprHttpException)exception; + return new DaprException( + io.grpc.Status.UNKNOWN.toString(), + null, + exception, + null, + daprHttpException.getPayload(), + daprHttpException.getStatusCode()); + } + return new DaprException(exception); } private static String buildErrorMessage(String errorCode, int httpStatusCode, String message) { String result = ((errorCode == null) || errorCode.isEmpty()) ? "UNKNOWN: " : errorCode + ": "; if ((message == null) || message.isEmpty()) { - if (httpStatusCode > 0) { + if (DaprHttpException.isValidHttpStatusCode(httpStatusCode)) { return result + "HTTP status code: " + httpStatusCode; } return result; } - if (httpStatusCode > 0) { + if (DaprHttpException.isValidHttpStatusCode(httpStatusCode)) { return result + message + " (HTTP status code: " + httpStatusCode + ")"; } return result + message; diff --git a/sdk/src/main/java/io/dapr/internal/exceptions/DaprHttpException.java b/sdk/src/main/java/io/dapr/internal/exceptions/DaprHttpException.java new file mode 100644 index 000000000..03b57f77c --- /dev/null +++ b/sdk/src/main/java/io/dapr/internal/exceptions/DaprHttpException.java @@ -0,0 +1,126 @@ +/* + * Copyright 2024 The Dapr Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and +limitations under the License. +*/ + +package io.dapr.internal.exceptions; + +import io.grpc.Metadata; + +import java.util.concurrent.ExecutionException; + +/** + * Internal exception for propagating HTTP status code. + */ +public class DaprHttpException extends ExecutionException { + + /** + * This is the metadata from HTTP binding that we want to automatically parse and make it as part of the exception. + */ + private static final Metadata.Key GRPC_METADATA_KEY_HTTP_STATUS_CODE = + Metadata.Key.of("metadata.statuscode", Metadata.ASCII_STRING_MARSHALLER); + + private final int statusCode; + + private final byte[] payload; + + /** + * Instantiates a new DaprHttpException, without http body. + * @param statusCode HTTP status code. + * @param cause Exception thrown. + */ + private DaprHttpException(int statusCode, Throwable cause) { + super(cause); + this.statusCode = statusCode; + this.payload = null; + } + + /** + * Instantiates a new DaprHttpException with a given HTTP payload. + * @param statusCode HTTP status code. + * @param payload HTTP payload. + */ + public DaprHttpException(int statusCode, byte[] payload) { + super(); + this.statusCode = statusCode; + this.payload = payload; + } + + /** + * Creates an ExecutionException (can also be HttpException, if applicable). + * @param grpcMetadata Optional gRPC metadata. + * @param cause Exception triggered during execution. + * @return ExecutionException + */ + public static ExecutionException fromGrpcExecutionException(Metadata grpcMetadata, Throwable cause) { + int httpStatusCode = parseHttpStatusCode(grpcMetadata); + if (!isValidHttpStatusCode(httpStatusCode)) { + return new ExecutionException(cause); + } + + return new DaprHttpException(httpStatusCode, cause); + } + + public static boolean isValidHttpStatusCode(int statusCode) { + return statusCode >= 100 && statusCode <= 599; // Status codes range from 100 to 599 + } + + public static boolean isSuccessfulHttpStatusCode(int statusCode) { + return statusCode >= 200 && statusCode < 300; + } + + private static int parseHttpStatusCode(Metadata grpcMetadata) { + if (grpcMetadata == null) { + return 0; + } + + return parseHttpStatusCode(grpcMetadata.get(GRPC_METADATA_KEY_HTTP_STATUS_CODE)); + } + + /** + * Parses a given string value into an HTTP status code, 0 if invalid. + * @param value String value to be parsed. + * @return HTTP status code, 0 if not valid. + */ + public static int parseHttpStatusCode(String value) { + if ((value == null) || value.isEmpty()) { + return 0; + } + + try { + int httpStatusCode = Integer.parseInt(value); + if (!isValidHttpStatusCode(httpStatusCode)) { + return 0; + } + + return httpStatusCode; + } catch (NumberFormatException nfe) { + return 0; + } + } + + /** + * Returns the HTTP Status code for the exception. + * @return HTTP Status code for the exception, 0 if not applicable. + */ + public int getStatusCode() { + return this.statusCode; + } + + /** + * Returns the HTTP payload for the exception. + * @return HTTP payload, null if not present. + */ + public byte[] getPayload() { + return this.payload; + } + +} diff --git a/sdk/src/main/java/io/dapr/internal/grpc/DaprClientGrpcInterceptors.java b/sdk/src/main/java/io/dapr/internal/grpc/DaprClientGrpcInterceptors.java index 9a47d1aeb..5241e1d5f 100644 --- a/sdk/src/main/java/io/dapr/internal/grpc/DaprClientGrpcInterceptors.java +++ b/sdk/src/main/java/io/dapr/internal/grpc/DaprClientGrpcInterceptors.java @@ -15,12 +15,16 @@ import io.dapr.internal.grpc.interceptors.DaprApiTokenInterceptor; import io.dapr.internal.grpc.interceptors.DaprAppIdInterceptor; +import io.dapr.internal.grpc.interceptors.DaprMetadataInterceptor; import io.dapr.internal.grpc.interceptors.DaprTimeoutInterceptor; import io.dapr.internal.grpc.interceptors.DaprTracingInterceptor; import io.dapr.internal.resiliency.TimeoutPolicy; +import io.grpc.Metadata; import io.grpc.stub.AbstractStub; import reactor.util.context.ContextView; +import java.util.function.Consumer; + /** * Class to be used as part of your service's client stub interceptor. * Usage: myClientStub = DaprClientGrpcInterceptors.intercept(myClientStub); @@ -35,7 +39,7 @@ public class DaprClientGrpcInterceptors { * @return async client instance with interceptors */ public static > T intercept(final String appId, final T client) { - return intercept(appId, client, null, null); + return intercept(appId, client, null, null, null); } /** @@ -45,7 +49,7 @@ public static > T intercept(final String appId, final * @return async client instance with interceptors */ public static > T intercept(final T client) { - return intercept(null, client, null, null); + return intercept(null, client, null, null, null); } /** @@ -58,7 +62,7 @@ public static > T intercept(final T client) { */ public static > T intercept( final String appId, final T client, final TimeoutPolicy timeoutPolicy) { - return intercept(appId, client, timeoutPolicy, null); + return intercept(appId, client, timeoutPolicy, null, null); } /** @@ -69,7 +73,7 @@ public static > T intercept( * @return async client instance with interceptors */ public static > T intercept(final T client, final TimeoutPolicy timeoutPolicy) { - return intercept(null, client, timeoutPolicy, null); + return intercept(null, client, timeoutPolicy, null, null); } /** @@ -82,7 +86,7 @@ public static > T intercept(final T client, final Time */ public static > T intercept( final String appId, final T client, final ContextView context) { - return intercept(appId, client, null, context); + return intercept(appId, client, null, context, null); } /** @@ -93,7 +97,7 @@ public static > T intercept( * @return async client instance with interceptors */ public static > T intercept(final T client, final ContextView context) { - return intercept(null, client, null, context); + return intercept(null, client, null, context, null); } /** @@ -108,7 +112,24 @@ public static > T intercept( final T client, final TimeoutPolicy timeoutPolicy, final ContextView context) { - return intercept(null, client, timeoutPolicy, context); + return intercept(null, client, timeoutPolicy, context, null); + } + + /** + * Adds all Dapr interceptors to a gRPC async stub. + * @param client gRPC client + * @param timeoutPolicy timeout policy for gRPC call + * @param context Reactor context for tracing + * @param metadataConsumer Consumer of the gRPC metadata + * @param async client type + * @return async client instance with interceptors + */ + public static > T intercept( + final T client, + final TimeoutPolicy timeoutPolicy, + final ContextView context, + final Consumer metadataConsumer) { + return intercept(null, client, timeoutPolicy, context, metadataConsumer); } /** @@ -117,6 +138,7 @@ public static > T intercept( * @param client gRPC client * @param timeoutPolicy timeout policy for gRPC call * @param context Reactor context for tracing + * @param metadataConsumer Consumer of the gRPC metadata * @param async client type * @return async client instance with interceptors */ @@ -124,7 +146,8 @@ public static > T intercept( final String appId, final T client, final TimeoutPolicy timeoutPolicy, - final ContextView context) { + final ContextView context, + final Consumer metadataConsumer) { if (client == null) { throw new IllegalArgumentException("client cannot be null"); } @@ -133,7 +156,8 @@ public static > T intercept( new DaprAppIdInterceptor(appId), new DaprApiTokenInterceptor(), new DaprTimeoutInterceptor(timeoutPolicy), - new DaprTracingInterceptor(context)); + new DaprTracingInterceptor(context), + new DaprMetadataInterceptor(metadataConsumer)); } } diff --git a/sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprMetadataInterceptor.java b/sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprMetadataInterceptor.java new file mode 100644 index 000000000..44b438a01 --- /dev/null +++ b/sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprMetadataInterceptor.java @@ -0,0 +1,68 @@ +/* + * Copyright 2024 The Dapr Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and +limitations under the License. +*/ + +package io.dapr.internal.grpc.interceptors; + +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.ClientCall; +import io.grpc.ClientInterceptor; +import io.grpc.ForwardingClientCall; +import io.grpc.ForwardingClientCallListener; +import io.grpc.Metadata; +import io.grpc.MethodDescriptor; + +import java.util.function.Consumer; + +/** + * Consumes gRPC metadata. + */ +public class DaprMetadataInterceptor implements ClientInterceptor { + + private final Consumer metadataConsumer; + + /** + * Creates an instance of the consumer for gRPC metadata. + * @param metadataConsumer gRPC metadata consumer + */ + public DaprMetadataInterceptor(Consumer metadataConsumer) { + this.metadataConsumer = metadataConsumer; + } + + @Override + public ClientCall interceptCall( + MethodDescriptor methodDescriptor, + CallOptions callOptions, + Channel channel) { + ClientCall clientCall = channel.newCall(methodDescriptor, callOptions); + return new ForwardingClientCall.SimpleForwardingClientCall<>(clientCall) { + @Override + public void start(final Listener responseListener, final Metadata metadata) { + final ClientCall.Listener headerListener = + new ForwardingClientCallListener.SimpleForwardingClientCallListener<>(responseListener) { + @Override + public void onHeaders(Metadata headers) { + responseListener.onHeaders(headers); + if (metadataConsumer != null) { + metadataConsumer.accept(headers); + } + } + }; + super.start(headerListener, metadata); + } + }; + } + + + +} From ab2650480456146506735655219815b679bc5bb0 Mon Sep 17 00:00:00 2001 From: salaboy Date: Fri, 27 Sep 2024 08:24:17 +0100 Subject: [PATCH 05/14] updating sdk tests Signed-off-by: salaboy --- .../java/io/dapr/it/testcontainers/DaprContainerIT.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerIT.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerIT.java index 66c8e68f3..bdafff9a7 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerIT.java @@ -110,13 +110,12 @@ public void testDaprContainerDefaults() { "A subscription should be configured by default if none is provided" ); - assertEquals( - 1, - DAPR_CONTAINER.getConfigurations().size(), - "A configuration should be configured" + assertNotNull( + DAPR_CONTAINER.getConfiguration(), + "A configuration should be provided" ); - Configuration configuration = DAPR_CONTAINER.getConfigurations().iterator().next(); + Configuration configuration = DAPR_CONTAINER.getConfiguration(); assertEquals("1",configuration.getTracing().getSamplingRate()); assertEquals(true,configuration.getTracing().getStdout()); assertEquals("localhost:4317",configuration.getTracing().getOtelEndpoint()); From dc80ca68222049bc3dc493c74c047d2ab3aab9ea Mon Sep 17 00:00:00 2001 From: salaboy Date: Tue, 1 Oct 2024 16:55:22 +0100 Subject: [PATCH 06/14] adding observation API Signed-off-by: salaboy --- .../dapr-spring-boot-autoconfigure/pom.xml | 24 ++- dapr-spring/dapr-spring-messaging/pom.xml | 8 +- .../messaging/DaprMessagingOperations.java | 4 + .../messaging/DaprMessagingTemplate.java | 188 +++++++++++++++++- .../observation/DaprMessageSenderContext.java | 80 ++++++++ .../observation/DaprTemplateObservation.java | 56 ++++++ .../DaprTemplateObservationConvention.java | 23 +++ ...aultDaprTemplateObservationConvention.java | 35 ++++ 8 files changed, 410 insertions(+), 8 deletions(-) create mode 100644 dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprMessageSenderContext.java create mode 100644 dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprTemplateObservation.java create mode 100644 dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprTemplateObservationConvention.java create mode 100644 dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DefaultDaprTemplateObservationConvention.java diff --git a/dapr-spring/dapr-spring-boot-autoconfigure/pom.xml b/dapr-spring/dapr-spring-boot-autoconfigure/pom.xml index 5cbcba6ae..87be8844b 100644 --- a/dapr-spring/dapr-spring-boot-autoconfigure/pom.xml +++ b/dapr-spring/dapr-spring-boot-autoconfigure/pom.xml @@ -29,13 +29,35 @@ org.springframework.boot - spring-boot-starter + spring-boot-starter-web org.springframework.boot spring-boot-autoconfigure-processor true + + io.micrometer + micrometer-tracing-bridge-otel + + + io.opentelemetry + opentelemetry-exporter-otlp + + + io.opentelemetry.instrumentation + opentelemetry-instrumentation-annotations + 2.8.0 + + + io.micrometer + micrometer-registry-otlp + + + net.ttddyy.observation + datasource-micrometer-spring-boot + 1.0.5 + org.springframework.data spring-data-keyvalue diff --git a/dapr-spring/dapr-spring-messaging/pom.xml b/dapr-spring/dapr-spring-messaging/pom.xml index c9b280a47..36f4179cf 100644 --- a/dapr-spring/dapr-spring-messaging/pom.xml +++ b/dapr-spring/dapr-spring-messaging/pom.xml @@ -12,6 +12,12 @@ dapr-spring-messaging dapr-spring-messaging Dapr Spring Messaging - jar + + + io.opentelemetry + opentelemetry-api + + + jar diff --git a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingOperations.java b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingOperations.java index ac1092c9a..bfae729d1 100644 --- a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingOperations.java +++ b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingOperations.java @@ -15,6 +15,10 @@ import reactor.core.publisher.Mono; +/** + * Create a new DaprMessagingOperations. + * @param payload type + */ public interface DaprMessagingOperations { /** diff --git a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java index 604849b86..0eed0b0d1 100644 --- a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java +++ b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java @@ -15,20 +15,105 @@ import io.dapr.client.DaprClient; import io.dapr.client.domain.Metadata; +import io.dapr.spring.messaging.observation.DaprMessageSenderContext; +import io.dapr.spring.messaging.observation.DaprTemplateObservation; +import io.dapr.spring.messaging.observation.DaprTemplateObservationConvention; +import io.dapr.spring.messaging.observation.DefaultDaprTemplateObservationConvention; +import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationRegistry; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.ContextKey; +import io.opentelemetry.context.propagation.TextMapSetter; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.SmartInitializingSingleton; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.core.log.LogAccessor; +import org.springframework.lang.Nullable; import reactor.core.publisher.Mono; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; -public class DaprMessagingTemplate implements DaprMessagingOperations { +/** + * Create a new DaprMessagingTemplate. + * @param templated message type + */ +public class DaprMessagingTemplate implements DaprMessagingOperations, + ApplicationContextAware, BeanNameAware, SmartInitializingSingleton { + + private final LogAccessor logger = new LogAccessor(this.getClass()); private static final String MESSAGE_TTL_IN_SECONDS = "10"; private final DaprClient daprClient; private final String pubsubName; - public DaprMessagingTemplate(DaprClient daprClient, String pubsubName) { + /** + * Whether to record observations. + */ + private final boolean observationEnabled; + + /** + * The registry to record observations with. + */ + @Nullable + private ObservationRegistry observationRegistry; + + /** + * The optional custom observation convention to use when recording observations. + */ + @Nullable + private DaprTemplateObservationConvention observationConvention; + + @Nullable + private ApplicationContext applicationContext; + + private String beanName = ""; + + /** + * New DaprMessagingTemplate. + * + * @param daprClient the DaprClient that will be used for sending the message + * @param pubsubName the configured PubSub Dapr Component + * @param observationEnabled if observation is enabled + */ + public DaprMessagingTemplate(DaprClient daprClient, String pubsubName, boolean observationEnabled) { this.daprClient = daprClient; this.pubsubName = pubsubName; + this.observationEnabled = observationEnabled; + } + + /** + * If observations are enabled, attempt to obtain the Observation registry and + * convention. + */ + @Override + public void afterSingletonsInstantiated() { + if (!this.observationEnabled) { + this.logger.debug(() -> "Observations are not enabled - not recording"); + return; + } + if (this.applicationContext == null) { + this.logger.warn(() -> "Observations enabled but application context null - not recording"); + return; + } + this.observationRegistry = this.applicationContext.getBeanProvider(ObservationRegistry.class) + .getIfUnique(() -> this.observationRegistry); + this.observationConvention = this.applicationContext.getBeanProvider(DaprTemplateObservationConvention.class) + .getIfUnique(() -> this.observationConvention); + } + + @Override + public void setBeanName(String beanName) { + this.beanName = beanName; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; } @Override @@ -46,10 +131,101 @@ private void doSend(String topic, T message) { } private Mono doSendAsync(String topic, T message) { - return daprClient.publishEvent(pubsubName, - topic, - message, - Collections.singletonMap(Metadata.TTL_IN_SECONDS, MESSAGE_TTL_IN_SECONDS)); + + this.logger.trace(() -> "Sending msg to '%s' topic".formatted(topic)); + + DaprMessageSenderContext senderContext = DaprMessageSenderContext.newContext(topic, this.beanName); + Observation observation = newObservation(senderContext); + observation.start(); + + + return daprClient.publishEvent(pubsubName, + topic, + message, + Collections.singletonMap(Metadata.TTL_IN_SECONDS, MESSAGE_TTL_IN_SECONDS)) + .contextWrite(getReactorContext(observation.getContextView())).doOnError( + (err) -> { + + this.logger.error(err, () -> "Failed to send msg to '%s' topic".formatted(topic)); + observation.error(err); + observation.stop(); + } + ).doOnSuccess((err) -> { + this.logger.trace(() -> "Sent msg to '%s' topic".formatted(topic)); + observation.stop(); + }); + } + + /** + * Converts current OpenTelemetry's context into Reactor's context. + * @return Reactor's context. + */ + public static reactor.util.context.ContextView getReactorContext() { + return getReactorContext(Context.current()); + } + + /** + * Converts given OpenTelemetry's context into Reactor's context. + * @param context OpenTelemetry's context. + * @return Reactor's context. + */ + public static reactor.util.context.Context getReactorContext(Context context) { + Map map = new HashMap<>(); + TextMapSetter> setter = + (carrier, key, value) -> map.put(key, value); + + GlobalOpenTelemetry.getPropagators().getTextMapPropagator().inject(context, map, setter); + reactor.util.context.Context reactorContext = reactor.util.context.Context.empty(); + for (Map.Entry entry : map.entrySet()) { + reactorContext = reactorContext.put(entry.getKey(), entry.getValue()); + } + return reactorContext; + } + + /** + * Converts given Micrometer's context into Reactor's context. + * @param contextView Micrometers's contextView. + * @return Reactor's context. + */ + public static reactor.util.context.Context getReactorContext(io.micrometer.observation.Observation.ContextView + contextView) { + Map map = new HashMap<>(); + TextMapSetter> setter = + (carrier, key, value) -> map.put(key, value); + + final reactor.util.context.Context reactorContext = reactor.util.context.Context.empty(); + + contextView.getAllKeyValues().forEach((entry) -> { + reactorContext.put(entry.getKey(), entry.getValue()); + }); + + Context otelContext = Context.root(); + reactorContext.stream() + .forEach(entry -> { + Object key = entry.getKey(); + Object value = entry.getValue(); + + // Create a Context.Key for OpenTelemetry + ContextKey otelKey = ContextKey.named(key.toString()); + + // Store the entry in OpenTelemetry Context + otelContext.with(otelKey, value); + }); + + GlobalOpenTelemetry.getPropagators().getTextMapPropagator() + .inject(otelContext, map, setter); + return reactorContext; + } + + + + + private Observation newObservation(DaprMessageSenderContext senderContext) { + if (this.observationRegistry == null) { + return Observation.NOOP; + } + return DaprTemplateObservation.TEMPLATE_OBSERVATION.observation(this.observationConvention, + DefaultDaprTemplateObservationConvention.INSTANCE, () -> senderContext, this.observationRegistry); } private static class SendMessageBuilderImpl implements SendMessageBuilder { diff --git a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprMessageSenderContext.java b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprMessageSenderContext.java new file mode 100644 index 000000000..7f2780de4 --- /dev/null +++ b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprMessageSenderContext.java @@ -0,0 +1,80 @@ +package io.dapr.spring.messaging.observation; + +import io.micrometer.observation.transport.SenderContext; +import java.util.HashMap; +import java.util.Map; + + +/** + * {@link SenderContext} for Dapr messages. + * + */ +public final class DaprMessageSenderContext extends SenderContext { + + private final String beanName; + + private final String destination; + + + private DaprMessageSenderContext(MessageHolder messageHolder, String topic, String beanName) { + super((carrier, key, value) -> messageHolder.property(key, value)); + setCarrier(messageHolder); + this.beanName = beanName; + this.destination = topic; + } + + /** + * Create a new context. + * @param topic topic to be used + * @param beanName name of the bean used usually (typically a {@code DaprMessagingTemplate}) + * @return DaprMessageSenderContext + */ + public static DaprMessageSenderContext newContext(String topic, String beanName) { + MessageHolder messageHolder = new MessageHolder(); + return new DaprMessageSenderContext(messageHolder, topic, beanName); + } + + public Map properties() { + return getCarrier().properties(); + } + + + /** + * The name of the bean sending the message (typically a {@code DaprMessagingTemplate}). + * @return the name of the bean sending the message + */ + public String getBeanName() { + return this.beanName; + } + + /** + * The destination topic for the message. + * @return the topic the message is being sent to + */ + public String getDestination() { + return this.destination; + } + + + /** + * Acts as a carrier for a Pulsar message and records the propagated properties for + * later access by the Pulsar message builder. + */ + public static final class MessageHolder { + + private final Map properties = new HashMap<>(); + + private MessageHolder() { + } + + public void property(String key, String value) { + this.properties.put(key, value); + } + + public Map properties() { + return this.properties; + } + + } + +} diff --git a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprTemplateObservation.java b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprTemplateObservation.java new file mode 100644 index 000000000..b091246cc --- /dev/null +++ b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprTemplateObservation.java @@ -0,0 +1,56 @@ +package io.dapr.spring.messaging.observation; + +import io.micrometer.common.docs.KeyName; +import io.micrometer.observation.Observation; +import io.micrometer.observation.Observation.Context; +import io.micrometer.observation.ObservationConvention; +import io.micrometer.observation.docs.ObservationDocumentation; + +/** + * An {@link Observation} for {@link io.dapr.spring.messaging.DaprMessagingTemplate}. + * + */ +public enum DaprTemplateObservation implements ObservationDocumentation { + + /** + * Observation created when a Dapr template sends a message. + */ + TEMPLATE_OBSERVATION { + + @Override + public Class> getDefaultConvention() { + return DefaultDaprTemplateObservationConvention.class; + } + + @Override + public String getPrefix() { + return "spring.dapr.template"; + } + + @Override + public KeyName[] getLowCardinalityKeyNames() { + return TemplateLowCardinalityTags.values(); + } + + }; + + /** + * Low cardinality tags. + */ + public enum TemplateLowCardinalityTags implements KeyName { + + /** + * Bean name of the template that sent the message. + */ + BEAN_NAME { + + @Override + public String asString() { + return "spring.dapr.template.name"; + } + + } + + } + +} diff --git a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprTemplateObservationConvention.java b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprTemplateObservationConvention.java new file mode 100644 index 000000000..2ef8952f0 --- /dev/null +++ b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprTemplateObservationConvention.java @@ -0,0 +1,23 @@ +package io.dapr.spring.messaging.observation; + + +import io.micrometer.observation.Observation.Context; +import io.micrometer.observation.ObservationConvention; + +/** + * {@link ObservationConvention} for Dapr template . + * + */ +public interface DaprTemplateObservationConvention extends ObservationConvention { + + @Override + default boolean supportsContext(Context context) { + return context instanceof DaprMessageSenderContext; + } + + @Override + default String getName() { + return "spring.dapr.template"; + } + +} diff --git a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DefaultDaprTemplateObservationConvention.java b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DefaultDaprTemplateObservationConvention.java new file mode 100644 index 000000000..4bf57b1b5 --- /dev/null +++ b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DefaultDaprTemplateObservationConvention.java @@ -0,0 +1,35 @@ +package io.dapr.spring.messaging.observation; + +import io.micrometer.common.KeyValues; + +/** + * Default {@link DefaultDaprTemplateObservationConvention} for Pulsar template key values. + * + */ +public class DefaultDaprTemplateObservationConvention implements DaprTemplateObservationConvention { + + /** + * A singleton instance of the convention. + */ + public static final DefaultDaprTemplateObservationConvention INSTANCE = + new DefaultDaprTemplateObservationConvention(); + + @Override + public KeyValues getLowCardinalityKeyValues(DaprMessageSenderContext context) { + return KeyValues.of(DaprTemplateObservation.TemplateLowCardinalityTags.BEAN_NAME.asString(), + context.getBeanName()); + } + + // Remove once addressed: + // https://github.com/micrometer-metrics/micrometer-docs-generator/issues/30 + @Override + public String getName() { + return "spring.dapr.template"; + } + + @Override + public String getContextualName(DaprMessageSenderContext context) { + return context.getDestination() + " send"; + } + +} From 28403883d2fe8ba023a83aa5ebd120f2768d5b21 Mon Sep 17 00:00:00 2001 From: salaboy Date: Fri, 4 Oct 2024 10:36:21 +0100 Subject: [PATCH 07/14] adding observation in messaging and data Signed-off-by: salaboy --- .../dapr-spring-boot-autoconfigure/pom.xml | 18 +-- .../data/observation/DaprKeyValueContext.java | 81 +++++++++++ .../DaprKeyValueTemplateObservation.java | 56 ++++++++ ...KeyValueTemplateObservationConvention.java | 23 ++++ ...KeyValueTemplateObservationConvention.java | 35 +++++ dapr-spring/dapr-spring-messaging/pom.xml | 4 + .../messaging/DaprMessagingTemplate.java | 130 +++++++----------- .../observation/DaprMessageSenderContext.java | 6 +- .../observation/DaprTemplateObservation.java | 4 +- .../DaprTemplateObservationConvention.java | 2 +- ...aultDaprTemplateObservationConvention.java | 4 +- 11 files changed, 258 insertions(+), 105 deletions(-) create mode 100644 dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DaprKeyValueContext.java create mode 100644 dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DaprKeyValueTemplateObservation.java create mode 100644 dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DaprKeyValueTemplateObservationConvention.java create mode 100644 dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DefaultDaprKeyValueTemplateObservationConvention.java diff --git a/dapr-spring/dapr-spring-boot-autoconfigure/pom.xml b/dapr-spring/dapr-spring-boot-autoconfigure/pom.xml index 87be8844b..742250424 100644 --- a/dapr-spring/dapr-spring-boot-autoconfigure/pom.xml +++ b/dapr-spring/dapr-spring-boot-autoconfigure/pom.xml @@ -31,6 +31,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-autoconfigure + org.springframework.boot spring-boot-autoconfigure-processor @@ -44,20 +48,6 @@ io.opentelemetry opentelemetry-exporter-otlp - - io.opentelemetry.instrumentation - opentelemetry-instrumentation-annotations - 2.8.0 - - - io.micrometer - micrometer-registry-otlp - - - net.ttddyy.observation - datasource-micrometer-spring-boot - 1.0.5 - org.springframework.data spring-data-keyvalue diff --git a/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DaprKeyValueContext.java b/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DaprKeyValueContext.java new file mode 100644 index 000000000..7274ad11e --- /dev/null +++ b/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DaprKeyValueContext.java @@ -0,0 +1,81 @@ +package io.dapr.spring.data.observation; + +import io.micrometer.observation.transport.SenderContext; + +import java.util.HashMap; +import java.util.Map; + + +/** + * {@link SenderContext} for Dapr KeyValue context. + * + */ +public final class DaprKeyValueContext extends SenderContext { + + private final String beanName; + + private final String keyValueStore; + + + private DaprKeyValueContext(KeyValueHolder keyValueHolder, String keyValueStore, String beanName) { + super((carrier, key, value) -> keyValueHolder.property(key, value)); + setCarrier(keyValueHolder); + this.beanName = beanName; + this.keyValueStore = keyValueStore; + } + + /** + * Create a new context. + * @param kvStore KVStore to be used + * @param beanName name of the bean used usually (typically a {@code DaprMessagingTemplate}) + * @return DaprMessageSenderContext + */ + public static DaprKeyValueContext newContext(String kvStore, String beanName) { + KeyValueHolder keyValueHolder = new KeyValueHolder(); + return new DaprKeyValueContext(keyValueHolder, kvStore, beanName); + } + + public Map properties() { + return getCarrier().properties(); + } + + + /** + * The name of the bean sending the message (typically a {@code DaprMessagingTemplate}). + * @return the name of the bean sending the message + */ + public String getBeanName() { + return this.beanName; + } + + /** + * The destination topic for the message. + * @return the topic the message is being sent to + */ + public String getKeyValueStore() { + return this.keyValueStore; + } + + + /** + * Acts as a carrier for a Dapr KeyValue and records the propagated properties for + * later access by the Dapr. + */ + public static final class KeyValueHolder { + + private final Map properties = new HashMap<>(); + + private KeyValueHolder() { + } + + public void property(String key, String value) { + this.properties.put(key, value); + } + + public Map properties() { + return this.properties; + } + + } + +} diff --git a/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DaprKeyValueTemplateObservation.java b/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DaprKeyValueTemplateObservation.java new file mode 100644 index 000000000..a98431d1b --- /dev/null +++ b/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DaprKeyValueTemplateObservation.java @@ -0,0 +1,56 @@ +package io.dapr.spring.data.observation; + +import io.micrometer.common.docs.KeyName; +import io.micrometer.observation.Observation; +import io.micrometer.observation.Observation.Context; +import io.micrometer.observation.ObservationConvention; +import io.micrometer.observation.docs.ObservationDocumentation; + +/** + * An {@link Observation} for {@link io.dapr.spring.data.DaprKeyValueTemplate}. + * + */ +public enum DaprKeyValueTemplateObservation implements ObservationDocumentation { + + /** + * Observation created when a Dapr template interacts with a KVStore. + */ + TEMPLATE_OBSERVATION { + + @Override + public Class> getDefaultConvention() { + return DefaultDaprKeyValueTemplateObservationConvention.class; + } + + @Override + public String getPrefix() { + return "spring.dapr.data.template"; + } + + @Override + public KeyName[] getLowCardinalityKeyNames() { + return TemplateLowCardinalityTags.values(); + } + + }; + + /** + * Low cardinality tags. + */ + public enum TemplateLowCardinalityTags implements KeyName { + + /** + * Bean name of the template that interacts with the kv store. + */ + BEAN_NAME { + + @Override + public String asString() { + return "spring.dapr.data.template.name"; + } + + } + + } + +} diff --git a/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DaprKeyValueTemplateObservationConvention.java b/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DaprKeyValueTemplateObservationConvention.java new file mode 100644 index 000000000..623899f6b --- /dev/null +++ b/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DaprKeyValueTemplateObservationConvention.java @@ -0,0 +1,23 @@ +package io.dapr.spring.data.observation; + + +import io.micrometer.observation.Observation.Context; +import io.micrometer.observation.ObservationConvention; + +/** + * {@link ObservationConvention} for Dapr KV template . + * + */ +public interface DaprKeyValueTemplateObservationConvention extends ObservationConvention { + + @Override + default boolean supportsContext(Context context) { + return context instanceof DaprKeyValueContext; + } + + @Override + default String getName() { + return "spring.dapr.data.template"; + } + +} diff --git a/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DefaultDaprKeyValueTemplateObservationConvention.java b/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DefaultDaprKeyValueTemplateObservationConvention.java new file mode 100644 index 000000000..acde9dd65 --- /dev/null +++ b/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DefaultDaprKeyValueTemplateObservationConvention.java @@ -0,0 +1,35 @@ +package io.dapr.spring.data.observation; + +import io.micrometer.common.KeyValues; + +/** + * Default {@link DefaultDaprKeyValueTemplateObservationConvention} for Dapr template key values. + * + */ +public class DefaultDaprKeyValueTemplateObservationConvention implements DaprKeyValueTemplateObservationConvention { + + /** + * A singleton instance of the convention. + */ + public static final DefaultDaprKeyValueTemplateObservationConvention INSTANCE = + new DefaultDaprKeyValueTemplateObservationConvention(); + + @Override + public KeyValues getLowCardinalityKeyValues(DaprKeyValueContext context) { + return KeyValues.of(DaprKeyValueTemplateObservation.TemplateLowCardinalityTags.BEAN_NAME.asString(), + context.getBeanName()); + } + + // Remove once addressed: + // https://github.com/micrometer-metrics/micrometer-docs-generator/issues/30 + @Override + public String getName() { + return "spring.dapr.data.template"; + } + + @Override + public String getContextualName(DaprKeyValueContext context) { + return context.getKeyValueStore() + " store"; + } + +} diff --git a/dapr-spring/dapr-spring-messaging/pom.xml b/dapr-spring/dapr-spring-messaging/pom.xml index 36f4179cf..e761aebd7 100644 --- a/dapr-spring/dapr-spring-messaging/pom.xml +++ b/dapr-spring/dapr-spring-messaging/pom.xml @@ -17,6 +17,10 @@ io.opentelemetry opentelemetry-api + + io.micrometer + micrometer-tracing + jar diff --git a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java index 0eed0b0d1..6d94fdeb4 100644 --- a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java +++ b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java @@ -21,18 +21,17 @@ import io.dapr.spring.messaging.observation.DefaultDaprTemplateObservationConvention; import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationRegistry; -import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.ContextKey; -import io.opentelemetry.context.propagation.TextMapSetter; +import io.micrometer.tracing.Tracer; +import io.opentelemetry.api.OpenTelemetry; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.log.LogAccessor; import org.springframework.lang.Nullable; +import reactor.core.publisher.Hooks; import reactor.core.publisher.Mono; - +import reactor.util.context.Context; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -56,6 +55,18 @@ public class DaprMessagingTemplate implements DaprMessagingOperations, */ private final boolean observationEnabled; + /** + * Micrometer's Tracer. + */ + @Nullable + private Tracer tracer; + + /** + * Micrometer's Tracer. + */ + @Nullable + private OpenTelemetry openTelemetry; + /** * The registry to record observations with. */ @@ -71,6 +82,7 @@ public class DaprMessagingTemplate implements DaprMessagingOperations, @Nullable private ApplicationContext applicationContext; + private String beanName = ""; /** @@ -84,6 +96,7 @@ public DaprMessagingTemplate(DaprClient daprClient, String pubsubName, boolean o this.daprClient = daprClient; this.pubsubName = pubsubName; this.observationEnabled = observationEnabled; + Hooks.enableAutomaticContextPropagation(); } /** @@ -102,6 +115,10 @@ public void afterSingletonsInstantiated() { } this.observationRegistry = this.applicationContext.getBeanProvider(ObservationRegistry.class) .getIfUnique(() -> this.observationRegistry); + this.tracer = this.applicationContext.getBeanProvider(Tracer.class) + .getIfUnique(() -> this.tracer); + this.openTelemetry = this.applicationContext.getBeanProvider(OpenTelemetry.class) + .getIfUnique(() -> this.openTelemetry); this.observationConvention = this.applicationContext.getBeanProvider(DaprTemplateObservationConvention.class) .getIfUnique(() -> this.observationConvention); } @@ -131,95 +148,42 @@ private void doSend(String topic, T message) { } private Mono doSendAsync(String topic, T message) { - this.logger.trace(() -> "Sending msg to '%s' topic".formatted(topic)); DaprMessageSenderContext senderContext = DaprMessageSenderContext.newContext(topic, this.beanName); Observation observation = newObservation(senderContext); - observation.start(); - - - return daprClient.publishEvent(pubsubName, - topic, - message, - Collections.singletonMap(Metadata.TTL_IN_SECONDS, MESSAGE_TTL_IN_SECONDS)) - .contextWrite(getReactorContext(observation.getContextView())).doOnError( - (err) -> { - - this.logger.error(err, () -> "Failed to send msg to '%s' topic".formatted(topic)); - observation.error(err); - observation.stop(); - } - ).doOnSuccess((err) -> { - this.logger.trace(() -> "Sent msg to '%s' topic".formatted(topic)); - observation.stop(); - }); - } - /** - * Converts current OpenTelemetry's context into Reactor's context. - * @return Reactor's context. - */ - public static reactor.util.context.ContextView getReactorContext() { - return getReactorContext(Context.current()); - } - - /** - * Converts given OpenTelemetry's context into Reactor's context. - * @param context OpenTelemetry's context. - * @return Reactor's context. - */ - public static reactor.util.context.Context getReactorContext(Context context) { - Map map = new HashMap<>(); - TextMapSetter> setter = - (carrier, key, value) -> map.put(key, value); - - GlobalOpenTelemetry.getPropagators().getTextMapPropagator().inject(context, map, setter); - reactor.util.context.Context reactorContext = reactor.util.context.Context.empty(); - for (Map.Entry entry : map.entrySet()) { - reactorContext = reactorContext.put(entry.getKey(), entry.getValue()); - } - return reactorContext; + return observation.observe(() -> { + System.out.printf("**** Sending [%s]%n", message); + + return daprClient.publishEvent(pubsubName, + topic, + message, + Collections.singletonMap(Metadata.TTL_IN_SECONDS, MESSAGE_TTL_IN_SECONDS)) + .contextWrite(this::addTracingHeaders) + .doOnError( + (err) -> { + + this.logger.error(err, () -> "Failed to send msg to '%s' topic".formatted(topic)); + observation.error(err); + observation.stop(); + } + ).doOnSuccess((err) -> { + this.logger.trace(() -> "Sent msg to '%s' topic".formatted(topic)); + observation.stop(); + }); + }); } - /** - * Converts given Micrometer's context into Reactor's context. - * @param contextView Micrometers's contextView. - * @return Reactor's context. - */ - public static reactor.util.context.Context getReactorContext(io.micrometer.observation.Observation.ContextView - contextView) { + private Context addTracingHeaders(reactor.util.context.Context context) { Map map = new HashMap<>(); - TextMapSetter> setter = - (carrier, key, value) -> map.put(key, value); - - final reactor.util.context.Context reactorContext = reactor.util.context.Context.empty(); - - contextView.getAllKeyValues().forEach((entry) -> { - reactorContext.put(entry.getKey(), entry.getValue()); - }); - - Context otelContext = Context.root(); - reactorContext.stream() - .forEach(entry -> { - Object key = entry.getKey(); - Object value = entry.getValue(); - - // Create a Context.Key for OpenTelemetry - ContextKey otelKey = ContextKey.named(key.toString()); - - // Store the entry in OpenTelemetry Context - otelContext.with(otelKey, value); + openTelemetry.getPropagators().getTextMapPropagator() + .inject(io.opentelemetry.context.Context.current(), map, (carrier, key, value) -> { + map.put(key, value); }); - - GlobalOpenTelemetry.getPropagators().getTextMapPropagator() - .inject(otelContext, map, setter); - return reactorContext; + return context.putAll(Context.of(map).readOnly()); } - - - private Observation newObservation(DaprMessageSenderContext senderContext) { if (this.observationRegistry == null) { return Observation.NOOP; diff --git a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprMessageSenderContext.java b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprMessageSenderContext.java index 7f2780de4..6e8a86de3 100644 --- a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprMessageSenderContext.java +++ b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprMessageSenderContext.java @@ -6,7 +6,7 @@ /** - * {@link SenderContext} for Dapr messages. + * {@link SenderContext} for Dapr Messaging. * */ public final class DaprMessageSenderContext extends SenderContext { @@ -57,8 +57,8 @@ public String getDestination() { /** - * Acts as a carrier for a Pulsar message and records the propagated properties for - * later access by the Pulsar message builder. + * Acts as a carrier for a Dapr message and records the propagated properties for + * later access by the Dapr. */ public static final class MessageHolder { diff --git a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprTemplateObservation.java b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprTemplateObservation.java index b091246cc..9d7742905 100644 --- a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprTemplateObservation.java +++ b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprTemplateObservation.java @@ -24,7 +24,7 @@ public Class> getDefaultConve @Override public String getPrefix() { - return "spring.dapr.template"; + return "spring.dapr.messaging.template"; } @Override @@ -46,7 +46,7 @@ public enum TemplateLowCardinalityTags implements KeyName { @Override public String asString() { - return "spring.dapr.template.name"; + return "spring.dapr.messaging.template.name"; } } diff --git a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprTemplateObservationConvention.java b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprTemplateObservationConvention.java index 2ef8952f0..9fdcac854 100644 --- a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprTemplateObservationConvention.java +++ b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DaprTemplateObservationConvention.java @@ -17,7 +17,7 @@ default boolean supportsContext(Context context) { @Override default String getName() { - return "spring.dapr.template"; + return "spring.dapr.messaging.template"; } } diff --git a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DefaultDaprTemplateObservationConvention.java b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DefaultDaprTemplateObservationConvention.java index 4bf57b1b5..8be852249 100644 --- a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DefaultDaprTemplateObservationConvention.java +++ b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/observation/DefaultDaprTemplateObservationConvention.java @@ -3,7 +3,7 @@ import io.micrometer.common.KeyValues; /** - * Default {@link DefaultDaprTemplateObservationConvention} for Pulsar template key values. + * Default {@link DefaultDaprTemplateObservationConvention} for Dapr template key values. * */ public class DefaultDaprTemplateObservationConvention implements DaprTemplateObservationConvention { @@ -24,7 +24,7 @@ public KeyValues getLowCardinalityKeyValues(DaprMessageSenderContext context) { // https://github.com/micrometer-metrics/micrometer-docs-generator/issues/30 @Override public String getName() { - return "spring.dapr.template"; + return "spring.dapr.messaging.template"; } @Override From cac7e27e2b1155bfb3f1d93618e5a53b0465cac1 Mon Sep 17 00:00:00 2001 From: artur-ciocanu Date: Thu, 26 Sep 2024 20:41:08 +0300 Subject: [PATCH 08/14] Ensure we use the same GRPC version everywhere (#1137) * Ensure we use the same GRPC version everywhere Signed-off-by: Artur Ciocanu * Fix actors tests assert Signed-off-by: Artur Ciocanu * Revert Dapr exception asserts Signed-off-by: Artur Ciocanu * Increase sleep to allow Spring Context to bootstrap Signed-off-by: Artur Ciocanu * Revert sleep value Signed-off-by: Artur Ciocanu * Increase the sleep for messaging test Signed-off-by: Artur Ciocanu * Move sleep before each, to ensure Spring context starts Signed-off-by: Artur Ciocanu * Add more delays to ensure Spring Controller gets the messages Signed-off-by: Artur Ciocanu --------- Signed-off-by: Artur Ciocanu Co-authored-by: Artur Ciocanu Signed-off-by: salaboy --- pom.xml | 4 ++-- sdk-actors/pom.xml | 1 - .../java/io/dapr/actors/client/DaprGrpcClientTest.java | 2 +- .../java/io/dapr/actors/runtime/DaprGrpcClientTest.java | 4 ++-- .../dapr/it/spring/messaging/DaprSpringMessagingIT.java | 8 ++++++-- sdk/pom.xml | 1 - 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index c8cf9699c..17573f976 100644 --- a/pom.xml +++ b/pom.xml @@ -104,13 +104,13 @@ io.grpc grpc-testing - 1.56.1 + ${grpc.version} test io.grpc grpc-inprocess - 1.59.0 + ${grpc.version} test diff --git a/sdk-actors/pom.xml b/sdk-actors/pom.xml index e24f33ecb..940d25609 100644 --- a/sdk-actors/pom.xml +++ b/sdk-actors/pom.xml @@ -18,7 +18,6 @@ false - 1.59.0 diff --git a/sdk-actors/src/test/java/io/dapr/actors/client/DaprGrpcClientTest.java b/sdk-actors/src/test/java/io/dapr/actors/client/DaprGrpcClientTest.java index aeb450c9a..313eca5a7 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/client/DaprGrpcClientTest.java +++ b/sdk-actors/src/test/java/io/dapr/actors/client/DaprGrpcClientTest.java @@ -129,7 +129,7 @@ public void invokeException() { ExecutionException.class, "UNKNOWN", "UNKNOWN: ", - () -> result.block()); + result::block); } @Test diff --git a/sdk-actors/src/test/java/io/dapr/actors/runtime/DaprGrpcClientTest.java b/sdk-actors/src/test/java/io/dapr/actors/runtime/DaprGrpcClientTest.java index 815186e60..335ea575f 100644 --- a/sdk-actors/src/test/java/io/dapr/actors/runtime/DaprGrpcClientTest.java +++ b/sdk-actors/src/test/java/io/dapr/actors/runtime/DaprGrpcClientTest.java @@ -96,7 +96,7 @@ public void getActorStateException() { assertThrowsDaprException( ExecutionException.class, "UNKNOWN", - "UNKNOWN: ", + "UNKNOWN: Application error processing RPC", result::block); } @@ -112,7 +112,7 @@ public void saveActorStateTransactionallyException() { assertThrowsDaprException( ExecutionException.class, "UNKNOWN", - "UNKNOWN: ", + "UNKNOWN: Application error processing RPC", result::block); } @Test diff --git a/sdk-tests/src/test/java/io/dapr/it/spring/messaging/DaprSpringMessagingIT.java b/sdk-tests/src/test/java/io/dapr/it/spring/messaging/DaprSpringMessagingIT.java index 19b6e3252..50d5b9114 100644 --- a/sdk-tests/src/test/java/io/dapr/it/spring/messaging/DaprSpringMessagingIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/spring/messaging/DaprSpringMessagingIT.java @@ -76,10 +76,15 @@ public class DaprSpringMessagingIT { private TestRestController testRestController; @BeforeAll - public static void setup(){ + public static void beforeAll(){ org.testcontainers.Testcontainers.exposeHostPorts(8080); } + @BeforeEach + public void beforeEach() throws InterruptedException { + Thread.sleep(1000); + } + @Test public void testDaprMessagingTemplate() throws InterruptedException { for (int i = 0; i < 10; i++) { @@ -97,5 +102,4 @@ public void testDaprMessagingTemplate() throws InterruptedException { assertThat(events.size()).isEqualTo(10); } - } diff --git a/sdk/pom.xml b/sdk/pom.xml index 66095e0b2..efa79cd6c 100644 --- a/sdk/pom.xml +++ b/sdk/pom.xml @@ -18,7 +18,6 @@ false - 1.59.0 --add-opens java.base/java.util=ALL-UNNAMED From 9bcfc7b44d98c734d6ce67a42a86e22fa1c00d3c Mon Sep 17 00:00:00 2001 From: Artur Souza Date: Wed, 2 Oct 2024 15:54:48 -0700 Subject: [PATCH 09/14] Remove all global state from setProperty (#1138) * Remove all global state in from setProperty Signed-off-by: Artur Souza * use Map.of Signed-off-by: Artur Souza * Remove dependency that is not needed. Signed-off-by: Artur Souza --------- Signed-off-by: Artur Souza Signed-off-by: salaboy --- .github/workflows/build.yml | 6 +-- .github/workflows/validate.yml | 6 +-- .../client/DaprClientAutoConfiguration.java | 16 ++++-- .../data/AbstractDaprKeyValueAdapter.java | 2 +- .../spring/data/MySQLDaprKeyValueAdapter.java | 4 +- .../data/PostgreSQLDaprKeyValueAdapter.java | 4 +- .../messaging/DaprMessagingTemplate.java | 4 ++ .../examples/pubsub/CloudEventPublisher.java | 3 +- .../io/dapr/actors/client/ActorClient.java | 38 ++++++++++---- .../src/test/java/io/dapr/it/BaseIT.java | 51 ++++--------------- .../src/test/java/io/dapr/it/DaprPorts.java | 28 +++++----- .../src/test/java/io/dapr/it/DaprRun.java | 21 +++++++- .../test/java/io/dapr/it/ToxiProxyRun.java | 28 ++++++++-- .../it/actors/ActivationDeactivationIT.java | 5 +- .../io/dapr/it/actors/ActorExceptionIT.java | 4 +- .../io/dapr/it/actors/ActorMethodNameIT.java | 6 +-- .../it/actors/ActorReminderFailoverIT.java | 6 +-- .../it/actors/ActorReminderRecoveryIT.java | 3 +- .../dapr/it/actors/ActorSdkResiliencyIT.java | 20 ++++---- .../java/io/dapr/it/actors/ActorStateIT.java | 44 +++++----------- .../dapr/it/actors/ActorTimerRecoveryIT.java | 2 +- .../actors/ActorTurnBasedConcurrencyIT.java | 4 +- .../src/test/java/io/dapr/it/api/ApiIT.java | 2 +- .../io/dapr/it/binding/http/BindingIT.java | 15 +++--- .../configuration/ConfigurationClientIT.java | 2 +- .../it/methodinvoke/grpc/MethodInvokeIT.java | 6 +-- .../it/methodinvoke/http/MethodInvokeIT.java | 8 +-- .../java/io/dapr/it/pubsub/http/PubSubIT.java | 31 +++++------ .../dapr/it/resiliency/SdkResiliencyIT.java | 9 ++-- .../io/dapr/it/secrets/SecretsClientIT.java | 2 +- .../spring/data/DaprKeyValueRepositoryIT.java | 2 +- .../data/MySQLDaprKeyValueTemplateIT.java | 4 +- .../PostgreSQLDaprKeyValueTemplateIT.java | 4 +- .../messaging/DaprSpringMessagingIT.java | 2 + .../io/dapr/it/state/GRPCStateClientIT.java | 2 +- .../it/testcontainers/DaprContainerIT.java | 3 +- .../it/testcontainers/DaprWorkflowsIT.java | 3 +- .../io/dapr/it/tracing/grpc/TracingIT.java | 2 +- .../io/dapr/it/tracing/http/TracingIT.java | 2 +- .../io/dapr/client/DaprClientBuilder.java | 14 ++++- .../main/java/io/dapr/client/DaprHttp.java | 3 +- .../dapr/client/DaprTracingInterceptor.java | 48 ----------------- .../dapr/client/domain/BulkPublishEntry.java | 5 +- .../client/domain/BulkPublishRequest.java | 6 +-- .../main/java/io/dapr/config/Properties.java | 17 +++++-- .../main/java/io/dapr/config/Property.java | 8 +++ .../io/dapr/exceptions/DaprErrorDetails.java | 26 +++++----- .../io/dapr/client/DaprClientBuilderTest.java | 1 - .../io/dapr/client/DaprClientHttpTest.java | 4 -- .../java/io/dapr/client/DaprHttpTest.java | 5 +- .../java/io/dapr/utils/NetworkUtilsTest.java | 40 ++++++++------- 51 files changed, 285 insertions(+), 296 deletions(-) delete mode 100644 sdk/src/main/java/io/dapr/client/DaprTracingInterceptor.java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 070f163dc..e4964523b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,9 +38,9 @@ jobs: GOARCH: amd64 GOPROXY: https://proxy.golang.org JDK_VER: ${{ matrix.java }} - DAPR_CLI_VER: 1.14.0-rc.6 - DAPR_RUNTIME_VER: 1.14.0-rc.6 - DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/v1.14.0-rc.4/install/install.sh + DAPR_CLI_VER: 1.14.0 + DAPR_RUNTIME_VER: 1.14.4 + DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/v1.14.0/install/install.sh DAPR_CLI_REF: DAPR_REF: TOXIPROXY_URL: https://github.com/Shopify/toxiproxy/releases/download/v2.5.0/toxiproxy-server-linux-amd64 diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index ef6bc85b0..58ea173f9 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -37,9 +37,9 @@ jobs: GOARCH: amd64 GOPROXY: https://proxy.golang.org JDK_VER: ${{ matrix.java }} - DAPR_CLI_VER: 1.14.0-rc.6 - DAPR_RUNTIME_VER: 1.14.0-rc.6 - DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/v1.14.0-rc.3/install/install.sh + DAPR_CLI_VER: 1.14.0 + DAPR_RUNTIME_VER: 1.14.4 + DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/v1.14.0/install/install.sh DAPR_CLI_REF: DAPR_REF: steps: diff --git a/dapr-spring/dapr-spring-boot-autoconfigure/src/main/java/io/dapr/spring/boot/autoconfigure/client/DaprClientAutoConfiguration.java b/dapr-spring/dapr-spring-boot-autoconfigure/src/main/java/io/dapr/spring/boot/autoconfigure/client/DaprClientAutoConfiguration.java index 3aa422cf1..f77683424 100644 --- a/dapr-spring/dapr-spring-boot-autoconfigure/src/main/java/io/dapr/spring/boot/autoconfigure/client/DaprClientAutoConfiguration.java +++ b/dapr-spring/dapr-spring-boot-autoconfigure/src/main/java/io/dapr/spring/boot/autoconfigure/client/DaprClientAutoConfiguration.java @@ -37,10 +37,18 @@ DaprConnectionDetails daprConnectionDetails(DaprClientProperties properties) { @ConditionalOnMissingBean DaprClientBuilder daprClientBuilder(DaprConnectionDetails daprConnectionDetails) { DaprClientBuilder builder = new DaprClientBuilder(); - builder.withPropertyOverride(Properties.HTTP_ENDPOINT, daprConnectionDetails.httpEndpoint()); - builder.withPropertyOverride(Properties.GRPC_ENDPOINT, daprConnectionDetails.grpcEndpoint()); - builder.withPropertyOverride(Properties.HTTP_PORT, String.valueOf(daprConnectionDetails.httpPort())); - builder.withPropertyOverride(Properties.GRPC_PORT, String.valueOf(daprConnectionDetails.grpcPort())); + if (daprConnectionDetails.httpEndpoint() != null) { + builder.withPropertyOverride(Properties.HTTP_ENDPOINT, daprConnectionDetails.httpEndpoint()); + } + if (daprConnectionDetails.grpcEndpoint() != null) { + builder.withPropertyOverride(Properties.GRPC_ENDPOINT, daprConnectionDetails.grpcEndpoint()); + } + if (daprConnectionDetails.httpPort() != null) { + builder.withPropertyOverride(Properties.HTTP_PORT, String.valueOf(daprConnectionDetails.httpPort())); + } + if (daprConnectionDetails.grpcPort() != null) { + builder.withPropertyOverride(Properties.GRPC_PORT, String.valueOf(daprConnectionDetails.grpcPort())); + } return builder; } diff --git a/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/AbstractDaprKeyValueAdapter.java b/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/AbstractDaprKeyValueAdapter.java index ecacda243..82b59dbd6 100644 --- a/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/AbstractDaprKeyValueAdapter.java +++ b/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/AbstractDaprKeyValueAdapter.java @@ -27,7 +27,7 @@ import java.util.Map; public abstract class AbstractDaprKeyValueAdapter implements KeyValueAdapter { - private static final Map CONTENT_TYPE_META = Collections.singletonMap( + private static final Map CONTENT_TYPE_META = Map.of( "contentType", "application/json"); private final DaprClient daprClient; diff --git a/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/MySQLDaprKeyValueAdapter.java b/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/MySQLDaprKeyValueAdapter.java index ad401817f..16701ba23 100644 --- a/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/MySQLDaprKeyValueAdapter.java +++ b/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/MySQLDaprKeyValueAdapter.java @@ -164,13 +164,13 @@ private String createSql(String sqlPattern, String keyspace, Object criteria) { } private void execUsingBinding(String sql) { - Map meta = Collections.singletonMap("sql", sql); + Map meta = Map.of("sql", sql); daprClient.invokeBinding(bindingName, "exec", null, meta).block(); } private T queryUsingBinding(String sql, TypeRef typeRef) { - Map meta = Collections.singletonMap("sql", sql); + Map meta = Map.of("sql", sql); return daprClient.invokeBinding(bindingName, "query", null, meta, typeRef).block(); } diff --git a/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/PostgreSQLDaprKeyValueAdapter.java b/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/PostgreSQLDaprKeyValueAdapter.java index 40c22db2f..e5cbf2b48 100644 --- a/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/PostgreSQLDaprKeyValueAdapter.java +++ b/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/PostgreSQLDaprKeyValueAdapter.java @@ -172,13 +172,13 @@ private String createSql(String sqlPattern, String keyspace, Object criteria) { } private void execUsingBinding(String sql) { - Map meta = Collections.singletonMap("sql", sql); + Map meta = Map.of("sql", sql); daprClient.invokeBinding(bindingName, "exec", null, meta).block(); } private T queryUsingBinding(String sql, TypeRef typeRef) { - Map meta = Collections.singletonMap("sql", sql); + Map meta = Map.of("sql", sql); return daprClient.invokeBinding(bindingName, "query", null, meta, typeRef).block(); } diff --git a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java index 6d94fdeb4..03e4cb61b 100644 --- a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java +++ b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java @@ -31,9 +31,13 @@ import org.springframework.lang.Nullable; import reactor.core.publisher.Hooks; import reactor.core.publisher.Mono; +<<<<<<< HEAD import reactor.util.context.Context; import java.util.Collections; import java.util.HashMap; +======= + +>>>>>>> 7490434d (Remove all global state from setProperty (#1138)) import java.util.Map; /** diff --git a/examples/src/main/java/io/dapr/examples/pubsub/CloudEventPublisher.java b/examples/src/main/java/io/dapr/examples/pubsub/CloudEventPublisher.java index 62264e34f..fbe23a244 100644 --- a/examples/src/main/java/io/dapr/examples/pubsub/CloudEventPublisher.java +++ b/examples/src/main/java/io/dapr/examples/pubsub/CloudEventPublisher.java @@ -19,6 +19,7 @@ import io.dapr.client.domain.Metadata; import io.dapr.client.domain.PublishEventRequest; +import java.util.Map; import java.util.UUID; import static java.util.Collections.singletonMap; @@ -66,7 +67,7 @@ public static void main(String[] args) throws Exception { client.publishEvent( new PublishEventRequest(PUBSUB_NAME, TOPIC_NAME, cloudEvent) .setContentType(CloudEvent.CONTENT_TYPE) - .setMetadata(singletonMap(Metadata.TTL_IN_SECONDS, MESSAGE_TTL_IN_SECONDS))).block(); + .setMetadata(Map.of(Metadata.TTL_IN_SECONDS, MESSAGE_TTL_IN_SECONDS))).block(); System.out.println("Published cloud event with message: " + cloudEvent.getData()); try { diff --git a/sdk-actors/src/main/java/io/dapr/actors/client/ActorClient.java b/sdk-actors/src/main/java/io/dapr/actors/client/ActorClient.java index 6befd413f..c2d7a4444 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/client/ActorClient.java +++ b/sdk-actors/src/main/java/io/dapr/actors/client/ActorClient.java @@ -20,8 +20,6 @@ import io.grpc.Channel; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import reactor.core.publisher.Mono; /** @@ -29,8 +27,6 @@ */ public class ActorClient implements AutoCloseable { - private static final Logger LOGGER = LoggerFactory.getLogger(ActorClient.class); - /** * gRPC channel for communication with Dapr sidecar. */ @@ -45,7 +41,7 @@ public class ActorClient implements AutoCloseable { * Instantiates a new channel for Dapr sidecar communication. */ public ActorClient() { - this(null); + this(new Properties(), null); } /** @@ -53,8 +49,27 @@ public ActorClient() { * * @param resiliencyOptions Client resiliency options. */ - private ActorClient(ResiliencyOptions resiliencyOptions) { - this(buildManagedChannel(), resiliencyOptions); + public ActorClient(ResiliencyOptions resiliencyOptions) { + this(new Properties(), resiliencyOptions); + } + + /** + * Instantiates a new channel for Dapr sidecar communication. + * + * @param overrideProperties Override properties. + */ + public ActorClient(Properties overrideProperties) { + this(buildManagedChannel(overrideProperties), null); + } + + /** + * Instantiates a new channel for Dapr sidecar communication. + * + * @param overrideProperties Override properties. + * @param resiliencyOptions Client resiliency options. + */ + public ActorClient(Properties overrideProperties, ResiliencyOptions resiliencyOptions) { + this(buildManagedChannel(overrideProperties), resiliencyOptions); } /** @@ -96,15 +111,18 @@ public void close() { /** * Creates a GRPC managed channel (or null, if not applicable). * + * @param overrideProperties Overrides * @return GRPC managed channel or null. */ - private static ManagedChannel buildManagedChannel() { - int port = Properties.GRPC_PORT.get(); + private static ManagedChannel buildManagedChannel(Properties overrideProperties) { + int port = overrideProperties.getValue(Properties.GRPC_PORT); if (port <= 0) { throw new IllegalArgumentException("Invalid port."); } - return ManagedChannelBuilder.forAddress(Properties.SIDECAR_IP.get(), port) + var sidecarHost = overrideProperties.getValue(Properties.SIDECAR_IP); + + return ManagedChannelBuilder.forAddress(sidecarHost, port) .usePlaintext() .userAgent(Version.getSdkVersion()) .build(); diff --git a/sdk-tests/src/test/java/io/dapr/it/BaseIT.java b/sdk-tests/src/test/java/io/dapr/it/BaseIT.java index abef394b7..f50025e21 100644 --- a/sdk-tests/src/test/java/io/dapr/it/BaseIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/BaseIT.java @@ -15,6 +15,7 @@ import io.dapr.actors.client.ActorClient; import io.dapr.client.resiliency.ResiliencyOptions; +import io.dapr.config.Properties; import org.apache.commons.lang3.tuple.ImmutablePair; import org.junit.jupiter.api.AfterAll; @@ -46,7 +47,7 @@ protected static DaprRun startDaprApp( Class serviceClass, Boolean useAppPort, int maxWaitMilliseconds) throws Exception { - return startDaprApp(testName, successMessage, serviceClass, useAppPort, maxWaitMilliseconds, GRPC); + return startDaprApp(testName, successMessage, serviceClass, useAppPort, maxWaitMilliseconds, HTTP); } protected static DaprRun startDaprApp( @@ -55,7 +56,7 @@ protected static DaprRun startDaprApp( Class serviceClass, AppRun.AppProtocol appProtocol, int maxWaitMilliseconds) throws Exception { - return startDaprApp(testName, successMessage, serviceClass, true, maxWaitMilliseconds, GRPC, appProtocol); + return startDaprApp(testName, successMessage, serviceClass, true, maxWaitMilliseconds, appProtocol); } protected static DaprRun startDaprApp( @@ -64,25 +65,6 @@ protected static DaprRun startDaprApp( Class serviceClass, Boolean useAppPort, int maxWaitMilliseconds, - AppRun.AppProtocol protocol) throws Exception { - return startDaprApp( - testName, - successMessage, - serviceClass, - useAppPort, - true, - maxWaitMilliseconds, - protocol, - HTTP); - } - - protected static DaprRun startDaprApp( - String testName, - String successMessage, - Class serviceClass, - Boolean useAppPort, - int maxWaitMilliseconds, - AppRun.AppProtocol protocol, AppRun.AppProtocol appProtocol) throws Exception { return startDaprApp( testName, @@ -91,7 +73,6 @@ protected static DaprRun startDaprApp( useAppPort, true, maxWaitMilliseconds, - protocol, appProtocol); } @@ -105,7 +86,6 @@ protected static DaprRun startDaprApp( false, true, maxWaitMilliseconds, - GRPC, HTTP); } @@ -116,7 +96,6 @@ protected static DaprRun startDaprApp( Boolean useAppPort, Boolean useDaprPorts, int maxWaitMilliseconds, - AppRun.AppProtocol protocol, AppRun.AppProtocol appProtocol) throws Exception { DaprRun.Builder builder = new DaprRun.Builder( testName, @@ -128,7 +107,6 @@ protected static DaprRun startDaprApp( TO_BE_STOPPED.add(run); DAPR_RUN_BUILDERS.put(run.getAppName(), builder); run.start(); - run.use(); return run; } @@ -138,24 +116,12 @@ protected static ImmutablePair startSplitDaprAndApp( Class serviceClass, Boolean useAppPort, int maxWaitMilliseconds) throws Exception { - return startSplitDaprAndApp( - testName, successMessage, serviceClass, useAppPort, maxWaitMilliseconds, AppRun.AppProtocol.GRPC); - } - - protected static ImmutablePair startSplitDaprAndApp( - String testName, - String successMessage, - Class serviceClass, - Boolean useAppPort, - int maxWaitMilliseconds, - AppRun.AppProtocol protocol) throws Exception { return startSplitDaprAndApp( testName, successMessage, serviceClass, useAppPort, maxWaitMilliseconds, - protocol, HTTP); } @@ -165,7 +131,6 @@ protected static ImmutablePair startSplitDaprAndApp( Class serviceClass, Boolean useAppPort, int maxWaitMilliseconds, - AppRun.AppProtocol protocol, AppRun.AppProtocol appProtocol) throws Exception { DaprRun.Builder builder = new DaprRun.Builder( testName, @@ -179,10 +144,14 @@ protected static ImmutablePair startSplitDaprAndApp( DAPR_RUN_BUILDERS.put(runs.right.getAppName(), builder); runs.left.start(); runs.right.start(); - runs.right.use(); return runs; } + protected static T deferClose(T object) { + TO_BE_CLOSED.add(object); + return object; + } + @AfterAll public static void cleanUp() throws Exception { while (!TO_BE_CLOSED.isEmpty()) { @@ -194,8 +163,8 @@ public static void cleanUp() throws Exception { } } - protected static ActorClient newActorClient() { - return newActorClient(null); + protected static ActorClient newActorClient(Properties properties) { + return new ActorClient(properties, null); } protected static ActorClient newActorClient(ResiliencyOptions resiliencyOptions) throws RuntimeException { diff --git a/sdk-tests/src/test/java/io/dapr/it/DaprPorts.java b/sdk-tests/src/test/java/io/dapr/it/DaprPorts.java index aaf186e87..b71062f7c 100644 --- a/sdk-tests/src/test/java/io/dapr/it/DaprPorts.java +++ b/sdk-tests/src/test/java/io/dapr/it/DaprPorts.java @@ -14,12 +14,14 @@ package io.dapr.it; import io.dapr.config.Properties; +import io.dapr.config.Property; import java.io.IOException; import java.net.ServerSocket; import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; public class DaprPorts { @@ -30,10 +32,18 @@ public class DaprPorts { private final Integer appPort; + private final Map, String> overrides; + private DaprPorts(Integer appPort, Integer httpPort, Integer grpcPort) { this.grpcPort = grpcPort; this.httpPort = httpPort; this.appPort = appPort; + this.overrides = Map.of( + Properties.GRPC_PORT, grpcPort.toString(), + Properties.HTTP_PORT, httpPort.toString(), + Properties.HTTP_ENDPOINT, "http://127.0.0.1:" + httpPort, + Properties.GRPC_ENDPOINT, "127.0.0.1:" + grpcPort + ); } public static DaprPorts build(boolean appPort, boolean httpPort, boolean grpcPort) { @@ -48,20 +58,6 @@ public static DaprPorts build(boolean appPort, boolean httpPort, boolean grpcPor } } - public void use() { - if (this.httpPort != null) { - System.getProperties().setProperty(Properties.HTTP_PORT.getName(), String.valueOf(this.httpPort)); - System.getProperties().setProperty( - Properties.HTTP_ENDPOINT.getName(), "http://127.0.0.1:" + this.httpPort); - } - - if (this.grpcPort != null) { - System.getProperties().setProperty(Properties.GRPC_PORT.getName(), String.valueOf(this.grpcPort)); - System.getProperties().setProperty( - Properties.GRPC_ENDPOINT.getName(), "127.0.0.1:" + this.grpcPort); - } - } - public Integer getGrpcPort() { return grpcPort; } @@ -74,6 +70,10 @@ public Integer getAppPort() { return appPort; } + public Map, String> getPropertyOverrides() { + return this.overrides; + } + private static Set findFreePorts(int n) throws IOException { Set output = new HashSet<>(); for (int i = 0; i < n;) { diff --git a/sdk-tests/src/test/java/io/dapr/it/DaprRun.java b/sdk-tests/src/test/java/io/dapr/it/DaprRun.java index 9a7533a27..fce5ac976 100644 --- a/sdk-tests/src/test/java/io/dapr/it/DaprRun.java +++ b/sdk-tests/src/test/java/io/dapr/it/DaprRun.java @@ -14,7 +14,11 @@ package io.dapr.it; import com.google.protobuf.Empty; +import io.dapr.actors.client.ActorClient; +import io.dapr.client.DaprClientBuilder; +import io.dapr.client.resiliency.ResiliencyOptions; import io.dapr.config.Properties; +import io.dapr.config.Property; import io.dapr.v1.AppCallbackHealthCheckGrpc; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; @@ -24,6 +28,7 @@ import org.apache.commons.lang3.tuple.ImmutablePair; import java.io.IOException; +import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; @@ -141,8 +146,20 @@ public void stop() throws InterruptedException, IOException { } } - public void use() { - this.ports.use(); + public Map, String> getPropertyOverrides() { + return this.ports.getPropertyOverrides(); + } + + public DaprClientBuilder newDaprClientBuilder() { + return new DaprClientBuilder().withPropertyOverrides(this.getPropertyOverrides()); + } + + public ActorClient newActorClient() { + return this.newActorClient(null); + } + + public ActorClient newActorClient(ResiliencyOptions resiliencyOptions) { + return new ActorClient(new Properties(this.getPropertyOverrides()), resiliencyOptions); } public void waitForAppHealth(int maxWaitMilliseconds) throws InterruptedException { diff --git a/sdk-tests/src/test/java/io/dapr/it/ToxiProxyRun.java b/sdk-tests/src/test/java/io/dapr/it/ToxiProxyRun.java index 1f592fd61..ad248ec4b 100644 --- a/sdk-tests/src/test/java/io/dapr/it/ToxiProxyRun.java +++ b/sdk-tests/src/test/java/io/dapr/it/ToxiProxyRun.java @@ -16,10 +16,16 @@ import eu.rekawek.toxiproxy.Proxy; import eu.rekawek.toxiproxy.ToxiproxyClient; import eu.rekawek.toxiproxy.model.ToxicDirection; +import io.dapr.actors.client.ActorClient; +import io.dapr.client.DaprClientBuilder; +import io.dapr.client.resiliency.ResiliencyOptions; +import io.dapr.config.Properties; +import io.dapr.config.Property; import io.dapr.utils.NetworkUtils; import java.io.IOException; import java.time.Duration; +import java.util.Map; public class ToxiProxyRun implements Stoppable { @@ -30,7 +36,9 @@ public class ToxiProxyRun implements Stoppable { private final Duration jitter; - private Command toxiProxyServer; + private final Command toxiProxyServer; + + private final DaprPorts toxiProxyPorts; private ToxiproxyClient toxiproxyClient; @@ -38,8 +46,6 @@ public class ToxiProxyRun implements Stoppable { private Proxy httpProxy; - private DaprPorts toxiProxyPorts; - public ToxiProxyRun(DaprRun run, Duration latency, Duration jitter) { this.daprRun = run; this.latency = latency; @@ -78,8 +84,20 @@ public void start() throws IOException, InterruptedException { } } - public void use() { - this.toxiProxyPorts.use(); + public Map, String> getPropertyOverrides() { + return this.toxiProxyPorts.getPropertyOverrides(); + } + + public DaprClientBuilder newDaprClientBuilder() { + return this.daprRun.newDaprClientBuilder().withPropertyOverrides(this.getPropertyOverrides()); + } + + public ActorClient newActorClient() { + return this.newActorClient(null); + } + + public ActorClient newActorClient(ResiliencyOptions resiliencyOptions) { + return new ActorClient(new Properties(this.getPropertyOverrides()), resiliencyOptions); } @Override diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActivationDeactivationIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActivationDeactivationIT.java index f57ce0905..369d02945 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActivationDeactivationIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActivationDeactivationIT.java @@ -37,7 +37,7 @@ public class ActivationDeactivationIT extends BaseIT { @Test public void activateInvokeDeactivate() throws Exception { // The call below will fail if service cannot start successfully. - startDaprApp( + var run = startDaprApp( ActivationDeactivationIT.class.getSimpleName(), DemoActorService.SUCCESS_MESSAGE, DemoActorService.class, @@ -46,7 +46,8 @@ public void activateInvokeDeactivate() throws Exception { final AtomicInteger atomicInteger = new AtomicInteger(1); logger.debug("Creating proxy builder"); - ActorProxyBuilder proxyBuilder = new ActorProxyBuilder(DemoActor.class, newActorClient()); + ActorProxyBuilder proxyBuilder + = new ActorProxyBuilder(DemoActor.class, deferClose(run.newActorClient())); logger.debug("Creating actorId"); ActorId actorId1 = new ActorId(Integer.toString(atomicInteger.getAndIncrement())); logger.debug("Building proxy"); diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActorExceptionIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActorExceptionIT.java index e8e1cd0c3..3b97084cb 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActorExceptionIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActorExceptionIT.java @@ -33,7 +33,7 @@ public class ActorExceptionIT extends BaseIT { @Test public void exceptionTest() throws Exception { // The call below will fail if service cannot start successfully. - startDaprApp( + var run = startDaprApp( ActorExceptionIT.class.getSimpleName(), MyActorService.SUCCESS_MESSAGE, MyActorService.class, @@ -42,7 +42,7 @@ public void exceptionTest() throws Exception { logger.debug("Creating proxy builder"); ActorProxyBuilder proxyBuilder = - new ActorProxyBuilder("MyActorTest", MyActor.class, newActorClient()); + new ActorProxyBuilder("MyActorTest", MyActor.class, deferClose(run.newActorClient())); logger.debug("Creating actorId"); ActorId actorId1 = new ActorId("1"); logger.debug("Building proxy"); diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActorMethodNameIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActorMethodNameIT.java index 65c6232c8..bf9a2eb74 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActorMethodNameIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActorMethodNameIT.java @@ -33,7 +33,7 @@ public class ActorMethodNameIT extends BaseIT { @Test public void actorMethodNameChange() throws Exception { // The call below will fail if service cannot start successfully. - startDaprApp( + var run = startDaprApp( ActorMethodNameIT.class.getSimpleName(), MyActorService.SUCCESS_MESSAGE, MyActorService.class, @@ -42,7 +42,7 @@ public void actorMethodNameChange() throws Exception { logger.debug("Creating proxy builder"); ActorProxyBuilder proxyBuilder = - new ActorProxyBuilder("MyActorTest", MyActor.class, newActorClient()); + new ActorProxyBuilder("MyActorTest", MyActor.class, deferClose(run.newActorClient())); logger.debug("Creating actorId"); ActorId actorId1 = new ActorId("1"); logger.debug("Building proxy"); @@ -57,7 +57,7 @@ public void actorMethodNameChange() throws Exception { logger.debug("Creating proxy builder 2"); ActorProxyBuilder proxyBuilder2 = - new ActorProxyBuilder("MyActorTest", ActorProxy.class, newActorClient()); + new ActorProxyBuilder("MyActorTest", ActorProxy.class, deferClose(run.newActorClient())); logger.debug("Building proxy 2"); ActorProxy proxy2 = proxyBuilder2.build(actorId1); diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActorReminderFailoverIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActorReminderFailoverIT.java index efd9aebac..8e7b64c93 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActorReminderFailoverIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActorReminderFailoverIT.java @@ -14,8 +14,10 @@ package io.dapr.it.actors; import io.dapr.actors.ActorId; +import io.dapr.actors.client.ActorClient; import io.dapr.actors.client.ActorProxy; import io.dapr.actors.client.ActorProxyBuilder; +import io.dapr.config.Properties; import io.dapr.it.BaseIT; import io.dapr.it.DaprRun; import io.dapr.it.actors.app.MyActorService; @@ -72,7 +74,7 @@ public void init() throws Exception { logger.debug("Creating proxy builder"); ActorProxyBuilder proxyBuilder = - new ActorProxyBuilder(actorType, ActorProxy.class, newActorClient()); + new ActorProxyBuilder(actorType, ActorProxy.class, deferClose(clientAppRun.newActorClient())); logger.debug("Creating actorId"); logger.debug("Building proxy"); proxy = proxyBuilder.build(actorId); @@ -91,8 +93,6 @@ public void tearDown() { */ @Test public void reminderRecoveryTest() throws Exception { - clientAppRun.use(); - logger.debug("Invoking actor method 'startReminder' which will register a reminder"); proxy.invokeMethod("startReminder", "myReminder").block(); diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActorReminderRecoveryIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActorReminderRecoveryIT.java index 73f0eb382..c388a906a 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActorReminderRecoveryIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActorReminderRecoveryIT.java @@ -96,7 +96,6 @@ public void setup(String actorType) throws Exception { // Run that will stay up for integration tests. // appId must not contain the appId from the other run, otherwise ITs will not run properly. clientRun = startDaprApp("ActorReminderRecoveryTestClient", 5000); - clientRun.use(); Thread.sleep(3000); @@ -104,7 +103,7 @@ public void setup(String actorType) throws Exception { logger.debug("Creating proxy builder"); ActorProxyBuilder proxyBuilder = - new ActorProxyBuilder(actorType, ActorProxy.class, newActorClient()); + new ActorProxyBuilder(actorType, ActorProxy.class, deferClose(clientRun.newActorClient())); logger.debug("Creating actorId"); logger.debug("Building proxy"); proxy = proxyBuilder.build(actorId); diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActorSdkResiliencyIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActorSdkResiliencyIT.java index e8140d68c..c9b7f27b7 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActorSdkResiliencyIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActorSdkResiliencyIT.java @@ -14,9 +14,9 @@ package io.dapr.it.actors; import io.dapr.actors.ActorId; +import io.dapr.actors.client.ActorClient; import io.dapr.actors.client.ActorProxyBuilder; import io.dapr.client.DaprClient; -import io.dapr.client.DaprClientBuilder; import io.dapr.client.resiliency.ResiliencyOptions; import io.dapr.it.BaseIT; import io.dapr.it.DaprRun; @@ -75,22 +75,22 @@ public static void init() throws Exception { true, 60000); - demoActor = buildDemoActorProxy(null); - daprClient = new DaprClientBuilder().build(); + demoActor = buildDemoActorProxy(deferClose(daprRun.newActorClient())); + daprClient = daprRun.newDaprClientBuilder().build(); toxiProxyRun = new ToxiProxyRun(daprRun, LATENCY, JITTER); toxiProxyRun.start(); - toxiProxyRun.use(); - toxiDemoActor = buildDemoActorProxy(new ResiliencyOptions().setTimeout(TIMEOUT)); + + toxiDemoActor = buildDemoActorProxy( + toxiProxyRun.newActorClient(new ResiliencyOptions().setTimeout(TIMEOUT))); resilientDemoActor = buildDemoActorProxy( - new ResiliencyOptions().setTimeout(TIMEOUT).setMaxRetries(MAX_RETRIES)); + toxiProxyRun.newActorClient(new ResiliencyOptions().setTimeout(TIMEOUT).setMaxRetries(MAX_RETRIES))); oneRetryDemoActor = buildDemoActorProxy( - new ResiliencyOptions().setTimeout(TIMEOUT).setMaxRetries(1)); + toxiProxyRun.newActorClient(new ResiliencyOptions().setTimeout(TIMEOUT).setMaxRetries(1))); } - private static DemoActor buildDemoActorProxy(ResiliencyOptions resiliencyOptions) { - ActorProxyBuilder builder = - new ActorProxyBuilder(DemoActor.class, newActorClient(resiliencyOptions)); + private static DemoActor buildDemoActorProxy(ActorClient actorClient) { + ActorProxyBuilder builder = new ActorProxyBuilder(DemoActor.class, actorClient); return builder.build(ACTOR_ID); } diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActorStateIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActorStateIT.java index 534fd481d..67d6b9659 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActorStateIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActorStateIT.java @@ -16,19 +16,14 @@ import io.dapr.actors.ActorId; import io.dapr.actors.client.ActorProxy; import io.dapr.actors.client.ActorProxyBuilder; -import io.dapr.it.AppRun; import io.dapr.it.BaseIT; import io.dapr.it.DaprRun; import io.dapr.it.actors.services.springboot.StatefulActor; import io.dapr.it.actors.services.springboot.StatefulActorService; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.stream.Stream; - import static io.dapr.it.Retry.callWithRetry; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -38,51 +33,37 @@ public class ActorStateIT extends BaseIT { private static Logger logger = LoggerFactory.getLogger(ActorStateIT.class); - /** - * Parameters for this test. - * Param #1: useGrpc. - * @return Collection of parameter tuples. - */ - public static Stream data() { - return Stream.of( - Arguments.of(AppRun.AppProtocol.HTTP ), - Arguments.of(AppRun.AppProtocol.GRPC ) - ); - } - - @ParameterizedTest - @MethodSource("data") - public void writeReadState(AppRun.AppProtocol serviceAppProtocol) throws Exception { + @Test + public void writeReadState() throws Exception { logger.debug("Starting actor runtime ..."); // The call below will fail if service cannot start successfully. - DaprRun runtime = startDaprApp( + DaprRun run = startDaprApp( this.getClass().getSimpleName(), StatefulActorService.SUCCESS_MESSAGE, StatefulActorService.class, true, - 60000, - serviceAppProtocol); + 60000); String message = "This is a message to be saved and retrieved."; String name = "Jon Doe"; byte[] bytes = new byte[] { 0x1 }; ActorId actorId = new ActorId( - String.format("%d-%b", System.currentTimeMillis(), serviceAppProtocol)); + String.format("%d", System.currentTimeMillis())); String actorType = "StatefulActorTest"; logger.debug("Building proxy ..."); ActorProxyBuilder proxyBuilder = - new ActorProxyBuilder(actorType, ActorProxy.class, newActorClient()); + new ActorProxyBuilder(actorType, ActorProxy.class, deferClose(run.newActorClient())); ActorProxy proxy = proxyBuilder.build(actorId); // wating for actor to be activated - Thread.sleep(2000); + Thread.sleep(5000); // Validate conditional read works. callWithRetry(() -> { logger.debug("Invoking readMessage where data is not present yet ... "); String result = proxy.invokeMethod("readMessage", String.class).block(); assertNull(result); - }, 5000); + }, 10000); callWithRetry(() -> { logger.debug("Invoking writeMessage ... "); @@ -146,7 +127,7 @@ public void writeReadState(AppRun.AppProtocol serviceAppProtocol) throws Excepti Thread.sleep(10000); logger.debug("Stopping service ..."); - runtime.stop(); + run.stop(); logger.debug("Starting service ..."); DaprRun run2 = startDaprApp( @@ -154,11 +135,10 @@ public void writeReadState(AppRun.AppProtocol serviceAppProtocol) throws Excepti StatefulActorService.SUCCESS_MESSAGE, StatefulActorService.class, true, - 60000, - serviceAppProtocol); + 60000); // Need new proxy builder because the proxy builder holds the channel. - proxyBuilder = new ActorProxyBuilder(actorType, ActorProxy.class, newActorClient()); + proxyBuilder = new ActorProxyBuilder(actorType, ActorProxy.class, deferClose(run2.newActorClient())); ActorProxy newProxy = proxyBuilder.build(actorId); // wating for actor to be activated diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActorTimerRecoveryIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActorTimerRecoveryIT.java index 796aa4e66..809cd21a9 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActorTimerRecoveryIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActorTimerRecoveryIT.java @@ -59,7 +59,7 @@ public void timerRecoveryTest() throws Exception { logger.debug("Creating proxy builder"); ActorProxyBuilder proxyBuilder = - new ActorProxyBuilder(actorType, ActorProxy.class, newActorClient()); + new ActorProxyBuilder(actorType, ActorProxy.class, deferClose(runs.right.newActorClient())); logger.debug("Creating actorId"); ActorId actorId = new ActorId(UUID.randomUUID().toString()); logger.debug("Building proxy"); diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActorTurnBasedConcurrencyIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActorTurnBasedConcurrencyIT.java index adc7b36c3..dd021d98b 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActorTurnBasedConcurrencyIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActorTurnBasedConcurrencyIT.java @@ -80,7 +80,7 @@ public void cleanUpTestCase() { public void invokeOneActorMethodReminderAndTimer() throws Exception { System.out.println("Starting test 'actorTest1'"); - startDaprApp( + var run = startDaprApp( ActorTurnBasedConcurrencyIT.class.getSimpleName(), MyActorService.SUCCESS_MESSAGE, MyActorService.class, @@ -92,7 +92,7 @@ public void invokeOneActorMethodReminderAndTimer() throws Exception { logger.debug("Creating proxy builder"); ActorProxyBuilder proxyBuilder = - new ActorProxyBuilder(actorType, ActorProxy.class, newActorClient()); + new ActorProxyBuilder(actorType, ActorProxy.class, deferClose(run.newActorClient())); logger.debug("Creating actorId"); ActorId actorId1 = new ActorId(ACTOR_ID); logger.debug("Building proxy"); diff --git a/sdk-tests/src/test/java/io/dapr/it/api/ApiIT.java b/sdk-tests/src/test/java/io/dapr/it/api/ApiIT.java index 462d22927..8b37c5ad3 100644 --- a/sdk-tests/src/test/java/io/dapr/it/api/ApiIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/api/ApiIT.java @@ -19,7 +19,7 @@ public void testShutdownAPI() throws Exception { // TODO(artursouza): change this to wait for the sidecar to be healthy (new method needed in DaprClient). Thread.sleep(3000); - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = run.newDaprClientBuilder().build()) { logger.info("Sending shutdown request."); client.shutdown().block(); diff --git a/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java b/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java index 610a55820..8b104f0d8 100644 --- a/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.List; +import java.util.Map; import static io.dapr.it.Retry.callWithRetry; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -37,10 +38,10 @@ public class BindingIT extends BaseIT { @Test public void httpOutputBindingError() throws Exception { - startDaprApp( + var run = startDaprApp( this.getClass().getSimpleName() + "-httpoutputbinding-exception", 60000); - try(DaprClient client = new DaprClientBuilder().build()) { + try(DaprClient client = run.newDaprClientBuilder().build()) { // Validate error message callWithRetry(() -> { System.out.println("Checking exception handling for output binding ..."); @@ -60,10 +61,10 @@ public void httpOutputBindingError() throws Exception { @Test public void httpOutputBindingErrorIgnoredByComponent() throws Exception { - startDaprApp( + var run = startDaprApp( this.getClass().getSimpleName() + "-httpoutputbinding-ignore-error", 60000); - try(DaprClient client = new DaprClientBuilder().build()) { + try(DaprClient client = run.newDaprClientBuilder().build()) { // Validate error message callWithRetry(() -> { System.out.println("Checking exception handling for output binding ..."); @@ -92,7 +93,7 @@ public void inputOutputBinding() throws Exception { var bidingName = "sample123"; - try(DaprClient client = new DaprClientBuilder().build()) { + try(DaprClient client = daprRun.newDaprClientBuilder().build()) { callWithRetry(() -> { System.out.println("Checking if input binding is up before publishing events ..."); client.invokeBinding( @@ -115,14 +116,14 @@ public void inputOutputBinding() throws Exception { System.out.println("sending first message"); client.invokeBinding( - bidingName, "create", myClass, Collections.singletonMap("MyMetadata", "MyValue"), Void.class).block(); + bidingName, "create", myClass, Map.of("MyMetadata", "MyValue"), Void.class).block(); // This is an example of sending a plain string. The input binding will receive // cat final String m = "cat"; System.out.println("sending " + m); client.invokeBinding( - bidingName, "create", m, Collections.singletonMap("MyMetadata", "MyValue"), Void.class).block(); + bidingName, "create", m, Map.of("MyMetadata", "MyValue"), Void.class).block(); // Metadata is not used by Kafka component, so it is not possible to validate. callWithRetry(() -> { diff --git a/sdk-tests/src/test/java/io/dapr/it/configuration/ConfigurationClientIT.java b/sdk-tests/src/test/java/io/dapr/it/configuration/ConfigurationClientIT.java index 02c5798de..ee1343467 100644 --- a/sdk-tests/src/test/java/io/dapr/it/configuration/ConfigurationClientIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/configuration/ConfigurationClientIT.java @@ -68,7 +68,7 @@ public class ConfigurationClientIT extends BaseIT { @BeforeAll public static void init() throws Exception { daprRun = startDaprApp(ConfigurationClientIT.class.getSimpleName(), 5000); - daprClient = new DaprClientBuilder().build(); + daprClient = daprRun.newDaprClientBuilder().build(); } @AfterAll diff --git a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/grpc/MethodInvokeIT.java b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/grpc/MethodInvokeIT.java index ed9609cc9..ea94d2136 100644 --- a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/grpc/MethodInvokeIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/grpc/MethodInvokeIT.java @@ -49,7 +49,7 @@ public void init() throws Exception { @Test public void testInvoke() throws Exception { - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().build()) { client.waitForSidecar(10000).block(); daprRun.waitForAppHealth(10000); @@ -81,7 +81,7 @@ public void testInvoke() throws Exception { @Test public void testInvokeTimeout() throws Exception { - try (DaprClient client = new DaprClientBuilder().withResiliencyOptions(RESILIENCY_OPTIONS).build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().withResiliencyOptions(RESILIENCY_OPTIONS).build()) { client.waitForSidecar(10000).block(); daprRun.waitForAppHealth(10000); @@ -99,7 +99,7 @@ public void testInvokeTimeout() throws Exception { @Test public void testInvokeException() throws Exception { - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().build()) { client.waitForSidecar(10000).block(); daprRun.waitForAppHealth(10000); diff --git a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeIT.java b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeIT.java index 1b5ab7577..ba7b485ca 100644 --- a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeIT.java @@ -48,7 +48,7 @@ public void testInvoke() throws Exception { // At this point, it is guaranteed that the service above is running and all ports being listened to. - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().build()) { client.waitForSidecar(10000).block(); for (int i = 0; i < NUM_MESSAGES; i++) { String message = String.format("This is message #%d", i); @@ -74,7 +74,7 @@ public void testInvoke() throws Exception { @Test public void testInvokeWithObjects() throws Exception { - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().build()) { client.waitForSidecar(10000).block(); for (int i = 0; i < NUM_MESSAGES; i++) { Person person = new Person(); @@ -110,7 +110,7 @@ public void testInvokeWithObjects() throws Exception { @Test public void testInvokeTimeout() throws Exception { - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().build()) { client.waitForSidecar(10000).block(); long started = System.currentTimeMillis(); String message = assertThrows(IllegalStateException.class, () -> { @@ -127,7 +127,7 @@ public void testInvokeTimeout() throws Exception { @Test public void testInvokeException() throws Exception { - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().build()) { client.waitForSidecar(10000).block(); MethodInvokeServiceProtos.SleepRequest req = MethodInvokeServiceProtos.SleepRequest.newBuilder().setSeconds(-9).build(); DaprException exception = assertThrows(DaprException.class, () -> diff --git a/sdk-tests/src/test/java/io/dapr/it/pubsub/http/PubSubIT.java b/sdk-tests/src/test/java/io/dapr/it/pubsub/http/PubSubIT.java index 347bd64de..57b9485e9 100644 --- a/sdk-tests/src/test/java/io/dapr/it/pubsub/http/PubSubIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/pubsub/http/PubSubIT.java @@ -43,6 +43,7 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Random; import java.util.Set; @@ -104,7 +105,7 @@ public void publishPubSubNotFound() throws Exception { this.getClass().getSimpleName(), 60000)); - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().build()) { assertThrowsDaprExceptionWithReason( "INVALID_ARGUMENT", "INVALID_ARGUMENT: pubsub unknown pubsub is not found", @@ -119,7 +120,7 @@ public void testBulkPublishPubSubNotFound() throws Exception { this.getClass().getSimpleName(), 60000)); - try (DaprPreviewClient client = new DaprClientBuilder().buildPreviewClient()) { + try (DaprPreviewClient client = daprRun.newDaprClientBuilder().buildPreviewClient()) { assertThrowsDaprException( "INVALID_ARGUMENT", "INVALID_ARGUMENT: pubsub unknown pubsub is not found", @@ -151,8 +152,8 @@ public String getContentType() { return "application/json"; } }; - try (DaprClient client = new DaprClientBuilder().withObjectSerializer(serializer).build(); - DaprPreviewClient previewClient = new DaprClientBuilder().withObjectSerializer(serializer).buildPreviewClient()) { + try (DaprClient client = daprRun.newDaprClientBuilder().withObjectSerializer(serializer).build(); + DaprPreviewClient previewClient = daprRun.newDaprClientBuilder().withObjectSerializer(serializer).buildPreviewClient()) { // Only for the gRPC test // Send a multiple messages on one topic in messagebus pubsub via publishEvents API. List messages = new ArrayList<>(); @@ -282,7 +283,7 @@ public String getContentType() { }; // Send a batch of messages on one topic - try (DaprClient client = new DaprClientBuilder().withObjectSerializer(serializer).build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().withObjectSerializer(serializer).build()) { for (int i = 0; i < NUM_MESSAGES; i++) { String message = String.format("This is message #%d on topic %s", i, TOPIC_NAME); //Publishing messages @@ -494,7 +495,7 @@ public String getContentType() { return "application/octet-stream"; } }; - try (DaprClient client = new DaprClientBuilder().withObjectSerializer(serializer).build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().withObjectSerializer(serializer).build()) { client.publishEvent( PUBSUB_NAME, BINARY_TOPIC_NAME, @@ -504,7 +505,7 @@ public String getContentType() { Thread.sleep(3000); - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().build()) { callWithRetry(() -> { System.out.println("Checking results for topic " + BINARY_TOPIC_NAME); final List messages = client.invokeMethod( @@ -526,7 +527,7 @@ public void testPubSubTTLMetadata() throws Exception { 60000)); // Send a batch of messages on one topic, all to be expired in 1 second. - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().build()) { for (int i = 0; i < NUM_MESSAGES; i++) { String message = String.format("This is message #%d on topic %s", i, TTL_TOPIC_NAME); //Publishing messages @@ -534,7 +535,7 @@ public void testPubSubTTLMetadata() throws Exception { PUBSUB_NAME, TTL_TOPIC_NAME, message, - Collections.singletonMap(Metadata.TTL_IN_SECONDS, "1")).block(); + Map.of(Metadata.TTL_IN_SECONDS, "1")).block(); System.out.println(String.format("Published message: '%s' to topic '%s' pubsub_name '%s'", message, TOPIC_NAME, PUBSUB_NAME)); } } @@ -555,7 +556,7 @@ public void testPubSubTTLMetadata() throws Exception { Thread.sleep(5000); final String appId = daprRun.getAppName(); - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().build()) { callWithRetry(() -> { System.out.println("Checking results for topic " + TTL_TOPIC_NAME); final List messages = client.invokeMethod(appId, "messages/" + TTL_TOPIC_NAME, null, HttpExtension.GET, List.class).block(); @@ -576,7 +577,7 @@ public void testPubSubBulkSubscribe() throws Exception { 60000)); // Send a batch of messages on one topic. - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().build()) { for (int i = 0; i < NUM_MESSAGES; i++) { String message = String.format("This is message #%d on topic %s", i, BULK_SUB_TOPIC_NAME); // Publishing messages @@ -590,7 +591,7 @@ public void testPubSubBulkSubscribe() throws Exception { Thread.sleep(5000); final String appId = daprRun.getAppName(); - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().build()) { callWithRetry(() -> { System.out.println("Checking results for topic " + BULK_SUB_TOPIC_NAME); @@ -643,7 +644,7 @@ public void testLongValues() throws Exception { values.add(val); } Iterator valuesIt = values.iterator(); - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().build()) { for (int i = 0; i < NUM_MESSAGES; i++) { ConvertToLong value = valuesIt.next(); System.out.println("The long value sent " + value.getValue()); @@ -652,7 +653,7 @@ public void testLongValues() throws Exception { PUBSUB_NAME, LONG_TOPIC_NAME, value, - Collections.singletonMap(Metadata.TTL_IN_SECONDS, "30")).block(); + Map.of(Metadata.TTL_IN_SECONDS, "30")).block(); try { Thread.sleep((long) (1000 * Math.random())); @@ -665,7 +666,7 @@ public void testLongValues() throws Exception { } Set actual = new HashSet<>(); - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().build()) { callWithRetry(() -> { System.out.println("Checking results for topic " + LONG_TOPIC_NAME); final List> messages = client.invokeMethod( diff --git a/sdk-tests/src/test/java/io/dapr/it/resiliency/SdkResiliencyIT.java b/sdk-tests/src/test/java/io/dapr/it/resiliency/SdkResiliencyIT.java index c3bdc7195..723e40b2a 100644 --- a/sdk-tests/src/test/java/io/dapr/it/resiliency/SdkResiliencyIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/resiliency/SdkResiliencyIT.java @@ -63,22 +63,21 @@ public class SdkResiliencyIT extends BaseIT { @BeforeAll public static void init() throws Exception { DaprRun daprRun = startDaprApp(SdkResiliencyIT.class.getSimpleName(), 5000); - daprClient = new DaprClientBuilder().build(); + daprClient = daprRun.newDaprClientBuilder().build(); daprClient.waitForSidecar(8000).block(); toxiProxyRun = new ToxiProxyRun(daprRun, LATENCY, JITTER); toxiProxyRun.start(); - toxiProxyRun.use(); - daprToxiClient = new DaprClientBuilder() + daprToxiClient = toxiProxyRun.newDaprClientBuilder() .withResiliencyOptions( new ResiliencyOptions().setTimeout(TIMEOUT)) .build(); - daprResilientClient = new DaprClientBuilder() + daprResilientClient = toxiProxyRun.newDaprClientBuilder() .withResiliencyOptions( new ResiliencyOptions().setTimeout(TIMEOUT).setMaxRetries(MAX_RETRIES)) .build(); - daprRetriesOnceClient = new DaprClientBuilder() + daprRetriesOnceClient = toxiProxyRun.newDaprClientBuilder() .withResiliencyOptions( new ResiliencyOptions().setTimeout(TIMEOUT).setMaxRetries(1)) .build(); diff --git a/sdk-tests/src/test/java/io/dapr/it/secrets/SecretsClientIT.java b/sdk-tests/src/test/java/io/dapr/it/secrets/SecretsClientIT.java index fc6260a68..23f05957b 100644 --- a/sdk-tests/src/test/java/io/dapr/it/secrets/SecretsClientIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/secrets/SecretsClientIT.java @@ -75,7 +75,7 @@ public static void init() throws Exception { @BeforeEach public void setup() { - this.daprClient = new DaprClientBuilder().build(); + this.daprClient = daprRun.newDaprClientBuilder().build(); } @AfterEach diff --git a/sdk-tests/src/test/java/io/dapr/it/spring/data/DaprKeyValueRepositoryIT.java b/sdk-tests/src/test/java/io/dapr/it/spring/data/DaprKeyValueRepositoryIT.java index c2a09e9e6..60d4b8854 100644 --- a/sdk-tests/src/test/java/io/dapr/it/spring/data/DaprKeyValueRepositoryIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/spring/data/DaprKeyValueRepositoryIT.java @@ -51,7 +51,7 @@ public class DaprKeyValueRepositoryIT { "host=postgres-repository user=postgres password=password port=5432 connect_timeout=10 database=dapr_db_repository"; private static final Map STATE_STORE_PROPERTIES = createStateStoreProperties(); - private static final Map BINDING_PROPERTIES = Collections.singletonMap("connectionString", CONNECTION_STRING); + private static final Map BINDING_PROPERTIES = Map.of("connectionString", CONNECTION_STRING); private static final Network DAPR_NETWORK = Network.newNetwork(); diff --git a/sdk-tests/src/test/java/io/dapr/it/spring/data/MySQLDaprKeyValueTemplateIT.java b/sdk-tests/src/test/java/io/dapr/it/spring/data/MySQLDaprKeyValueTemplateIT.java index f5d145b90..d365685d9 100644 --- a/sdk-tests/src/test/java/io/dapr/it/spring/data/MySQLDaprKeyValueTemplateIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/spring/data/MySQLDaprKeyValueTemplateIT.java @@ -63,7 +63,7 @@ public class MySQLDaprKeyValueTemplateIT { private static final String BINDING_DSN = "mysql:password@tcp(mysql:3306)/dapr_db"; private static final Map STATE_STORE_PROPERTIES = createStateStoreProperties(); - private static final Map BINDING_PROPERTIES = Collections.singletonMap("url", BINDING_DSN); + private static final Map BINDING_PROPERTIES = Map.of("url", BINDING_DSN); private static final Network DAPR_NETWORK = Network.newNetwork(); @@ -114,7 +114,7 @@ private static Map createStateStoreProperties() { */ @AfterEach public void tearDown() { - var meta = Collections.singletonMap("sql", "delete from state"); + var meta = Map.of("sql", "delete from state"); daprClient.invokeBinding(BINDING_NAME, "exec", null, meta).block(); } diff --git a/sdk-tests/src/test/java/io/dapr/it/spring/data/PostgreSQLDaprKeyValueTemplateIT.java b/sdk-tests/src/test/java/io/dapr/it/spring/data/PostgreSQLDaprKeyValueTemplateIT.java index 1d2ef4de8..b055d3aef 100644 --- a/sdk-tests/src/test/java/io/dapr/it/spring/data/PostgreSQLDaprKeyValueTemplateIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/spring/data/PostgreSQLDaprKeyValueTemplateIT.java @@ -54,7 +54,7 @@ public class PostgreSQLDaprKeyValueTemplateIT { "host=postgres user=postgres password=password port=5432 connect_timeout=10 database=dapr_db"; private static final Map STATE_STORE_PROPERTIES = createStateStoreProperties(); - private static final Map BINDING_PROPERTIES = Collections.singletonMap("connectionString", CONNECTION_STRING); + private static final Map BINDING_PROPERTIES = Map.of("connectionString", CONNECTION_STRING); private static final Network DAPR_NETWORK = Network.newNetwork(); @@ -96,7 +96,7 @@ private static Map createStateStoreProperties() { @BeforeEach public void setUp() { - var meta = Collections.singletonMap("sql", "delete from state"); + var meta = Map.of("sql", "delete from state"); daprClient.invokeBinding(BINDING_NAME, "exec", null, meta).block(); } diff --git a/sdk-tests/src/test/java/io/dapr/it/spring/messaging/DaprSpringMessagingIT.java b/sdk-tests/src/test/java/io/dapr/it/spring/messaging/DaprSpringMessagingIT.java index 50d5b9114..fc03f4412 100644 --- a/sdk-tests/src/test/java/io/dapr/it/spring/messaging/DaprSpringMessagingIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/spring/messaging/DaprSpringMessagingIT.java @@ -23,6 +23,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Disabled; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -86,6 +87,7 @@ public void beforeEach() throws InterruptedException { } @Test + @Disabled("Test is flaky due to global state in the spring test application.") public void testDaprMessagingTemplate() throws InterruptedException { for (int i = 0; i < 10; i++) { var msg = "ProduceAndReadWithPrimitiveMessageType:" + i; diff --git a/sdk-tests/src/test/java/io/dapr/it/state/GRPCStateClientIT.java b/sdk-tests/src/test/java/io/dapr/it/state/GRPCStateClientIT.java index 1c77d93d2..5254e0b06 100644 --- a/sdk-tests/src/test/java/io/dapr/it/state/GRPCStateClientIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/state/GRPCStateClientIT.java @@ -37,7 +37,7 @@ public class GRPCStateClientIT extends AbstractStateClientIT { @BeforeAll public static void init() throws Exception { daprRun = startDaprApp(GRPCStateClientIT.class.getSimpleName(), 5000); - daprClient = new DaprClientBuilder().build(); + daprClient = daprRun.newDaprClientBuilder().build(); } @AfterAll diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerIT.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerIT.java index bdafff9a7..d565be86f 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerIT.java @@ -46,7 +46,6 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static java.util.Collections.singletonMap; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -166,7 +165,7 @@ public void testPubSub() throws Exception { try (DaprClient client = (builder).build()) { String message = "message content"; - Map metadata = singletonMap(Metadata.TTL_IN_SECONDS, MESSAGE_TTL_IN_SECONDS); + Map metadata = Map.of(Metadata.TTL_IN_SECONDS, MESSAGE_TTL_IN_SECONDS); client.publishEvent(PUBSUB_NAME, PUBSUB_TOPIC_NAME, message, metadata).block(); } diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprWorkflowsIT.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprWorkflowsIT.java index 91ccfa7ce..f0c39ed80 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprWorkflowsIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprWorkflowsIT.java @@ -37,6 +37,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Collections; +import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -59,7 +60,7 @@ public class DaprWorkflowsIT { .withAppName("workflow-dapr-app") .withNetwork(DAPR_NETWORK) .withComponent(new Component("kvstore", "state.in-memory", "v1", - Collections.singletonMap("actorStateStore", "true"))) + Map.of("actorStateStore", "true"))) .withComponent(new Component("pubsub", "pubsub.in-memory", "v1", Collections.emptyMap())) .withDaprLogLevel(DaprLogLevel.DEBUG) .withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String())) diff --git a/sdk-tests/src/test/java/io/dapr/it/tracing/grpc/TracingIT.java b/sdk-tests/src/test/java/io/dapr/it/tracing/grpc/TracingIT.java index 76df40044..256347398 100644 --- a/sdk-tests/src/test/java/io/dapr/it/tracing/grpc/TracingIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/tracing/grpc/TracingIT.java @@ -47,7 +47,7 @@ public void testInvoke() throws Exception { String spanName = UUID.randomUUID().toString(); Span span = tracer.spanBuilder(spanName).setSpanKind(SpanKind.CLIENT).startSpan(); - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().build()) { client.waitForSidecar(10000).block(); try (Scope scope = span.makeCurrent()) { SleepRequest req = SleepRequest.newBuilder().setSeconds(1).build(); diff --git a/sdk-tests/src/test/java/io/dapr/it/tracing/http/TracingIT.java b/sdk-tests/src/test/java/io/dapr/it/tracing/http/TracingIT.java index a4c75d140..3285d2ca8 100644 --- a/sdk-tests/src/test/java/io/dapr/it/tracing/http/TracingIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/tracing/http/TracingIT.java @@ -46,7 +46,7 @@ public void testInvoke() throws Exception { String spanName = UUID.randomUUID().toString(); Span span = tracer.spanBuilder(spanName).setSpanKind(SpanKind.CLIENT).startSpan(); - try (DaprClient client = new DaprClientBuilder().build()) { + try (DaprClient client = daprRun.newDaprClientBuilder().build()) { client.waitForSidecar(10000).block(); try (Scope scope = span.makeCurrent()) { client.invokeMethod(daprRun.getAppName(), "sleep", 1, HttpExtension.POST) diff --git a/sdk/src/main/java/io/dapr/client/DaprClientBuilder.java b/sdk/src/main/java/io/dapr/client/DaprClientBuilder.java index a31276b9d..ad67eed8c 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientBuilder.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientBuilder.java @@ -117,12 +117,24 @@ public DaprClientBuilder withResiliencyOptions(ResiliencyOptions options) { * @param property that we want to override * @param value the value of such property * @return an instance of the setup Client - */ + */ public DaprClientBuilder withPropertyOverride(Property property, String value) { this.propertyOverrides.put(property.getName(), value); return this; } + /** + * Allow to set up properties override for static properties. + * @param overrides properties to override + * @return an instance of the setup Client + */ + public DaprClientBuilder withPropertyOverrides(Map, String> overrides) { + for (final Map.Entry, String> override : overrides.entrySet()) { + this.propertyOverrides.put(override.getKey().getName(), override.getValue()); + } + return this; + } + /** * Build an instance of the Client based on the provided setup. * diff --git a/sdk/src/main/java/io/dapr/client/DaprHttp.java b/sdk/src/main/java/io/dapr/client/DaprHttp.java index 01485e433..d2478d87f 100644 --- a/sdk/src/main/java/io/dapr/client/DaprHttp.java +++ b/sdk/src/main/java/io/dapr/client/DaprHttp.java @@ -71,8 +71,7 @@ public class DaprHttp implements AutoCloseable { /** * Context entries allowed to be in HTTP Headers. */ - private static final Set ALLOWED_CONTEXT_IN_HEADERS = - Collections.unmodifiableSet(new HashSet<>(Arrays.asList("grpc-trace-bin", "traceparent", "tracestate"))); + private static final Set ALLOWED_CONTEXT_IN_HEADERS = Set.of("grpc-trace-bin", "traceparent", "tracestate"); /** * Object mapper to parse DaprError with or without details. diff --git a/sdk/src/main/java/io/dapr/client/DaprTracingInterceptor.java b/sdk/src/main/java/io/dapr/client/DaprTracingInterceptor.java deleted file mode 100644 index 20f6d1c06..000000000 --- a/sdk/src/main/java/io/dapr/client/DaprTracingInterceptor.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2024 The Dapr Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io.dapr.client; - -import io.grpc.CallOptions; -import io.grpc.Channel; -import io.grpc.ClientCall; -import io.grpc.ClientInterceptor; -import io.grpc.MethodDescriptor; -import reactor.util.context.ContextView; - -/** - * Injects tracing headers to gRPC metadata. - */ -public class DaprTracingInterceptor implements ClientInterceptor { - - private final io.dapr.internal.grpc.interceptors.DaprTracingInterceptor delegate; - - /** - * Creates an instance of the injector for gRPC context from Reactor's context. - * @param context Reactor's context - */ - public DaprTracingInterceptor(ContextView context) { - this.delegate = new io.dapr.internal.grpc.interceptors.DaprTracingInterceptor(context); - } - - /** - * {@inheritDoc} - */ - @Override - public ClientCall interceptCall( - MethodDescriptor methodDescriptor, - CallOptions callOptions, - Channel channel) { - return this.delegate.interceptCall(methodDescriptor, callOptions, channel); - } -} diff --git a/sdk/src/main/java/io/dapr/client/domain/BulkPublishEntry.java b/sdk/src/main/java/io/dapr/client/domain/BulkPublishEntry.java index da8a05ffb..57ba82609 100644 --- a/sdk/src/main/java/io/dapr/client/domain/BulkPublishEntry.java +++ b/sdk/src/main/java/io/dapr/client/domain/BulkPublishEntry.java @@ -55,7 +55,7 @@ public BulkPublishEntry(String entryId, T event, String contentType) { this.entryId = entryId; this.event = event; this.contentType = contentType; - this.metadata = Collections.unmodifiableMap(new HashMap<>()); + this.metadata = Map.of(); } /** @@ -70,8 +70,7 @@ public BulkPublishEntry(String entryId, T event, String contentType, Map()) : - Collections.unmodifiableMap(metadata); + this.metadata = metadata == null ? Map.of() : Collections.unmodifiableMap(metadata); } public String getEntryId() { diff --git a/sdk/src/main/java/io/dapr/client/domain/BulkPublishRequest.java b/sdk/src/main/java/io/dapr/client/domain/BulkPublishRequest.java index 4c6a3dee8..e4b29daff 100644 --- a/sdk/src/main/java/io/dapr/client/domain/BulkPublishRequest.java +++ b/sdk/src/main/java/io/dapr/client/domain/BulkPublishRequest.java @@ -72,10 +72,8 @@ public BulkPublishRequest(String pubsubName, String topic, List metadata) { this.pubsubName = pubsubName; this.topic = topic; - this.entries = entries == null ? Collections.unmodifiableList(new ArrayList<>()) : - Collections.unmodifiableList(entries); - this.metadata = metadata == null ? Collections.unmodifiableMap(new HashMap<>()) : - Collections.unmodifiableMap(metadata); + this.entries = entries == null ? List.of() : Collections.unmodifiableList(entries); + this.metadata = metadata == null ? Map.of() : Collections.unmodifiableMap(metadata); } public String getPubsubName() { diff --git a/sdk/src/main/java/io/dapr/config/Properties.java b/sdk/src/main/java/io/dapr/config/Properties.java index 38a88b767..14b0a4fb2 100644 --- a/sdk/src/main/java/io/dapr/config/Properties.java +++ b/sdk/src/main/java/io/dapr/config/Properties.java @@ -18,8 +18,8 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.time.Duration; -import java.util.Collections; import java.util.Map; +import java.util.stream.Collectors; /** * Global properties for Dapr's SDK, using Supplier so they are dynamically resolved. @@ -189,10 +189,17 @@ public Properties() { /** * Creates a new instance to handle Properties per instance. - * @param overrides to override static properties - */ - public Properties(Map overrides) { - this.overrides = Collections.unmodifiableMap(overrides); + * @param overridesInput to override static properties + */ + public Properties(Map overridesInput) { + this.overrides = overridesInput == null ? Map.of() : + Map.copyOf(overridesInput.entrySet().stream() + .filter(e -> e.getKey() != null) + .filter(e -> e.getValue() != null) + .collect(Collectors.toMap( + entry -> entry.getKey().toString(), + entry -> entry.getValue() + ))); } /** diff --git a/sdk/src/main/java/io/dapr/config/Property.java b/sdk/src/main/java/io/dapr/config/Property.java index f0e54f2e7..c24ab5384 100644 --- a/sdk/src/main/java/io/dapr/config/Property.java +++ b/sdk/src/main/java/io/dapr/config/Property.java @@ -58,6 +58,14 @@ public String getName() { return this.name; } + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return this.name; + } + /** * Gets the environment variable's name. * @return Name. diff --git a/sdk/src/main/java/io/dapr/exceptions/DaprErrorDetails.java b/sdk/src/main/java/io/dapr/exceptions/DaprErrorDetails.java index f78dc31e6..ee1d182f8 100644 --- a/sdk/src/main/java/io/dapr/exceptions/DaprErrorDetails.java +++ b/sdk/src/main/java/io/dapr/exceptions/DaprErrorDetails.java @@ -33,20 +33,18 @@ public class DaprErrorDetails { static final DaprErrorDetails EMPTY_INSTANCE = new DaprErrorDetails((Status) null); private static final Map, ErrorDetailType> SUPPORTED_ERROR_TYPES = - Collections.unmodifiableMap(new HashMap<>() { - { - put(com.google.rpc.ErrorInfo.class, ErrorDetailType.ERROR_INFO); - put(com.google.rpc.RetryInfo.class, ErrorDetailType.RETRY_INFO); - put(com.google.rpc.DebugInfo.class, ErrorDetailType.DEBUG_INFO); - put(com.google.rpc.QuotaFailure.class, ErrorDetailType.QUOTA_FAILURE); - put(com.google.rpc.PreconditionFailure.class, ErrorDetailType.PRECONDITION_FAILURE); - put(com.google.rpc.BadRequest.class, ErrorDetailType.BAD_REQUEST); - put(com.google.rpc.RequestInfo.class, ErrorDetailType.REQUEST_INFO); - put(com.google.rpc.ResourceInfo.class, ErrorDetailType.RESOURCE_INFO); - put(com.google.rpc.Help.class, ErrorDetailType.HELP); - put(com.google.rpc.LocalizedMessage.class, ErrorDetailType.LOCALIZED_MESSAGE); - } - }); + Map.of( + com.google.rpc.ErrorInfo.class, ErrorDetailType.ERROR_INFO, + com.google.rpc.RetryInfo.class, ErrorDetailType.RETRY_INFO, + com.google.rpc.DebugInfo.class, ErrorDetailType.DEBUG_INFO, + com.google.rpc.QuotaFailure.class, ErrorDetailType.QUOTA_FAILURE, + com.google.rpc.PreconditionFailure.class, ErrorDetailType.PRECONDITION_FAILURE, + com.google.rpc.BadRequest.class, ErrorDetailType.BAD_REQUEST, + com.google.rpc.RequestInfo.class, ErrorDetailType.REQUEST_INFO, + com.google.rpc.ResourceInfo.class, ErrorDetailType.RESOURCE_INFO, + com.google.rpc.Help.class, ErrorDetailType.HELP, + com.google.rpc.LocalizedMessage.class, ErrorDetailType.LOCALIZED_MESSAGE + ); private static final Map> ERROR_TYPES_FQN_REVERSE_LOOKUP = SUPPORTED_ERROR_TYPES.keySet().stream().collect(Collectors.toMap( diff --git a/sdk/src/test/java/io/dapr/client/DaprClientBuilderTest.java b/sdk/src/test/java/io/dapr/client/DaprClientBuilderTest.java index 4a972a019..dbc8ffae1 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientBuilderTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientBuilderTest.java @@ -41,7 +41,6 @@ public void build() { @Test public void buildWithOverrideSidecarIP() { - DaprClientBuilder daprClientBuilder = new DaprClientBuilder(); daprClientBuilder.withPropertyOverride(Properties.SIDECAR_IP, "unknown-host"); DaprClient daprClient = daprClientBuilder.build(); diff --git a/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java index fae617c69..c09a00124 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java @@ -124,7 +124,6 @@ public void waitForSidecarTimeOutHealthCheck() throws Exception { @Test public void waitForSidecarBadHealthCheck() throws Exception { int port = findFreePort(); - System.setProperty(Properties.HTTP_PORT.getName(), Integer.toString(port)); daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), port, daprApiToken, okHttpClient); DaprClient daprClientHttp = buildDaprClient(daprHttp); @@ -149,7 +148,6 @@ public void waitForSidecarBadHealthCheck() throws Exception { @Test public void waitForSidecarSlowSuccessfulHealthCheck() throws Exception { int port = findFreePort(); - System.setProperty(Properties.HTTP_PORT.getName(), Integer.toString(port)); daprHttp = new DaprHttp(Properties.SIDECAR_IP.get(), port, daprApiToken, okHttpClient); DaprClient daprClientHttp = buildDaprClient(daprHttp); @@ -178,7 +176,6 @@ public void waitForSidecarSlowSuccessfulHealthCheck() throws Exception { @Test public void waitForSidecarOK() throws Exception { int port = findFreePort(); - System.setProperty(Properties.HTTP_PORT.getName(), Integer.toString(port)); daprHttp = new DaprHttp(sidecarIp, port, daprApiToken, okHttpClient); DaprClient daprClientHttp = buildDaprClient(daprHttp); @@ -201,7 +198,6 @@ public void waitForSidecarTimeoutOK() throws Exception { .respond(204); try (ServerSocket serverSocket = new ServerSocket(0)) { final int port = serverSocket.getLocalPort(); - System.setProperty(Properties.HTTP_PORT.getName(), Integer.toString(port)); Thread t = new Thread(() -> { try { try (Socket socket = serverSocket.accept()) { diff --git a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java index b65270ba5..bf21e6419 100644 --- a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java @@ -122,9 +122,7 @@ public void invokeMethod() throws IOException { @Test public void invokeMethodIPv6() throws IOException { - String prevSidecarIp = sidecarIp; - System.setProperty(Properties.SIDECAR_IP.getName(), "2001:db8:3333:4444:5555:6666:7777:8888"); - sidecarIp = formatIpAddress(Properties.SIDECAR_IP.get()); + sidecarIp = formatIpAddress("2001:db8:3333:4444:5555:6666:7777:8888"); Map headers = new HashMap<>(); headers.put("content-type", "text/html"); headers.put("header1", "value1"); @@ -132,7 +130,6 @@ public void invokeMethodIPv6() throws IOException { .post("http://" + sidecarIp + ":3500/v1.0/state") .respond(serializer.serialize(EXPECTED_RESULT)); DaprHttp daprHttp = new DaprHttp(sidecarIp, 3500, daprTokenApi, okHttpClient); - System.setProperty(Properties.SIDECAR_IP.getName(), prevSidecarIp); Mono mono = daprHttp.invokeApi("POST", "v1.0/state".split("/"), null, (byte[]) null, headers, Context.empty()); DaprHttp.Response response = mono.block(); diff --git a/sdk/src/test/java/io/dapr/utils/NetworkUtilsTest.java b/sdk/src/test/java/io/dapr/utils/NetworkUtilsTest.java index 878d249f6..d90697f28 100644 --- a/sdk/src/test/java/io/dapr/utils/NetworkUtilsTest.java +++ b/sdk/src/test/java/io/dapr/utils/NetworkUtilsTest.java @@ -8,19 +8,25 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.util.HashMap; +import java.util.Map; + public class NetworkUtilsTest { private final int defaultGrpcPort = 4000; private final String defaultSidecarIP = "127.0.0.1"; private ManagedChannel channel; - private Properties properties = new Properties(); + private Map propertiesOverride; @BeforeEach public void setUp() { - System.setProperty(Properties.GRPC_PORT.getName(), Integer.toString(defaultGrpcPort)); - System.setProperty(Properties.SIDECAR_IP.getName(), defaultSidecarIP); - System.setProperty(Properties.GRPC_ENDPOINT.getName(), ""); + // Must be mutable for some test scenarios here. + propertiesOverride = new HashMap<>(Map.of( + Properties.GRPC_PORT.getName(), Integer.toString(defaultGrpcPort), + Properties.SIDECAR_IP.getName(), defaultSidecarIP, + Properties.GRPC_ENDPOINT.getName(), "" + )); } @AfterEach @@ -32,7 +38,7 @@ public void tearDown() { @Test public void testBuildGrpcManagedChannel() { - channel = NetworkUtils.buildGrpcManagedChannel(properties); + channel = NetworkUtils.buildGrpcManagedChannel(new Properties(propertiesOverride)); String expectedAuthority = String.format("%s:%s", defaultSidecarIP, defaultGrpcPort); Assertions.assertEquals(expectedAuthority, channel.authority()); @@ -40,8 +46,8 @@ public void testBuildGrpcManagedChannel() { @Test public void testBuildGrpcManagedChannel_httpEndpointNoPort() { - System.setProperty(Properties.GRPC_ENDPOINT.getName(), "http://example.com"); - channel = NetworkUtils.buildGrpcManagedChannel(properties); + propertiesOverride.put(Properties.GRPC_ENDPOINT.getName(), "http://example.com"); + channel = NetworkUtils.buildGrpcManagedChannel(new Properties(propertiesOverride)); String expectedAuthority = "example.com:80"; Assertions.assertEquals(expectedAuthority, channel.authority()); @@ -49,8 +55,8 @@ public void testBuildGrpcManagedChannel_httpEndpointNoPort() { @Test public void testBuildGrpcManagedChannel_httpEndpointWithPort() { - System.setProperty(Properties.GRPC_ENDPOINT.getName(), "http://example.com:3000"); - channel = NetworkUtils.buildGrpcManagedChannel(properties); + propertiesOverride.put(Properties.GRPC_ENDPOINT.getName(), "http://example.com:3000"); + channel = NetworkUtils.buildGrpcManagedChannel(new Properties(propertiesOverride)); String expectedAuthority = "example.com:3000"; Assertions.assertEquals(expectedAuthority, channel.authority()); @@ -58,8 +64,8 @@ public void testBuildGrpcManagedChannel_httpEndpointWithPort() { @Test public void testBuildGrpcManagedChannel_httpsEndpointNoPort() { - System.setProperty(Properties.GRPC_ENDPOINT.getName(), "https://example.com"); - channel = NetworkUtils.buildGrpcManagedChannel(properties); + propertiesOverride.put(Properties.GRPC_ENDPOINT.getName(), "https://example.com"); + channel = NetworkUtils.buildGrpcManagedChannel(new Properties(propertiesOverride)); String expectedAuthority = "example.com:443"; Assertions.assertEquals(expectedAuthority, channel.authority()); @@ -67,8 +73,8 @@ public void testBuildGrpcManagedChannel_httpsEndpointNoPort() { @Test public void testBuildGrpcManagedChannel_httpsEndpointWithPort() { - System.setProperty(Properties.GRPC_ENDPOINT.getName(), "https://example.com:3000"); - channel = NetworkUtils.buildGrpcManagedChannel(properties); + propertiesOverride.put(Properties.GRPC_ENDPOINT.getName(), "https://example.com:3000"); + channel = NetworkUtils.buildGrpcManagedChannel(new Properties(propertiesOverride)); String expectedAuthority = "example.com:3000"; Assertions.assertEquals(expectedAuthority, channel.authority()); @@ -138,8 +144,8 @@ private static void testGrpcEndpointParsingScenario( String expectedEndpoint, boolean expectSecure ) { - System.setProperty(Properties.GRPC_ENDPOINT.getName(), grpcEndpointEnvValue); - var settings = NetworkUtils.GrpcEndpointSettings.parse(new Properties()); + var override = Map.of(Properties.GRPC_ENDPOINT.getName(), grpcEndpointEnvValue); + var settings = NetworkUtils.GrpcEndpointSettings.parse(new Properties(override)); Assertions.assertEquals(expectedEndpoint, settings.endpoint); Assertions.assertEquals(expectSecure, settings.secure); @@ -147,8 +153,8 @@ private static void testGrpcEndpointParsingScenario( private static void testGrpcEndpointParsingErrorScenario(String grpcEndpointEnvValue) { try { - System.setProperty(Properties.GRPC_ENDPOINT.getName(), grpcEndpointEnvValue); - NetworkUtils.GrpcEndpointSettings.parse(new Properties()); + var override = Map.of(Properties.GRPC_ENDPOINT.getName(), grpcEndpointEnvValue); + NetworkUtils.GrpcEndpointSettings.parse(new Properties(override)); Assert.fail(); } catch (IllegalArgumentException e) { // Expected From d4c2b1c61f4b69ba4e0cbf5ea5f90ba9ad84cdac Mon Sep 17 00:00:00 2001 From: salaboy Date: Fri, 4 Oct 2024 11:01:50 +0100 Subject: [PATCH 10/14] fixing findbugs Signed-off-by: salaboy --- .../dapr-spring-boot-autoconfigure/pom.xml | 5 ----- .../data/observation/DaprKeyValueContext.java | 8 ++++---- spotbugs-exclude.xml | 20 ++++++++++++++++--- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/dapr-spring/dapr-spring-boot-autoconfigure/pom.xml b/dapr-spring/dapr-spring-boot-autoconfigure/pom.xml index 742250424..bab81a4ea 100644 --- a/dapr-spring/dapr-spring-boot-autoconfigure/pom.xml +++ b/dapr-spring/dapr-spring-boot-autoconfigure/pom.xml @@ -53,11 +53,6 @@ spring-data-keyvalue true - - org.springframework.boot - spring-boot-starter-web - test - org.testcontainers testcontainers diff --git a/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DaprKeyValueContext.java b/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DaprKeyValueContext.java index 7274ad11e..6c9b694b6 100644 --- a/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DaprKeyValueContext.java +++ b/dapr-spring/dapr-spring-data/src/main/java/io/dapr/spring/data/observation/DaprKeyValueContext.java @@ -41,16 +41,16 @@ public Map properties() { /** - * The name of the bean sending the message (typically a {@code DaprMessagingTemplate}). - * @return the name of the bean sending the message + * The name of the bean interacting with the KeyValue Store (typically a {@code DaprKeyValueTemplate}). + * @return the name of the bean interacting with the KeyValue store */ public String getBeanName() { return this.beanName; } /** - * The destination topic for the message. - * @return the topic the message is being sent to + * The KeyValue store used for storing/retriving data. + * @return the key value store used */ public String getKeyValueStore() { return this.keyValueStore; diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml index f0111ca63..b27c317a3 100644 --- a/spotbugs-exclude.xml +++ b/spotbugs-exclude.xml @@ -22,6 +22,12 @@ + + + + + + @@ -46,9 +52,17 @@ - - - + + + + + + + + + + + \ No newline at end of file From 232bcff6e26549c83836a7765e2613bd6ab79f50 Mon Sep 17 00:00:00 2001 From: Artur Souza Date: Wed, 18 Sep 2024 11:13:17 -0700 Subject: [PATCH 11/14] Handle HTTP binding error. (#1024) (#1130) Update binding http IT Signed-off-by: Artur Souza Signed-off-by: salaboy --- .../java/io/dapr/it/binding/http/BindingIT.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java b/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java index 8b104f0d8..e023ef9ea 100644 --- a/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java @@ -38,10 +38,10 @@ public class BindingIT extends BaseIT { @Test public void httpOutputBindingError() throws Exception { - var run = startDaprApp( + startDaprApp( this.getClass().getSimpleName() + "-httpoutputbinding-exception", 60000); - try(DaprClient client = run.newDaprClientBuilder().build()) { + try(DaprClient client = new DaprClientBuilder().build()) { // Validate error message callWithRetry(() -> { System.out.println("Checking exception handling for output binding ..."); @@ -61,10 +61,10 @@ public void httpOutputBindingError() throws Exception { @Test public void httpOutputBindingErrorIgnoredByComponent() throws Exception { - var run = startDaprApp( + startDaprApp( this.getClass().getSimpleName() + "-httpoutputbinding-ignore-error", 60000); - try(DaprClient client = run.newDaprClientBuilder().build()) { + try(DaprClient client = new DaprClientBuilder().build()) { // Validate error message callWithRetry(() -> { System.out.println("Checking exception handling for output binding ..."); @@ -93,7 +93,7 @@ public void inputOutputBinding() throws Exception { var bidingName = "sample123"; - try(DaprClient client = daprRun.newDaprClientBuilder().build()) { + try(DaprClient client = new DaprClientBuilder().build()) { callWithRetry(() -> { System.out.println("Checking if input binding is up before publishing events ..."); client.invokeBinding( @@ -116,14 +116,14 @@ public void inputOutputBinding() throws Exception { System.out.println("sending first message"); client.invokeBinding( - bidingName, "create", myClass, Map.of("MyMetadata", "MyValue"), Void.class).block(); + bidingName, "create", myClass, Collections.singletonMap("MyMetadata", "MyValue"), Void.class).block(); // This is an example of sending a plain string. The input binding will receive // cat final String m = "cat"; System.out.println("sending " + m); client.invokeBinding( - bidingName, "create", m, Map.of("MyMetadata", "MyValue"), Void.class).block(); + bidingName, "create", m, Collections.singletonMap("MyMetadata", "MyValue"), Void.class).block(); // Metadata is not used by Kafka component, so it is not possible to validate. callWithRetry(() -> { From fbd8402ddebfade1f1407b1c23e0381db7b7175e Mon Sep 17 00:00:00 2001 From: Artur Souza Date: Wed, 2 Oct 2024 15:54:48 -0700 Subject: [PATCH 12/14] Remove all global state from setProperty (#1138) * Remove all global state in from setProperty Signed-off-by: Artur Souza * use Map.of Signed-off-by: Artur Souza * Remove dependency that is not needed. Signed-off-by: Artur Souza --------- Signed-off-by: Artur Souza Signed-off-by: salaboy --- .../spring/messaging/DaprMessagingTemplate.java | 5 +++++ .../java/io/dapr/it/binding/http/BindingIT.java | 14 +++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java index 03e4cb61b..34de90f0b 100644 --- a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java +++ b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java @@ -32,10 +32,15 @@ import reactor.core.publisher.Hooks; import reactor.core.publisher.Mono; <<<<<<< HEAD +<<<<<<< HEAD import reactor.util.context.Context; import java.util.Collections; import java.util.HashMap; ======= +======= + +import java.util.Map; +>>>>>>> 7490434d (Remove all global state from setProperty (#1138)) >>>>>>> 7490434d (Remove all global state from setProperty (#1138)) import java.util.Map; diff --git a/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java b/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java index e023ef9ea..8b104f0d8 100644 --- a/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/binding/http/BindingIT.java @@ -38,10 +38,10 @@ public class BindingIT extends BaseIT { @Test public void httpOutputBindingError() throws Exception { - startDaprApp( + var run = startDaprApp( this.getClass().getSimpleName() + "-httpoutputbinding-exception", 60000); - try(DaprClient client = new DaprClientBuilder().build()) { + try(DaprClient client = run.newDaprClientBuilder().build()) { // Validate error message callWithRetry(() -> { System.out.println("Checking exception handling for output binding ..."); @@ -61,10 +61,10 @@ public void httpOutputBindingError() throws Exception { @Test public void httpOutputBindingErrorIgnoredByComponent() throws Exception { - startDaprApp( + var run = startDaprApp( this.getClass().getSimpleName() + "-httpoutputbinding-ignore-error", 60000); - try(DaprClient client = new DaprClientBuilder().build()) { + try(DaprClient client = run.newDaprClientBuilder().build()) { // Validate error message callWithRetry(() -> { System.out.println("Checking exception handling for output binding ..."); @@ -93,7 +93,7 @@ public void inputOutputBinding() throws Exception { var bidingName = "sample123"; - try(DaprClient client = new DaprClientBuilder().build()) { + try(DaprClient client = daprRun.newDaprClientBuilder().build()) { callWithRetry(() -> { System.out.println("Checking if input binding is up before publishing events ..."); client.invokeBinding( @@ -116,14 +116,14 @@ public void inputOutputBinding() throws Exception { System.out.println("sending first message"); client.invokeBinding( - bidingName, "create", myClass, Collections.singletonMap("MyMetadata", "MyValue"), Void.class).block(); + bidingName, "create", myClass, Map.of("MyMetadata", "MyValue"), Void.class).block(); // This is an example of sending a plain string. The input binding will receive // cat final String m = "cat"; System.out.println("sending " + m); client.invokeBinding( - bidingName, "create", m, Collections.singletonMap("MyMetadata", "MyValue"), Void.class).block(); + bidingName, "create", m, Map.of("MyMetadata", "MyValue"), Void.class).block(); // Metadata is not used by Kafka component, so it is not possible to validate. callWithRetry(() -> { From b28f823c9f317e1e3677df18110000c1298966d4 Mon Sep 17 00:00:00 2001 From: salaboy Date: Fri, 4 Oct 2024 11:12:07 +0100 Subject: [PATCH 13/14] exclude NP Signed-off-by: salaboy --- spotbugs-exclude.xml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml index b27c317a3..c0fcf5d3f 100644 --- a/spotbugs-exclude.xml +++ b/spotbugs-exclude.xml @@ -53,15 +53,13 @@ - - + - - + From 89210c9a321508f862d677a9f9f7fefea4ccab13 Mon Sep 17 00:00:00 2001 From: salaboy Date: Thu, 31 Oct 2024 09:25:27 +0000 Subject: [PATCH 14/14] removing unused imports --- .../java/io/dapr/spring/messaging/DaprMessagingTemplate.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java index 6eb3f5198..6d94fdeb4 100644 --- a/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java +++ b/dapr-spring/dapr-spring-messaging/src/main/java/io/dapr/spring/messaging/DaprMessagingTemplate.java @@ -31,7 +31,6 @@ import org.springframework.lang.Nullable; import reactor.core.publisher.Hooks; import reactor.core.publisher.Mono; - import reactor.util.context.Context; import java.util.Collections; import java.util.HashMap;