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 7e10c1f8fe..bc81885aa0 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 @@ -13,6 +13,7 @@ package io.dapr.spring.boot.autoconfigure.client; +import io.dapr.actors.client.ActorClient; import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; import io.dapr.config.Properties; @@ -70,6 +71,13 @@ DaprWorkflowClient daprWorkflowClient(DaprConnectionDetails daprConnectionDetail return new DaprWorkflowClient(properties); } + @Bean + @ConditionalOnMissingBean + ActorClient daprActorClient(DaprConnectionDetails daprConnectionDetails) { + Properties properties = createPropertiesFromConnectionDetails(daprConnectionDetails); + return new ActorClient(properties); + } + @Bean @ConditionalOnMissingBean WorkflowRuntimeBuilder daprWorkflowRuntimeBuilder(DaprConnectionDetails daprConnectionDetails) { 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 08c0a1c9ec..1fe2d4f19d 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 @@ -15,6 +15,7 @@ import io.dapr.client.resiliency.ResiliencyOptions; import io.dapr.config.Properties; +import io.dapr.utils.NetworkUtils; import io.dapr.utils.Version; import io.dapr.v1.DaprGrpc; import io.grpc.Channel; @@ -83,7 +84,7 @@ public ActorClient(Properties overrideProperties, ResiliencyOptions resiliencyOp * @param resiliencyOptions Client resiliency options. */ public ActorClient(Properties overrideProperties, Map metadata, ResiliencyOptions resiliencyOptions) { - this(buildManagedChannel(overrideProperties), + this(NetworkUtils.buildGrpcManagedChannel(overrideProperties), metadata, resiliencyOptions, overrideProperties.getValue(Properties.API_TOKEN)); @@ -129,25 +130,6 @@ 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(Properties overrideProperties) { - int port = overrideProperties.getValue(Properties.GRPC_PORT); - if (port <= 0) { - throw new IllegalArgumentException("Invalid port."); - } - - var sidecarHost = overrideProperties.getValue(Properties.SIDECAR_IP); - - return ManagedChannelBuilder.forAddress(sidecarHost, port) - .usePlaintext() - .userAgent(Version.getSdkVersion()) - .build(); - } /** * Build an instance of the Client based on the provided setup. 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 67d6b9659c..90bab85e52 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 @@ -141,7 +141,7 @@ public void writeReadState() throws Exception { proxyBuilder = new ActorProxyBuilder(actorType, ActorProxy.class, deferClose(run2.newActorClient())); ActorProxy newProxy = proxyBuilder.build(actorId); - // wating for actor to be activated + // waiting for actor to be activated Thread.sleep(2000); callWithRetry(() -> { diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprActorsIT.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprActorsIT.java new file mode 100644 index 0000000000..1a9107857f --- /dev/null +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprActorsIT.java @@ -0,0 +1,81 @@ +package io.dapr.it.testcontainers; + +import io.dapr.actors.ActorId; +import io.dapr.actors.client.ActorClient; +import io.dapr.actors.client.ActorProxyBuilder; +import io.dapr.actors.runtime.ActorRuntime; +import io.dapr.testcontainers.Component; +import io.dapr.testcontainers.DaprContainer; +import io.dapr.testcontainers.DaprLogLevel; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.Network; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.util.Map; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@SpringBootTest( + webEnvironment = WebEnvironment.RANDOM_PORT, + classes = { + TestActorsApplication.class, + TestDaprActorsConfiguration.class + } +) +@Testcontainers +@Tag("testcontainers") +public class DaprActorsIT { + private static final Network DAPR_NETWORK = Network.newNetwork(); + + @Container + private static final DaprContainer DAPR_CONTAINER = new DaprContainer("daprio/daprd:1.14.1") + .withAppName("actor-dapr-app") + .withNetwork(DAPR_NETWORK) + .withComponent(new Component("kvstore", "state.in-memory", "v1", + Map.of("actorStateStore", "true"))) + .withDaprLogLevel(DaprLogLevel.DEBUG) + .withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String())) + .withAppChannelAddress("host.testcontainers.internal"); + + /** + * Expose the Dapr ports to the host. + * + * @param registry the dynamic property registry + */ + @DynamicPropertySource + static void daprProperties(DynamicPropertyRegistry registry) { + registry.add("dapr.http.endpoint", DAPR_CONTAINER::getHttpEndpoint); + registry.add("dapr.grpc.endpoint", DAPR_CONTAINER::getGrpcEndpoint); + } + + @BeforeAll + public static void setUp(){ + ActorRuntime.getInstance().registerActor(TestActorImpl.class); + } + + @Autowired + private ActorClient daprActorClient; + + @Test + public void testActors() throws Exception { + + ActorProxyBuilder builder = new ActorProxyBuilder<>(TestActor.class, daprActorClient); + ActorId actorId = ActorId.createRandom(); + TestActor actor = builder.build(actorId); + + String message = UUID.randomUUID().toString(); + + String echoedMessage = actor.echo(message); + + assertEquals(echoedMessage, message); + } +} 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 f0c39ed803..0e71ce647c 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 @@ -56,7 +56,7 @@ public class DaprWorkflowsIT { private static final Network DAPR_NETWORK = Network.newNetwork(); @Container - private static final DaprContainer DAPR_CONTAINER = new DaprContainer("daprio/daprd:1.13.2") + private static final DaprContainer DAPR_CONTAINER = new DaprContainer("daprio/daprd:1.14.1") .withAppName("workflow-dapr-app") .withNetwork(DAPR_NETWORK) .withComponent(new Component("kvstore", "state.in-memory", "v1", diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestActor.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestActor.java new file mode 100644 index 0000000000..a3f8ef6d06 --- /dev/null +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestActor.java @@ -0,0 +1,9 @@ +package io.dapr.it.testcontainers; +import io.dapr.actors.ActorMethod; +import io.dapr.actors.ActorType; + +@ActorType(name = "TestActor") +public interface TestActor { + @ActorMethod(name = "echo_message") + String echo(String message); +} diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestActorImpl.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestActorImpl.java new file mode 100644 index 0000000000..0a5febddef --- /dev/null +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestActorImpl.java @@ -0,0 +1,16 @@ +package io.dapr.it.testcontainers; + +import io.dapr.actors.ActorId; +import io.dapr.actors.runtime.AbstractActor; +import io.dapr.actors.runtime.ActorRuntimeContext; + +public class TestActorImpl extends AbstractActor implements TestActor { + public TestActorImpl(ActorRuntimeContext runtimeContext, ActorId id) { + super(runtimeContext, id); + } + + @Override + public String echo(String message) { + return message; + } +} diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestActorsApplication.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestActorsApplication.java new file mode 100644 index 0000000000..ba9a748c8a --- /dev/null +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestActorsApplication.java @@ -0,0 +1,25 @@ +/* + * 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.it.testcontainers; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class TestActorsApplication { + + public static void main(String[] args) { + SpringApplication.run(TestActorsApplication.class, args); + } +} diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprActorsConfiguration.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprActorsConfiguration.java new file mode 100644 index 0000000000..5d169c28fa --- /dev/null +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprActorsConfiguration.java @@ -0,0 +1,26 @@ +package io.dapr.it.testcontainers; + +import java.util.Map; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import io.dapr.actors.client.ActorClient; +import io.dapr.config.Properties; + +@Configuration +public class TestDaprActorsConfiguration { + @Bean + public ActorClient daprActorClient( + @Value("${dapr.http.endpoint}") String daprHttpEndpoint, + @Value("${dapr.grpc.endpoint}") String daprGrpcEndpoint + ){ + Map overrides = Map.of( + "dapr.http.endpoint", daprHttpEndpoint, + "dapr.grpc.endpoint", daprGrpcEndpoint + ); + + return new ActorClient(new Properties(overrides)); + } +}