Skip to content

Commit

Permalink
Initial Testcontainers integration for Dapr (#1085)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
salaboy and artursouza authored Aug 5, 2024
1 parent 5618af5 commit e30dc2d
Show file tree
Hide file tree
Showing 24 changed files with 1,148 additions and 21 deletions.
19 changes: 14 additions & 5 deletions .github/scripts/update_sdk_version.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down
2 changes: 1 addition & 1 deletion examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 -->
Expand Down Expand Up @@ -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 -->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
version: '3'
services:
zookeeper:
image: confluentinc/cp-zookeeper:7.4.4
Expand Down
4 changes: 2 additions & 2 deletions examples/src/main/java/io/dapr/examples/querystate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 -->
Expand Down Expand Up @@ -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 -->
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
version: '3'
services:
mongo:
image: mongo
Expand Down
4 changes: 2 additions & 2 deletions examples/src/main/java/io/dapr/examples/state/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 -->
Expand Down Expand Up @@ -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 -->
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
version: '3'
services:
mongo:
image: mongo
Expand Down
6 changes: 5 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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>
Expand Down Expand Up @@ -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>
Expand Down
21 changes: 21 additions & 0 deletions sdk-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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>
Expand All @@ -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>
Expand Down
Original file line number Diff line number Diff line change
@@ -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")));
}
}
Loading

0 comments on commit e30dc2d

Please sign in to comment.