daprd resolves its placement service by DNS name ({@code placement:50005}), so
+ * there must be exactly ONE container answering to the {@code "placement"} alias on the
+ * shared network. If several exist (which happens when each {@code DaprContainer}
+ * auto-creates its own, never-stopped placement), Docker DNS round-robins daprd to an
+ * arbitrary one -- often an empty placement that never received this test's actor-host
+ * registrations -- producing "did not find address for actor" in multi-sidecar failover
+ * and losing the actor host across a sidecar restart. Sharing this singleton (wired via
+ * {@code DaprContainer.withPlacementContainer}) guarantees a single DNS answer.
+ */
+ public static synchronized DaprPlacementContainer placement() {
+ if (placement == null) {
+ placement = new DaprPlacementContainer(DaprContainerConstants.DAPR_PLACEMENT_IMAGE_TAG)
+ .withNetwork(network())
+ .withNetworkAliases(PLACEMENT_NETWORK_ALIAS)
+ .withReuse(true);
+ placement.start();
+ }
+ return placement;
+ }
+
+ /**
+ * The single Dapr scheduler service shared by every daprd in the JVM. Owns actor
+ * reminders in Dapr 1.18+, so it must stay up across a daprd restart for reminder
+ * recovery to work. Same single-DNS-answer requirement as {@link #placement()}.
+ */
+ public static synchronized DaprSchedulerContainer scheduler() {
+ if (scheduler == null) {
+ scheduler = new DaprSchedulerContainer(DaprContainerConstants.DAPR_SCHEDULER_IMAGE_TAG)
+ .withNetwork(network())
+ .withNetworkAliases(SCHEDULER_NETWORK_ALIAS)
+ .withReuse(true);
+ scheduler.start();
+ }
+ return scheduler;
+ }
}
diff --git a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/grpc/MethodInvokeService.java b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/grpc/MethodInvokeService.java
index ac7b157af6..90d3739c82 100644
--- a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/grpc/MethodInvokeService.java
+++ b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/grpc/MethodInvokeService.java
@@ -14,7 +14,6 @@
package io.dapr.it.methodinvoke.grpc;
import io.dapr.grpc.GrpcHealthCheckService;
-import io.dapr.it.DaprRunConfig;
import io.dapr.it.MethodInvokeServiceGrpc;
import io.grpc.Server;
import io.grpc.ServerBuilder;
@@ -28,9 +27,6 @@
import static io.dapr.it.MethodInvokeServiceProtos.SleepRequest;
import static io.dapr.it.MethodInvokeServiceProtos.SleepResponse;
-@DaprRunConfig(
- enableAppHealthCheck = true
-)
public class MethodInvokeService {
private static final long STARTUP_DELAY_SECONDS = 10;
diff --git a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeService.java b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeService.java
index 8b4858fc21..5d0e1cbbca 100644
--- a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeService.java
+++ b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeService.java
@@ -13,7 +13,6 @@
package io.dapr.it.methodinvoke.http;
-import io.dapr.it.DaprRunConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -21,9 +20,6 @@
/**
* Service for subscriber.
*/
-@DaprRunConfig(
- enableAppHealthCheck = true
-)
@SpringBootApplication
public class MethodInvokeService {
diff --git a/sdk-tests/src/test/java/io/dapr/it/resiliency/WaitForSidecarIT.java b/sdk-tests/src/test/java/io/dapr/it/resiliency/WaitForSidecarIT.java
index c7dd5ccc56..00c6bfc64e 100644
--- a/sdk-tests/src/test/java/io/dapr/it/resiliency/WaitForSidecarIT.java
+++ b/sdk-tests/src/test/java/io/dapr/it/resiliency/WaitForSidecarIT.java
@@ -8,65 +8,91 @@
* 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.
+ * limitations under the License.
*/
package io.dapr.it.resiliency;
-import io.dapr.it.BaseIT;
-import io.dapr.it.DaprRun;
-import io.dapr.it.ToxiProxyRun;
+import eu.rekawek.toxiproxy.Proxy;
+import eu.rekawek.toxiproxy.ToxiproxyClient;
+import eu.rekawek.toxiproxy.model.ToxicDirection;
+import eu.rekawek.toxiproxy.model.toxic.Latency;
+import io.dapr.client.DaprClient;
+import io.dapr.client.DaprClientBuilder;
+import io.dapr.config.Properties;
+import io.dapr.it.containers.BaseContainerIT;
+import io.dapr.testcontainers.DaprContainer;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import org.testcontainers.toxiproxy.ToxiproxyContainer;
+import java.io.IOException;
import java.time.Duration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
- * Test SDK resiliency.
+ * Test SDK resiliency around {@code waitForSidecar}.
*/
-public class WaitForSidecarIT extends BaseIT {
+public class WaitForSidecarIT extends BaseContainerIT {
// Use a number large enough to make sure it will respect the entire timeout.
private static final Duration LATENCY = Duration.ofSeconds(5);
- private static final Duration JITTER = Duration.ofSeconds(0);
+ private static DaprContainer dapr;
- private static DaprRun daprRun;
+ private static ToxiproxyContainer toxiproxy;
- private static ToxiProxyRun toxiProxyRun;
+ private static Proxy proxy;
- private static DaprRun daprNotRunning;
+ private static DaprContainer daprNotRunning;
+
+ private static int daprNotRunningHttpPort;
@BeforeAll
- public static void init() throws Exception {
- daprRun = startDaprApp(WaitForSidecarIT.class.getSimpleName(), 5000);
- daprNotRunning = startDaprApp(WaitForSidecarIT.class.getSimpleName() + "NotRunning", 5000);
+ public static void init() throws IOException {
+ dapr = daprBuilder("wait-for-sidecar-it")
+ .withNetworkAliases("dapr");
+ dapr.start();
+ deferStop(dapr);
+
+ toxiproxy = newToxiproxy();
+ ToxiproxyClient toxiproxyClient = new ToxiproxyClient(toxiproxy.getHost(), toxiproxy.getControlPort());
+ proxy = toxiproxyClient.createProxy("dapr", "0.0.0.0:8666", "dapr:3500");
+
+ // A second sidecar that is started and then stopped, so a client pointed at its
+ // (now-dead) mapped port cannot possibly get a response. Deterministic stand-in
+ // for a "Dapr is not running" target.
+ daprNotRunning = daprBuilder("wait-for-sidecar-it-not-running")
+ .withNetworkAliases("dapr-not-running");
+ daprNotRunning.start();
+ daprNotRunningHttpPort = daprNotRunning.getHttpPort();
daprNotRunning.stop();
-
- toxiProxyRun = new ToxiProxyRun(daprRun, LATENCY, JITTER);
- toxiProxyRun.start();
}
@Test
public void waitSucceeds() throws Exception {
- try(var client = daprRun.newDaprClient()) {
+ try (DaprClient client = newDaprClient(dapr)) {
client.waitForSidecar(5000).block();
}
}
@Test
- public void waitTimeout() {
- int timeoutInMillis = (int)LATENCY.minusMillis(100).toMillis();
+ public void waitTimeout() throws IOException {
+ int timeoutInMillis = (int) LATENCY.minusMillis(100).toMillis();
long started = System.currentTimeMillis();
- assertThrows(RuntimeException.class, () -> {
- try(var client = toxiProxyRun.newDaprClientBuilder().build()) {
- client.waitForSidecar(timeoutInMillis).block();
- }
- });
+ Latency latency = proxy.toxics().latency("latency", ToxicDirection.DOWNSTREAM, LATENCY.toMillis());
+ try {
+ assertThrows(RuntimeException.class, () -> {
+ try (DaprClient client = viaProxyClientBuilder().build()) {
+ client.waitForSidecar(timeoutInMillis).block();
+ }
+ });
+ } finally {
+ latency.remove();
+ }
long duration = System.currentTimeMillis() - started;
@@ -75,11 +101,16 @@ public void waitTimeout() {
@Test
public void waitSlow() throws Exception {
- int timeoutInMillis = (int)LATENCY.plusMillis(100).toMillis();
+ int timeoutInMillis = (int) LATENCY.plusMillis(100).toMillis();
long started = System.currentTimeMillis();
- try(var client = toxiProxyRun.newDaprClientBuilder().build()) {
+ Latency latency = proxy.toxics().latency("latency", ToxicDirection.DOWNSTREAM, LATENCY.toMillis());
+ try {
+ try (DaprClient client = viaProxyClientBuilder().build()) {
client.waitForSidecar(timeoutInMillis).block();
+ }
+ } finally {
+ latency.remove();
}
long duration = System.currentTimeMillis() - started;
@@ -95,7 +126,7 @@ public void waitNotRunningTimeout() {
long started = System.currentTimeMillis();
assertThrows(RuntimeException.class, () -> {
- try(var client = daprNotRunning.newDaprClientBuilder().build()) {
+ try (DaprClient client = notRunningClientBuilder().build()) {
client.waitForSidecar(timeoutMilliseconds).block();
}
});
@@ -104,4 +135,16 @@ public void waitNotRunningTimeout() {
assertThat(duration).isGreaterThanOrEqualTo(timeoutMilliseconds);
}
+
+ private static DaprClientBuilder viaProxyClientBuilder() {
+ return new DaprClientBuilder()
+ .withPropertyOverride(Properties.HTTP_ENDPOINT, "http://localhost:" + toxiproxy.getMappedPort(8666))
+ .withPropertyOverride(Properties.GRPC_ENDPOINT, "http://localhost:" + toxiproxy.getMappedPort(8666));
+ }
+
+ private static DaprClientBuilder notRunningClientBuilder() {
+ return new DaprClientBuilder()
+ .withPropertyOverride(Properties.HTTP_ENDPOINT, "http://localhost:" + daprNotRunningHttpPort)
+ .withPropertyOverride(Properties.GRPC_ENDPOINT, "http://localhost:" + daprNotRunningHttpPort);
+ }
}
diff --git a/sdk-tests/src/test/java/io/dapr/it/tracing/grpc/Service.java b/sdk-tests/src/test/java/io/dapr/it/tracing/grpc/Service.java
index 1aa660d880..fc2e59e050 100644
--- a/sdk-tests/src/test/java/io/dapr/it/tracing/grpc/Service.java
+++ b/sdk-tests/src/test/java/io/dapr/it/tracing/grpc/Service.java
@@ -15,7 +15,6 @@
import com.google.protobuf.Any;
import io.dapr.grpc.GrpcHealthCheckService;
-import io.dapr.it.DaprRunConfig;
import io.dapr.v1.AppCallbackGrpc;
import io.dapr.v1.CommonProtos;
import io.grpc.Server;
@@ -27,9 +26,6 @@
import static io.dapr.it.MethodInvokeServiceProtos.SleepRequest;
import static io.dapr.it.MethodInvokeServiceProtos.SleepResponse;
-@DaprRunConfig(
- enableAppHealthCheck = true
-)
public class Service {
public static final String SUCCESS_MESSAGE = "application discovered on port ";
diff --git a/sdk-tests/src/test/java/io/dapr/it/tracing/http/OpenTelemetryConfig.java b/sdk-tests/src/test/java/io/dapr/it/tracing/http/OpenTelemetryConfig.java
index c66e795887..5c0447ab2a 100644
--- a/sdk-tests/src/test/java/io/dapr/it/tracing/http/OpenTelemetryConfig.java
+++ b/sdk-tests/src/test/java/io/dapr/it/tracing/http/OpenTelemetryConfig.java
@@ -27,8 +27,16 @@ public class OpenTelemetryConfig {
public static final String SERVICE_NAME = "integration testing service over http";
@Bean
- public OpenTelemetry initOpenTelemetry() throws InterruptedException {
- return io.dapr.it.tracing.OpenTelemetry.createOpenTelemetry(SERVICE_NAME);
+ public OpenTelemetry initOpenTelemetry() {
+ // Use the explicit-endpoint overload so this bean does NOT block on a Zipkin readiness
+ // probe during app startup. This app runs as a host subprocess and only needs a propagator
+ // for context extraction; it exports no spans that the test asserts on (the validated
+ // "calllocal/