mirror of https://github.com/dapr/java-sdk.git
Initial Testcontainers integration for Dapr (#1085)
* initial testcontainers pr
Signed-off-by: salaboy <Salaboy@gmail.com>
* fixing variable reference
Signed-off-by: salaboy <Salaboy@gmail.com>
* adding equals to spotbug issues
Signed-off-by: salaboy <Salaboy@gmail.com>
* adding http port to run tests
Signed-off-by: salaboy <Salaboy@gmail.com>
* updating pom
Signed-off-by: salaboy <Salaboy@gmail.com>
* fixing style
Signed-off-by: salaboy <Salaboy@gmail.com>
* extracting classes
Signed-off-by: salaboy <Salaboy@gmail.com>
* removing restassured dependency
Signed-off-by: salaboy <Salaboy@gmail.com>
* refactoring IT out to sdk-tests
Signed-off-by: salaboy <Salaboy@gmail.com>
* adding correct wiremock dep version
Signed-off-by: salaboy <Salaboy@gmail.com>
* missing header
Signed-off-by: salaboy <Salaboy@gmail.com>
* fixing spotbugs issue
Signed-off-by: salaboy <Salaboy@gmail.com>
* adding hashcode too
Signed-off-by: salaboy <Salaboy@gmail.com>
* testing configure method
Signed-off-by: salaboy <Salaboy@gmail.com>
* making inmutable collections and maps
Signed-off-by: salaboy <Salaboy@gmail.com>
* checkstyle
Signed-off-by: salaboy <Salaboy@gmail.com>
* removing space
Signed-off-by: salaboy <Salaboy@gmail.com>
* Refactor tracking of alpha artifact version
Signed-off-by: Artur Souza <asouza.pro@gmail.com>
Signed-off-by: salaboy <Salaboy@gmail.com>
* Use
Usage: docker compose [OPTIONS] COMMAND
Define and run multi-container applications with Docker
Options:
--all-resources Include all resources, even those not used by services
--ansi string Control when to print ANSI control characters ("never"|"always"|"auto") (default "auto")
--compatibility Run compose in backward compatibility mode
--dry-run Execute command in dry run mode
--env-file stringArray Specify an alternate environment file
-f, --file stringArray Compose configuration files
--parallel int Control max parallelism, -1 for unlimited (default -1)
--profile stringArray Specify a profile to enable
--progress string Set type of progress output (auto, tty, plain, quiet) (default "auto")
--project-directory string Specify an alternate working directory
(default: the path of the, first specified, Compose file)
-p, --project-name string Project name
Commands:
attach Attach local standard input, output, and error streams to a service's running container
build Build or rebuild services
config Parse, resolve and render compose file in canonical format
cp Copy files/folders between a service container and the local filesystem
create Creates containers for a service
down Stop and remove containers, networks
events Receive real time events from containers
exec Execute a command in a running container
images List images used by the created containers
kill Force stop service containers
logs View output from containers
ls List running compose projects
pause Pause services
port Print the public port for a port binding
ps List containers
pull Pull service images
push Push service images
restart Restart service containers
rm Removes stopped service containers
run Run a one-off command on a service
scale Scale services
start Start services
stats Display a live stream of container(s) resource usage statistics
stop Stop services
top Display the running processes
unpause Unpause services
up Create and start containers
version Show the Docker Compose version information
wait Block until the first service container stops
watch Watch build context for service and rebuild/refresh containers when files are updated
Run 'docker compose COMMAND --help' for more information on a command. instead of docker-compose
Signed-off-by: Artur Souza <asouza.pro@gmail.com>
Signed-off-by: salaboy <Salaboy@gmail.com>
* removing version from docker compose
Signed-off-by: salaboy <Salaboy@gmail.com>
* Update README.md
Signed-off-by: Artur Souza <asouza.pro@gmail.com>
---------
Signed-off-by: salaboy <Salaboy@gmail.com>
Signed-off-by: Artur Souza <asouza.pro@gmail.com>
Co-authored-by: Artur Souza <asouza.pro@gmail.com>
This commit is contained in:
parent
5618af5ed9
commit
e30dc2df28
|
|
@ -4,14 +4,23 @@ set -uex
|
|||
|
||||
DAPR_JAVA_SDK_VERSION=$1
|
||||
|
||||
# The workflows sdk tracks the regular SDK minor and patch versions, just not the major.
|
||||
# Replaces the workflows SDK major version to 0 until it is stable.
|
||||
DAPR_JAVA_WORKFLOWS_SDK_VERSION=`echo $DAPR_JAVA_SDK_VERSION | sed 's/^[0-9]*\./0./'`
|
||||
# Alpha artifacts of the sdk tracks the regular SDK minor and patch versions, just not the major.
|
||||
# Replaces the SDK major version to 0 for alpha artifacts.
|
||||
DAPR_JAVA_SDK_ALPHA_VERSION=`echo $DAPR_JAVA_SDK_VERSION | sed 's/^[0-9]*\./0./'`
|
||||
|
||||
mvn versions:set -DnewVersion=$DAPR_JAVA_SDK_VERSION
|
||||
mvn versions:set-property -Dproperty=dapr.sdk.alpha.version -DnewVersion=$DAPR_JAVA_SDK_ALPHA_VERSION
|
||||
mvn versions:set-property -Dproperty=dapr.sdk.version -DnewVersion=$DAPR_JAVA_SDK_VERSION -f sdk-tests/pom.xml
|
||||
mvn versions:set-property -Dproperty=dapr.sdk.alpha.version -DnewVersion=$DAPR_JAVA_SDK_ALPHA_VERSION -f sdk-tests/pom.xml
|
||||
|
||||
mvn versions:set -DnewVersion=$DAPR_JAVA_WORKFLOWS_SDK_VERSION -f sdk-workflows/pom.xml
|
||||
mvn versions:set-property -Dproperty=dapr.sdk-workflows.version -DnewVersion=$DAPR_JAVA_WORKFLOWS_SDK_VERSION
|
||||
###################
|
||||
# Alpha artifacts #
|
||||
###################
|
||||
|
||||
# sdk-workflows
|
||||
mvn versions:set -DnewVersion=$DAPR_JAVA_SDK_ALPHA_VERSION -f sdk-workflows/pom.xml
|
||||
|
||||
# testcontainers-dapr
|
||||
mvn versions:set -DnewVersion=$DAPR_JAVA_SDK_ALPHA_VERSION -f testcontainers-dapr/pom.xml
|
||||
|
||||
git clean -f
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ jobs:
|
|||
./dist/linux_amd64/release/placement &
|
||||
- name: Spin local environment
|
||||
run: |
|
||||
docker-compose -f ./sdk-tests/deploy/local-test.yml up -d mongo kafka
|
||||
docker compose -f ./sdk-tests/deploy/local-test.yml up -d mongo kafka
|
||||
docker ps
|
||||
- name: Install local ToxiProxy to simulate connectivity issues to Dapr sidecar
|
||||
run: |
|
||||
|
|
|
|||
|
|
@ -237,13 +237,13 @@ Similarly, all of these need to be run for running the ITs either individually o
|
|||
Run the following commands from the root of the repo to start all the docker containers that the tests depend on.
|
||||
|
||||
```bash
|
||||
docker-compose -f ./sdk-tests/deploy/local-test.yml up -d
|
||||
docker compose -f ./sdk-tests/deploy/local-test.yml up -d
|
||||
```
|
||||
|
||||
To stop the containers and services, run the following commands.
|
||||
|
||||
```bash
|
||||
docker-compose -f ./sdk-tests/deploy/local-test.yml down
|
||||
docker compose -f ./sdk-tests/deploy/local-test.yml down
|
||||
```
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@
|
|||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-workflows</artifactId>
|
||||
<version>${dapr.sdk-workflows.version}</version>
|
||||
<version>${dapr.sdk.alpha.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
|
|
|
|||
|
|
@ -58,13 +58,11 @@ Before getting into the application code, follow these steps in order to set up
|
|||
|
||||
<!-- STEP
|
||||
name: Setup kafka container
|
||||
expected_stderr_lines:
|
||||
- 'Creating network "http_default" with the default driver'
|
||||
sleep: 20
|
||||
-->
|
||||
|
||||
```bash
|
||||
docker-compose -f ./src/main/java/io/dapr/examples/bindings/http/docker-compose-single-kafka.yml up -d
|
||||
docker compose -f ./src/main/java/io/dapr/examples/bindings/http/docker-compose-single-kafka.yml up -d
|
||||
```
|
||||
|
||||
<!-- END_STEP -->
|
||||
|
|
@ -248,7 +246,7 @@ name: Cleanup Kafka containers
|
|||
-->
|
||||
|
||||
```bash
|
||||
docker-compose -f ./src/main/java/io/dapr/examples/bindings/http/docker-compose-single-kafka.yml down
|
||||
docker compose -f ./src/main/java/io/dapr/examples/bindings/http/docker-compose-single-kafka.yml down
|
||||
```
|
||||
|
||||
<!-- END_STEP -->
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: '3'
|
||||
services:
|
||||
zookeeper:
|
||||
image: confluentinc/cp-zookeeper:7.4.4
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ sleep: 5
|
|||
-->
|
||||
|
||||
```bash
|
||||
docker-compose -f ./src/main/java/io/dapr/examples/querystate/docker-compose-single-mongo.yml up -d
|
||||
docker compose -f ./src/main/java/io/dapr/examples/querystate/docker-compose-single-mongo.yml up -d
|
||||
```
|
||||
|
||||
<!-- END_STEP -->
|
||||
|
|
@ -305,7 +305,7 @@ name: Cleanup MongoDB containers
|
|||
-->
|
||||
|
||||
```bash
|
||||
docker-compose -f ./src/main/java/io/dapr/examples/querystate/docker-compose-single-mongo.yml down
|
||||
docker compose -f ./src/main/java/io/dapr/examples/querystate/docker-compose-single-mongo.yml down
|
||||
```
|
||||
|
||||
<!-- END_STEP -->
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: '3'
|
||||
services:
|
||||
mongo:
|
||||
image: mongo
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ sleep: 5
|
|||
-->
|
||||
|
||||
```bash
|
||||
docker-compose -f ./src/main/java/io/dapr/examples/state/docker-compose-single-mongo.yml up -d
|
||||
docker compose -f ./src/main/java/io/dapr/examples/state/docker-compose-single-mongo.yml up -d
|
||||
```
|
||||
|
||||
<!-- END_STEP -->
|
||||
|
|
@ -227,7 +227,7 @@ name: Cleanup MongoDB container
|
|||
-->
|
||||
|
||||
```bash
|
||||
docker-compose -f ./src/main/java/io/dapr/examples/state/docker-compose-single-mongo.yml down
|
||||
docker compose -f ./src/main/java/io/dapr/examples/state/docker-compose-single-mongo.yml down
|
||||
```
|
||||
|
||||
<!-- END_STEP -->
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: '3'
|
||||
services:
|
||||
mongo:
|
||||
image: mongo
|
||||
|
|
|
|||
6
pom.xml
6
pom.xml
|
|
@ -17,7 +17,7 @@
|
|||
<grpc.version>1.59.0</grpc.version>
|
||||
<protobuf.version>3.17.3</protobuf.version>
|
||||
<dapr.proto.baseurl>https://raw.githubusercontent.com/dapr/dapr/v1.13.0-rc.5/dapr/proto</dapr.proto.baseurl>
|
||||
<dapr.sdk-workflows.version>0.12.0-SNAPSHOT</dapr.sdk-workflows.version>
|
||||
<dapr.sdk.alpha.version>0.12.0-SNAPSHOT</dapr.sdk.alpha.version>
|
||||
<os-maven-plugin.version>1.6.2</os-maven-plugin.version>
|
||||
<maven-dependency-plugin.version>3.1.1</maven-dependency-plugin.version>
|
||||
<maven-antrun-plugin.version>1.8</maven-antrun-plugin.version>
|
||||
|
|
@ -38,6 +38,8 @@
|
|||
<failsafe.version>3.2.2</failsafe.version>
|
||||
<surefire.version>3.2.2</surefire.version>
|
||||
<junit-bom.version>5.8.2</junit-bom.version>
|
||||
<snakeyaml.version>2.0</snakeyaml.version>
|
||||
<testcontainers.version>1.20.0</testcontainers.version>
|
||||
</properties>
|
||||
|
||||
<distributionManagement>
|
||||
|
|
@ -330,6 +332,8 @@
|
|||
<module>sdk-workflows</module>
|
||||
<module>sdk-springboot</module>
|
||||
<module>examples</module>
|
||||
<!-- We are following test containers artifact convention on purpose, don't rename -->
|
||||
<module>testcontainers-dapr</module>
|
||||
<!-- don't add sdk-tests to the build,
|
||||
it's only used for CI testing by github action
|
||||
<module>sdk-tests</module>
|
||||
|
|
|
|||
|
|
@ -16,12 +16,15 @@
|
|||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
<dapr.sdk.version>1.12.0-SNAPSHOT</dapr.sdk.version>
|
||||
<dapr.sdk.alpha.version>0.12.0-SNAPSHOT</dapr.sdk.alpha.version>
|
||||
<protobuf.output.directory>${project.build.directory}/generated-sources</protobuf.output.directory>
|
||||
<protobuf.input.directory>${project.basedir}/proto</protobuf.input.directory>
|
||||
<grpc.version>1.59.0</grpc.version>
|
||||
<protobuf.version>3.17.3</protobuf.version>
|
||||
<opentelemetry.version>1.39.0</opentelemetry.version>
|
||||
<spring-boot.version>3.3.1</spring-boot.version>
|
||||
<logback-classic.version>1.4.12</logback-classic.version>
|
||||
<wiremock.version>3.9.1</wiremock.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
|
@ -130,6 +133,12 @@
|
|||
<version>${dapr.sdk.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>testcontainers-dapr</artifactId>
|
||||
<version>${dapr.sdk.alpha.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-actors</artifactId>
|
||||
|
|
@ -147,6 +156,18 @@
|
|||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.wiremock</groupId>
|
||||
<artifactId>wiremock-standalone</artifactId>
|
||||
<version>${wiremock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback-classic.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* 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 com.github.tomakehurst.wiremock.junit.WireMockRule;
|
||||
import io.dapr.client.DaprClient;
|
||||
import io.dapr.client.DaprClientBuilder;
|
||||
import io.dapr.client.domain.Metadata;
|
||||
import io.dapr.client.domain.State;
|
||||
|
||||
import io.dapr.testcontainers.DaprContainer;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.testcontainers.Testcontainers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.any;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.configureFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.post;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
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 com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class DaprContainerTest {
|
||||
|
||||
// Time-to-live for messages published.
|
||||
private static final String MESSAGE_TTL_IN_SECONDS = "1000";
|
||||
private static final String STATE_STORE_NAME = "kvstore";
|
||||
private static final String KEY = "my-key";
|
||||
private static final String PUBSUB_NAME = "pubsub";
|
||||
private static final String PUBSUB_TOPIC_NAME = "topic";
|
||||
|
||||
@ClassRule
|
||||
public static WireMockRule wireMockRule = new WireMockRule(wireMockConfig().port(8081));
|
||||
|
||||
@ClassRule
|
||||
public static DaprContainer daprContainer = new DaprContainer("daprio/daprd")
|
||||
.withAppName("dapr-app")
|
||||
.withAppPort(8081)
|
||||
.withAppChannelAddress("host.testcontainers.internal");
|
||||
|
||||
/**
|
||||
* Sets the Dapr properties for the test.
|
||||
*/
|
||||
@BeforeClass
|
||||
public static void setDaprProperties() {
|
||||
configStub();
|
||||
Testcontainers.exposeHostPorts(8081);
|
||||
System.setProperty("dapr.grpc.port", Integer.toString(daprContainer.getGrpcPort()));
|
||||
System.setProperty("dapr.http.port", Integer.toString(daprContainer.getHttpPort()));
|
||||
}
|
||||
|
||||
private static void configStub() {
|
||||
|
||||
stubFor(any(urlMatching("/dapr/subscribe"))
|
||||
.willReturn(aResponse().withBody("[]").withStatus(200)));
|
||||
|
||||
stubFor(get(urlMatching("/dapr/config"))
|
||||
.willReturn(aResponse().withBody("[]").withStatus(200)));
|
||||
|
||||
stubFor(any(urlMatching("/([a-z1-9]*)"))
|
||||
.willReturn(aResponse().withBody("[]").withStatus(200)));
|
||||
|
||||
// create a stub
|
||||
stubFor(post(urlEqualTo("/events"))
|
||||
.willReturn(aResponse().withBody("event received!").withStatus(200)));
|
||||
|
||||
configureFor("localhost", 8081);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDaprContainerDefaults() {
|
||||
assertEquals(
|
||||
"The pubsub and kvstore component should be configured by default",
|
||||
2,
|
||||
daprContainer.getComponents().size());
|
||||
assertEquals(
|
||||
"A subscription should be configured by default if none is provided",
|
||||
1,
|
||||
daprContainer.getSubscriptions().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStateStore() throws Exception {
|
||||
try (DaprClient client = (new DaprClientBuilder()).build()) {
|
||||
client.waitForSidecar(5000).block();
|
||||
|
||||
String value = "value";
|
||||
// Save state
|
||||
client.saveState(STATE_STORE_NAME, KEY, value).block();
|
||||
|
||||
// Get the state back from the state store
|
||||
State<String> retrievedState = client.getState(STATE_STORE_NAME, KEY, String.class).block();
|
||||
|
||||
assertEquals("The value retrieved should be the same as the one stored", value, retrievedState.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlacement() throws Exception {
|
||||
// Here we are just waiting for Dapr to be ready
|
||||
try (DaprClient client = (new DaprClientBuilder()).build()) {
|
||||
client.waitForSidecar(5000).block();
|
||||
}
|
||||
|
||||
OkHttpClient client = new OkHttpClient.Builder().build();
|
||||
|
||||
String url = "http://" + daprContainer.getHost() + ":" + daprContainer.getMappedPort(3500);
|
||||
Request request = new Request.Builder().url(url + "/v1.0/metadata").build();
|
||||
|
||||
try (Response response = client.newCall(request).execute()) {
|
||||
if (response.isSuccessful()) {
|
||||
assertTrue(response.body().string().contains("placement: connected"));
|
||||
|
||||
} else {
|
||||
throw new IOException("Unexpected response: " + response.code());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPubSub() throws Exception {
|
||||
try (DaprClient client = (new DaprClientBuilder()).build()) {
|
||||
client.waitForSidecar(5000).block();
|
||||
|
||||
String message = "message content";
|
||||
Map<String, String> metadata = singletonMap(Metadata.TTL_IN_SECONDS, MESSAGE_TTL_IN_SECONDS);
|
||||
client.publishEvent(PUBSUB_NAME, PUBSUB_TOPIC_NAME, message, metadata).block();
|
||||
}
|
||||
|
||||
verify(getRequestedFor(urlMatching("/dapr/config")));
|
||||
verify(postRequestedFor(urlEqualTo("/events")).withHeader("Content-Type", equalTo("application/cloudevents+json")));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-parent</artifactId>
|
||||
<version>1.12.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>testcontainers-dapr</artifactId>
|
||||
<name>testcontainers-dapr</name>
|
||||
<description>Testcontainers Dapr Module</description>
|
||||
<version>0.12.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>${snakeyaml.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers</artifactId>
|
||||
<version>${testcontainers.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.11</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>report</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>target/jacoco-report/</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>check</id>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<rule>
|
||||
<element>BUNDLE</element>
|
||||
<limits>
|
||||
<limit>
|
||||
<counter>LINE</counter>
|
||||
<value>COVEREDRATIO</value>
|
||||
<minimum>80%</minimum>
|
||||
</limit>
|
||||
</limits>
|
||||
</rule>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a Dapr component.
|
||||
*/
|
||||
public class Component {
|
||||
private String name;
|
||||
private String type;
|
||||
private String version;
|
||||
private List<MetadataEntry> metadata;
|
||||
|
||||
/**
|
||||
* Creates a new component.
|
||||
*
|
||||
* @param name Component name.
|
||||
* @param type Component type.
|
||||
* @param version Component version.
|
||||
* @param metadata Metadata.
|
||||
*/
|
||||
public Component(String name, String type, String version, Map<String, String> metadata) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.version = version;
|
||||
|
||||
List<MetadataEntry> entries = new ArrayList<>();
|
||||
if (!metadata.isEmpty()) {
|
||||
for (Map.Entry<String, String> entry : metadata.entrySet()) {
|
||||
entries.add(new MetadataEntry(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
}
|
||||
this.metadata = Collections.unmodifiableList(entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new component.
|
||||
*
|
||||
* @param name Component name.
|
||||
* @param type Component type.
|
||||
* @param version Component version.
|
||||
* @param metadataEntries Component metadata entries.
|
||||
*/
|
||||
public Component(String name, String type, String version, List<MetadataEntry> metadataEntries) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.version = version;
|
||||
metadata = Objects.requireNonNull(metadataEntries);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public List<MetadataEntry> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,341 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.Network;
|
||||
import org.testcontainers.images.builder.Transferable;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.nodes.Tag;
|
||||
import org.yaml.snakeyaml.representer.Representer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class DaprContainer extends GenericContainer<DaprContainer> {
|
||||
|
||||
private static final int DAPRD_DEFAULT_HTTP_PORT = 3500;
|
||||
private static final int DAPRD_DEFAULT_GRPC_PORT = 50001;
|
||||
private final Set<Component> components = new HashSet<>();
|
||||
private final Set<Subscription> subscriptions = new HashSet<>();
|
||||
private DaprProtocol protocol = DaprProtocol.HTTP;
|
||||
private String appName;
|
||||
private Integer appPort = null;
|
||||
private DaprLogLevel daprLogLevel = DaprLogLevel.INFO;
|
||||
private String appChannelAddress = "localhost";
|
||||
private String placementService = "placement";
|
||||
private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("daprio/daprd");
|
||||
private static final Yaml yaml = getYamlMapper();
|
||||
private DaprPlacementContainer placementContainer;
|
||||
private String placementDockerImageName = "daprio/placement";
|
||||
private boolean shouldReusePlacement;
|
||||
|
||||
/**
|
||||
* Creates a new Dapr container.
|
||||
* @param dockerImageName Docker image name.
|
||||
*/
|
||||
public DaprContainer(DockerImageName dockerImageName) {
|
||||
super(dockerImageName);
|
||||
dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME);
|
||||
// For susbcriptions the container needs to access the app channel
|
||||
withAccessToHost(true);
|
||||
// Here we don't want to wait for the Dapr sidecar to be ready, as the sidecar
|
||||
// needs to
|
||||
// connect with the application for susbcriptions
|
||||
|
||||
withExposedPorts(DAPRD_DEFAULT_HTTP_PORT, DAPRD_DEFAULT_GRPC_PORT);
|
||||
|
||||
}
|
||||
|
||||
private static Yaml getYamlMapper() {
|
||||
DumperOptions options = new DumperOptions();
|
||||
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||
options.setPrettyFlow(true);
|
||||
Representer representer = new Representer(options);
|
||||
representer.addClassTag(MetadataEntry.class, Tag.MAP);
|
||||
return new Yaml(representer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Dapr container.
|
||||
* @param image Docker image name.
|
||||
*/
|
||||
public DaprContainer(String image) {
|
||||
this(DockerImageName.parse(image));
|
||||
}
|
||||
|
||||
public Set<Component> getComponents() {
|
||||
return components;
|
||||
}
|
||||
|
||||
public Set<Subscription> getSubscriptions() {
|
||||
return subscriptions;
|
||||
}
|
||||
|
||||
public DaprContainer withAppPort(Integer port) {
|
||||
this.appPort = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DaprContainer withPlacementService(String placementService) {
|
||||
this.placementService = placementService;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DaprContainer withAppName(String appName) {
|
||||
this.appName = appName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DaprContainer withDaprLogLevel(DaprLogLevel daprLogLevel) {
|
||||
this.daprLogLevel = daprLogLevel;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DaprContainer withSubscription(Subscription subscription) {
|
||||
subscriptions.add(subscription);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DaprContainer withComponent(Component component) {
|
||||
components.add(component);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Adds a Dapr component from a YAML file.
|
||||
* @param path Path to the YAML file.
|
||||
* @return This container.
|
||||
*/
|
||||
public DaprContainer withComponent(Path path) {
|
||||
try {
|
||||
Map<String, Object> component = this.yaml.loadAs(Files.newInputStream(path), Map.class);
|
||||
|
||||
String type = (String) component.get("type");
|
||||
Map<String, Object> metadata = (Map<String, Object>) component.get("metadata");
|
||||
String name = (String) metadata.get("name");
|
||||
|
||||
Map<String, Object> spec = (Map<String, Object>) component.get("spec");
|
||||
String version = (String) spec.get("version");
|
||||
List<Map<String, String>> specMetadata =
|
||||
(List<Map<String, String>>) spec.getOrDefault("metadata", Collections.emptyMap());
|
||||
|
||||
ArrayList<MetadataEntry> metadataEntries = new ArrayList<>();
|
||||
|
||||
for (Map<String, String> specMetadataItem : specMetadata) {
|
||||
for (Map.Entry<String, String> metadataItem : specMetadataItem.entrySet()) {
|
||||
metadataEntries.add(new MetadataEntry(metadataItem.getKey(), metadataItem.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
return withComponent(new Component(name, type, version, metadataEntries));
|
||||
} catch (IOException e) {
|
||||
logger().warn("Error while reading component from {}", path.toAbsolutePath());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getHttpPort() {
|
||||
return getMappedPort(DAPRD_DEFAULT_HTTP_PORT);
|
||||
}
|
||||
|
||||
public String getHttpEndpoint() {
|
||||
return "http://" + getHost() + ":" + getMappedPort(DAPRD_DEFAULT_HTTP_PORT);
|
||||
}
|
||||
|
||||
public int getGrpcPort() {
|
||||
return getMappedPort(DAPRD_DEFAULT_GRPC_PORT);
|
||||
}
|
||||
|
||||
public DaprContainer withAppChannelAddress(String appChannelAddress) {
|
||||
this.appChannelAddress = appChannelAddress;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a map of Dapr component details.
|
||||
* @param component A Dapr Component.
|
||||
* @return Map of component details.
|
||||
*/
|
||||
public Map<String, Object> componentToMap(Component component) {
|
||||
Map<String, Object> componentProps = new HashMap<>();
|
||||
componentProps.put("apiVersion", "dapr.io/v1alpha1");
|
||||
componentProps.put("kind", "Component");
|
||||
|
||||
Map<String, String> componentMetadata = new LinkedHashMap<>();
|
||||
componentMetadata.put("name", component.getName());
|
||||
componentProps.put("metadata", componentMetadata);
|
||||
|
||||
Map<String, Object> componentSpec = new HashMap<>();
|
||||
componentSpec.put("type", component.getType());
|
||||
componentSpec.put("version", component.getVersion());
|
||||
|
||||
if (!component.getMetadata().isEmpty()) {
|
||||
componentSpec.put("metadata", component.getMetadata());
|
||||
}
|
||||
componentProps.put("spec", componentSpec);
|
||||
return Collections.unmodifiableMap(componentProps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a map of Dapr subscription details.
|
||||
* @param subscription A Dapr Subscription.
|
||||
* @return Map of subscription details.
|
||||
*/
|
||||
public Map<String, Object> subscriptionToMap(Subscription subscription) {
|
||||
Map<String, Object> subscriptionProps = new HashMap<>();
|
||||
subscriptionProps.put("apiVersion", "dapr.io/v1alpha1");
|
||||
subscriptionProps.put("kind", "Subscription");
|
||||
|
||||
Map<String, String> subscriptionMetadata = new LinkedHashMap<>();
|
||||
subscriptionMetadata.put("name", subscription.getName());
|
||||
subscriptionProps.put("metadata", subscriptionMetadata);
|
||||
|
||||
Map<String, Object> subscriptionSpec = new HashMap<>();
|
||||
subscriptionSpec.put("pubsubname", subscription.getPubsubName());
|
||||
subscriptionSpec.put("topic", subscription.getTopic());
|
||||
subscriptionSpec.put("route", subscription.getRoute());
|
||||
|
||||
subscriptionProps.put("spec", subscriptionSpec);
|
||||
return Collections.unmodifiableMap(subscriptionProps);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
super.configure();
|
||||
|
||||
if (getNetwork() == null) {
|
||||
withNetwork(Network.newNetwork());
|
||||
}
|
||||
if (this.placementContainer == null) {
|
||||
this.placementContainer = new DaprPlacementContainer(this.placementDockerImageName)
|
||||
.withNetwork(getNetwork())
|
||||
.withNetworkAliases(placementService)
|
||||
.withReuse(this.shouldReusePlacement);
|
||||
this.placementContainer.start();
|
||||
}
|
||||
|
||||
List<String> cmds = new ArrayList<>();
|
||||
cmds.add("./daprd");
|
||||
cmds.add("-app-id");
|
||||
cmds.add(appName);
|
||||
cmds.add("--dapr-listen-addresses=0.0.0.0");
|
||||
cmds.add("--app-protocol");
|
||||
cmds.add(protocol.getName());
|
||||
cmds.add("-placement-host-address");
|
||||
cmds.add(placementService + ":50005");
|
||||
|
||||
if (appChannelAddress != null && !appChannelAddress.isEmpty()) {
|
||||
cmds.add("--app-channel-address");
|
||||
cmds.add(appChannelAddress);
|
||||
}
|
||||
if (appPort != null) {
|
||||
cmds.add("--app-port");
|
||||
cmds.add(Integer.toString(appPort));
|
||||
}
|
||||
cmds.add("--log-level");
|
||||
cmds.add(daprLogLevel.toString());
|
||||
cmds.add("-components-path");
|
||||
cmds.add("/dapr-resources");
|
||||
withCommand(cmds.toArray(new String[]{}));
|
||||
|
||||
if (components.isEmpty()) {
|
||||
components.add(new Component("kvstore", "state.in-memory", "v1", Collections.emptyMap()));
|
||||
components.add(new Component("pubsub", "pubsub.in-memory", "v1", Collections.emptyMap()));
|
||||
}
|
||||
|
||||
if (subscriptions.isEmpty() && !components.isEmpty()) {
|
||||
subscriptions.add(new Subscription("local", "pubsub", "topic", "/events"));
|
||||
}
|
||||
|
||||
for (Component component : components) {
|
||||
String componentYaml = componentToYaml(component);
|
||||
withCopyToContainer(Transferable.of(componentYaml), "/dapr-resources/" + component.getName() + ".yaml");
|
||||
}
|
||||
|
||||
for (Subscription subscription : subscriptions) {
|
||||
String subscriptionYaml = subscriptionToYaml(subscription);
|
||||
withCopyToContainer(Transferable.of(subscriptionYaml), "/dapr-resources/" + subscription.getName() + ".yaml");
|
||||
}
|
||||
}
|
||||
|
||||
public String subscriptionToYaml(Subscription subscription) {
|
||||
Map<String, Object> subscriptionMap = subscriptionToMap(subscription);
|
||||
return yaml.dumpAsMap(subscriptionMap);
|
||||
}
|
||||
|
||||
public String componentToYaml(Component component) {
|
||||
Map<String, Object> componentMap = componentToMap(component);
|
||||
return yaml.dumpAsMap(componentMap);
|
||||
}
|
||||
|
||||
public String getAppName() {
|
||||
return appName;
|
||||
}
|
||||
|
||||
public Integer getAppPort() {
|
||||
return appPort;
|
||||
}
|
||||
|
||||
public String getAppChannelAddress() {
|
||||
return appChannelAddress;
|
||||
}
|
||||
|
||||
public String getPlacementService() {
|
||||
return placementService;
|
||||
}
|
||||
|
||||
public static DockerImageName getDefaultImageName() {
|
||||
return DEFAULT_IMAGE_NAME;
|
||||
}
|
||||
|
||||
public DaprContainer withPlacementImage(String placementDockerImageName) {
|
||||
this.placementDockerImageName = placementDockerImageName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DaprContainer withReusablePlacement(boolean reuse) {
|
||||
this.shouldReusePlacement = reuse;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DaprContainer withPlacementContainer(DaprPlacementContainer placementContainer) {
|
||||
this.placementContainer = placementContainer;
|
||||
return this;
|
||||
}
|
||||
|
||||
// Required by spotbugs plugin
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return super.equals(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
public enum DaprLogLevel {
|
||||
ERROR,
|
||||
WARN,
|
||||
INFO,
|
||||
DEBUG
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
/**
|
||||
* Test container for Dapr placement service.
|
||||
*/
|
||||
public class DaprPlacementContainer extends GenericContainer<DaprPlacementContainer> {
|
||||
|
||||
private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("daprio/placement");
|
||||
private int placementPort = 50005;
|
||||
|
||||
/**
|
||||
* Creates a new Dapr placement container.
|
||||
* @param dockerImageName Docker image name.
|
||||
*/
|
||||
public DaprPlacementContainer(DockerImageName dockerImageName) {
|
||||
super(dockerImageName);
|
||||
dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME);
|
||||
|
||||
withExposedPorts(placementPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Dapr placement container.
|
||||
* @param image Docker image name.
|
||||
*/
|
||||
public DaprPlacementContainer(String image) {
|
||||
this(DockerImageName.parse(image));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
super.configure();
|
||||
withCommand("./placement", "-port", Integer.toString(placementPort));
|
||||
}
|
||||
|
||||
public static DockerImageName getDefaultImageName() {
|
||||
return DEFAULT_IMAGE_NAME;
|
||||
}
|
||||
|
||||
public DaprPlacementContainer withPort(Integer port) {
|
||||
this.placementPort = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return placementPort;
|
||||
}
|
||||
|
||||
// Required by spotbugs plugin
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return super.equals(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
public enum DaprProtocol {
|
||||
HTTP("http"),
|
||||
GRPC("grpc");
|
||||
|
||||
private String name;
|
||||
|
||||
DaprProtocol(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
public class MetadataEntry {
|
||||
private String name;
|
||||
private String value;
|
||||
|
||||
public MetadataEntry(String name, String value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
public class Subscription {
|
||||
private String name;
|
||||
private String pubsubName;
|
||||
private String topic;
|
||||
private String route;
|
||||
|
||||
/**
|
||||
* Creates a new subscription.
|
||||
*
|
||||
* @param name Subscription name.
|
||||
* @param pubsubName PubSub name.
|
||||
* @param topic Topic name.
|
||||
* @param route Route.
|
||||
*/
|
||||
public Subscription(String name, String pubsubName, String topic, String route) {
|
||||
this.name = name;
|
||||
this.pubsubName = pubsubName;
|
||||
this.topic = topic;
|
||||
this.route = route;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getPubsubName() {
|
||||
return pubsubName;
|
||||
}
|
||||
|
||||
public String getTopic() {
|
||||
return topic;
|
||||
}
|
||||
|
||||
public String getRoute() {
|
||||
return route;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
public class DaprComponentTest {
|
||||
|
||||
@Test
|
||||
public void componentStateStoreSerializationTest() {
|
||||
DaprContainer dapr = new DaprContainer("daprio/daprd")
|
||||
.withAppName("dapr-app")
|
||||
.withAppPort(8081)
|
||||
.withComponent(new Component(
|
||||
"statestore",
|
||||
"state.in-memory",
|
||||
"v1",
|
||||
Collections.singletonMap("actorStateStore", "true")))
|
||||
.withAppChannelAddress("host.testcontainers.internal");
|
||||
|
||||
Set<Component> components = dapr.getComponents();
|
||||
Assert.assertEquals(1, components.size());
|
||||
|
||||
Component kvstore = components.iterator().next();
|
||||
Assert.assertEquals(false, kvstore.getMetadata().isEmpty());
|
||||
|
||||
String componentYaml = dapr.componentToYaml(kvstore);
|
||||
String expectedComponentYaml = "metadata:\n" + " name: statestore\n"
|
||||
+ "apiVersion: dapr.io/v1alpha1\n"
|
||||
+ "kind: Component\n"
|
||||
+ "spec:\n"
|
||||
+ " metadata:\n"
|
||||
+ " - name: actorStateStore\n"
|
||||
+ " value: 'true'\n"
|
||||
+ " type: state.in-memory\n"
|
||||
+ " version: v1\n";
|
||||
|
||||
Assert.assertEquals(expectedComponentYaml, componentYaml);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containerConfigurationTest() {
|
||||
DaprContainer dapr = new DaprContainer("daprio/daprd")
|
||||
.withAppName("dapr-app")
|
||||
.withAppPort(8081)
|
||||
.withDaprLogLevel(DaprLogLevel.DEBUG)
|
||||
.withAppChannelAddress("host.testcontainers.internal");
|
||||
|
||||
dapr.configure();
|
||||
|
||||
assertThrows(IllegalStateException.class, () -> { dapr.getHttpEndpoint(); });
|
||||
assertThrows(IllegalStateException.class, () -> { dapr.getGrpcPort(); });
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subscriptionSerializationTest() {
|
||||
DaprContainer dapr = new DaprContainer("daprio/daprd")
|
||||
.withAppName("dapr-app")
|
||||
.withAppPort(8081)
|
||||
.withSubscription(new Subscription("my-subscription", "pubsub", "topic", "/events"))
|
||||
.withAppChannelAddress("host.testcontainers.internal");
|
||||
|
||||
Set<Subscription> subscriptions = dapr.getSubscriptions();
|
||||
Assert.assertEquals(1, subscriptions.size());
|
||||
|
||||
String subscriptionYaml = dapr.subscriptionToYaml(subscriptions.iterator().next());
|
||||
String expectedSubscriptionYaml = "metadata:\n" + " name: my-subscription\n"
|
||||
+ "apiVersion: dapr.io/v1alpha1\n"
|
||||
+ "kind: Subscription\n"
|
||||
+ "spec:\n"
|
||||
+ " route: /events\n"
|
||||
+ " pubsubname: pubsub\n"
|
||||
+ " topic: topic\n";
|
||||
Assert.assertEquals(expectedSubscriptionYaml, subscriptionYaml);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withComponentFromPath() {
|
||||
URL stateStoreYaml = this.getClass().getClassLoader().getResource("dapr-resources/statestore.yaml");
|
||||
Path path = Paths.get(stateStoreYaml.getPath());
|
||||
|
||||
DaprContainer dapr = new DaprContainer("daprio/daprd")
|
||||
.withAppName("dapr-app")
|
||||
.withAppPort(8081)
|
||||
.withComponent(path)
|
||||
.withAppChannelAddress("host.testcontainers.internal");
|
||||
|
||||
Set<Component> components = dapr.getComponents();
|
||||
Assert.assertEquals(1, components.size());
|
||||
Component kvstore = components.iterator().next();
|
||||
Assert.assertEquals(false, kvstore.getMetadata().isEmpty());
|
||||
|
||||
String componentYaml = dapr.componentToYaml(kvstore);
|
||||
String expectedComponentYaml = "metadata:\n"
|
||||
+ " name: statestore\n"
|
||||
+ "apiVersion: dapr.io/v1alpha1\n"
|
||||
+ "kind: Component\n"
|
||||
+ "spec:\n"
|
||||
+ " metadata:\n"
|
||||
+ " - name: name\n"
|
||||
+ " value: keyPrefix\n"
|
||||
+ " - name: value\n"
|
||||
+ " value: name\n"
|
||||
+ " - name: name\n"
|
||||
+ " value: redisHost\n"
|
||||
+ " - name: value\n"
|
||||
+ " value: redis:6379\n"
|
||||
+ " - name: name\n"
|
||||
+ " value: redisPassword\n"
|
||||
+ " - name: value\n"
|
||||
+ " value: ''\n"
|
||||
+ " type: null\n"
|
||||
+ " version: v1\n";
|
||||
|
||||
Assert.assertEquals(expectedComponentYaml, componentYaml);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DaprPlacementContainerTest {
|
||||
|
||||
@ClassRule
|
||||
public static DaprPlacementContainer placement = new DaprPlacementContainer("daprio/placement");
|
||||
|
||||
@Test
|
||||
public void testDaprPlacementContainerDefaults() {
|
||||
Assert.assertEquals("The default port is set", 50005, placement.getPort());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
apiVersion: dapr.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: statestore
|
||||
spec:
|
||||
type: state.redis
|
||||
version: v1
|
||||
metadata:
|
||||
- name: keyPrefix
|
||||
value: name
|
||||
- name: redisHost
|
||||
value: redis:6379
|
||||
- name: redisPassword
|
||||
value: ""
|
||||
Loading…
Reference in New Issue