diff --git a/sdk-tests/pom.xml b/sdk-tests/pom.xml index 3cb916ccd..e1175974a 100644 --- a/sdk-tests/pom.xml +++ b/sdk-tests/pom.xml @@ -25,6 +25,8 @@ 3.3.1 1.4.12 3.9.1 + ${dapr.sdk.alpha.version} + 1.20.0 @@ -214,6 +216,17 @@ 4.0.1 compile + + io.dapr + testcontainers-dapr + ${testcontainers-dapr.version} + + + org.testcontainers + junit-jupiter + ${testcontainers-test.version} + test + diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerTest.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerTest.java index 4011152e2..aecad75b2 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerTest.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerTest.java @@ -13,7 +13,7 @@ limitations under the License. package io.dapr.it.testcontainers; -import com.github.tomakehurst.wiremock.junit.WireMockRule; +import com.github.tomakehurst.wiremock.junit5.WireMockTest; import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; import io.dapr.client.domain.Metadata; @@ -23,10 +23,10 @@ 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 org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; import java.io.IOException; import java.util.Map; @@ -43,11 +43,12 @@ 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 org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static java.util.Collections.singletonMap; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +@Testcontainers +@WireMockTest(httpPort = 8081) public class DaprContainerTest { // Time-to-live for messages published. @@ -57,10 +58,7 @@ public class DaprContainerTest { 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 + @Container public static DaprContainer daprContainer = new DaprContainer("daprio/daprd") .withAppName("dapr-app") .withAppPort(8081) @@ -69,16 +67,15 @@ public class DaprContainerTest { /** * Sets the Dapr properties for the test. */ - @BeforeClass + @BeforeAll public static void setDaprProperties() { configStub(); - Testcontainers.exposeHostPorts(8081); + org.testcontainers.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))); @@ -98,19 +95,20 @@ public class DaprContainerTest { @Test public void testDaprContainerDefaults() { assertEquals( - "The pubsub and kvstore component should be configured by default", 2, - daprContainer.getComponents().size()); + daprContainer.getComponents().size(), + "The pubsub and kvstore component should be configured by default" + ); assertEquals( - "A subscription should be configured by default if none is provided", 1, - daprContainer.getSubscriptions().size()); + daprContainer.getSubscriptions().size(), + "A subscription should be configured by default if none is provided"); } @Test public void testStateStore() throws Exception { try (DaprClient client = (new DaprClientBuilder()).build()) { - client.waitForSidecar(5000).block(); + client.waitForSidecar(1000).block(); String value = "value"; // Save state @@ -127,7 +125,7 @@ public class DaprContainerTest { 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(); + client.waitForSidecar(1000).block(); } OkHttpClient client = new OkHttpClient.Builder().build(); @@ -143,13 +141,12 @@ public class DaprContainerTest { throw new IOException("Unexpected response: " + response.code()); } } - } @Test public void testPubSub() throws Exception { try (DaprClient client = (new DaprClientBuilder()).build()) { - client.waitForSidecar(5000).block(); + client.waitForSidecar(1000).block(); String message = "message content"; Map metadata = singletonMap(Metadata.TTL_IN_SECONDS, MESSAGE_TTL_IN_SECONDS); diff --git a/testcontainers-dapr/src/test/java/io/dapr/testcontainers/DaprPlacementContainerTest.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprPlacementContainerTest.java similarity index 57% rename from testcontainers-dapr/src/test/java/io/dapr/testcontainers/DaprPlacementContainerTest.java rename to sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprPlacementContainerTest.java index c62c8c1af..0283c881a 100644 --- a/testcontainers-dapr/src/test/java/io/dapr/testcontainers/DaprPlacementContainerTest.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprPlacementContainerTest.java @@ -11,19 +11,23 @@ limitations under the License. */ -package io.dapr.testcontainers; +package io.dapr.it.testcontainers; -import org.junit.Assert; -import org.junit.ClassRule; -import org.junit.Test; +import io.dapr.testcontainers.DaprPlacementContainer; +import org.junit.jupiter.api.Test; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@Testcontainers public class DaprPlacementContainerTest { - @ClassRule - public static DaprPlacementContainer placement = new DaprPlacementContainer("daprio/placement"); + @Container + private static final DaprPlacementContainer PLACEMENT_CONTAINER = new DaprPlacementContainer("daprio/placement"); @Test public void testDaprPlacementContainerDefaults() { - Assert.assertEquals("The default port is set", 50005, placement.getPort()); + assertEquals(50005, PLACEMENT_CONTAINER.getPort(), "The default port is set"); } } diff --git a/testcontainers-dapr/pom.xml b/testcontainers-dapr/pom.xml index e2f11560a..ca146fc01 100644 --- a/testcontainers-dapr/pom.xml +++ b/testcontainers-dapr/pom.xml @@ -15,6 +15,11 @@ jar + + org.junit.jupiter + junit-jupiter + test + org.yaml snakeyaml 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 e0623d01f..d18e72fb6 100644 --- a/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java +++ b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java @@ -15,6 +15,8 @@ package io.dapr.testcontainers; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.Network; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.containers.wait.strategy.WaitStrategy; import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.DockerImageName; import org.yaml.snakeyaml.DumperOptions; @@ -38,6 +40,10 @@ public class DaprContainer extends GenericContainer { 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") + .forPort(DAPRD_DEFAULT_HTTP_PORT) + .forStatusCodeMatching(statusCode -> statusCode >= 200 && statusCode <= 399); + private final Set components = new HashSet<>(); private final Set subscriptions = new HashSet<>(); private DaprProtocol protocol = DaprProtocol.HTTP; @@ -59,23 +65,9 @@ public class DaprContainer extends GenericContainer { 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); + setWaitStrategy(WAIT_STRATEGY); } /** @@ -124,8 +116,6 @@ public class DaprContainer extends GenericContainer { return this; } - - /** * Adds a Dapr component from a YAML file. * @param path Path to the YAML file. @@ -197,6 +187,7 @@ public class DaprContainer extends GenericContainer { if (!component.getMetadata().isEmpty()) { componentSpec.put("metadata", component.getMetadata()); } + componentProps.put("spec", componentSpec); return Collections.unmodifiableMap(componentProps); } @@ -231,6 +222,7 @@ public class DaprContainer extends GenericContainer { if (getNetwork() == null) { withNetwork(Network.newNetwork()); } + if (this.placementContainer == null) { this.placementContainer = new DaprPlacementContainer(this.placementDockerImageName) .withNetwork(getNetwork()) @@ -253,10 +245,12 @@ public class DaprContainer extends GenericContainer { 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"); @@ -338,4 +332,13 @@ public class DaprContainer extends GenericContainer { public int hashCode() { return super.hashCode(); } + + 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); + } } diff --git a/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprProtocol.java b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprProtocol.java index 1d5185dd3..8cf6e696a 100644 --- a/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprProtocol.java +++ b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprProtocol.java @@ -17,7 +17,7 @@ public enum DaprProtocol { HTTP("http"), GRPC("grpc"); - private String name; + private final String name; DaprProtocol(String name) { this.name = name; diff --git a/testcontainers-dapr/src/main/java/io/dapr/testcontainers/Subscription.java b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/Subscription.java index faa1b6916..278f9aa5b 100644 --- a/testcontainers-dapr/src/main/java/io/dapr/testcontainers/Subscription.java +++ b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/Subscription.java @@ -14,10 +14,10 @@ limitations under the License. package io.dapr.testcontainers; public class Subscription { - private String name; - private String pubsubName; - private String topic; - private String route; + private final String name; + private final String pubsubName; + private final String topic; + private final String route; /** * Creates a new subscription. 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 eb3067e3f..2a5db5967 100644 --- a/testcontainers-dapr/src/test/java/io/dapr/testcontainers/DaprComponentTest.java +++ b/testcontainers-dapr/src/test/java/io/dapr/testcontainers/DaprComponentTest.java @@ -13,8 +13,7 @@ limitations under the License. package io.dapr.testcontainers; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.net.URL; import java.nio.file.Path; @@ -22,7 +21,9 @@ import java.nio.file.Paths; import java.util.Collections; import java.util.Set; -import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; public class DaprComponentTest { @@ -39,10 +40,10 @@ public class DaprComponentTest { .withAppChannelAddress("host.testcontainers.internal"); Set components = dapr.getComponents(); - Assert.assertEquals(1, components.size()); + assertEquals(1, components.size()); Component kvstore = components.iterator().next(); - Assert.assertEquals(false, kvstore.getMetadata().isEmpty()); + assertFalse(kvstore.getMetadata().isEmpty()); String componentYaml = dapr.componentToYaml(kvstore); String expectedComponentYaml = "metadata:\n" + " name: statestore\n" @@ -55,25 +56,21 @@ public class DaprComponentTest { + " type: state.in-memory\n" + " version: v1\n"; - Assert.assertEquals(expectedComponentYaml, componentYaml); + 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"); + .withAppName("dapr-app") + .withAppPort(8081) + .withDaprLogLevel(DaprLogLevel.DEBUG) + .withAppChannelAddress("host.testcontainers.internal"); dapr.configure(); - assertThrows(IllegalStateException.class, () -> { dapr.getHttpEndpoint(); }); - assertThrows(IllegalStateException.class, () -> { dapr.getGrpcPort(); }); - - - - + assertThrows(IllegalStateException.class, dapr::getHttpEndpoint); + assertThrows(IllegalStateException.class, dapr::getGrpcPort); } @Test @@ -85,7 +82,7 @@ public class DaprComponentTest { .withAppChannelAddress("host.testcontainers.internal"); Set subscriptions = dapr.getSubscriptions(); - Assert.assertEquals(1, subscriptions.size()); + assertEquals(1, subscriptions.size()); String subscriptionYaml = dapr.subscriptionToYaml(subscriptions.iterator().next()); String expectedSubscriptionYaml = "metadata:\n" + " name: my-subscription\n" @@ -95,7 +92,7 @@ public class DaprComponentTest { + " route: /events\n" + " pubsubname: pubsub\n" + " topic: topic\n"; - Assert.assertEquals(expectedSubscriptionYaml, subscriptionYaml); + assertEquals(expectedSubscriptionYaml, subscriptionYaml); } @Test @@ -110,9 +107,9 @@ public class DaprComponentTest { .withAppChannelAddress("host.testcontainers.internal"); Set components = dapr.getComponents(); - Assert.assertEquals(1, components.size()); + assertEquals(1, components.size()); Component kvstore = components.iterator().next(); - Assert.assertEquals(false, kvstore.getMetadata().isEmpty()); + assertFalse(kvstore.getMetadata().isEmpty()); String componentYaml = dapr.componentToYaml(kvstore); String expectedComponentYaml = "metadata:\n" @@ -136,6 +133,6 @@ public class DaprComponentTest { + " type: null\n" + " version: v1\n"; - Assert.assertEquals(expectedComponentYaml, componentYaml); + assertEquals(expectedComponentYaml, componentYaml); } }