From fe4ec6cef5f1a2d6cec269c5652804af1550d6f4 Mon Sep 17 00:00:00 2001 From: slinkydeveloper Date: Fri, 1 Nov 2024 18:32:37 +0100 Subject: [PATCH] Add multi node setup test suites. This adds two new test suites, `threeNodes` and `threeNodesAlwaysSuspending`. The StopRuntime, KillRuntime and NonDeterminismErrors tests are disabled for now. --- README.md | 6 + .../sdktesting/infra/ContainerLogger.kt | 31 ++-- .../sdktesting/infra/RestateContainer.kt | 164 +++++++++++++----- .../sdktesting/infra/RestateDeployer.kt | 87 ++++++++-- .../sdktesting/infra/RestateDeployerConfig.kt | 6 +- .../restate/sdktesting/infra/annotations.kt | 1 + .../dev/restate/sdktesting/junit/TestSuite.kt | 12 +- .../restate/sdktesting/junit/TestSuites.kt | 26 ++- .../kotlin/dev/restate/sdktesting/main.kt | 7 +- .../restate/sdktesting/tests/KillRuntime.kt | 1 + .../sdktesting/tests/NonDeterminismErrors.kt | 1 + .../sdktesting/tests/SleepWithFailures.kt | 5 +- .../restate/sdktesting/tests/StopRuntime.kt | 1 + src/main/resources/junit-platform.properties | 2 +- 14 files changed, 250 insertions(+), 100 deletions(-) diff --git a/README.md b/README.md index db387c3..d64a31d 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,12 @@ java -jar restate-sdk-test-suite.jar debug \ Please note, some tests requiring to kill/stop the service deployment won't work with the `debug` command. +## Building this tool + +```shell +./gradlew shadowJar +``` + ## Releasing this tool Just push a new git tag: diff --git a/src/main/kotlin/dev/restate/sdktesting/infra/ContainerLogger.kt b/src/main/kotlin/dev/restate/sdktesting/infra/ContainerLogger.kt index 14a3031..e949c2a 100644 --- a/src/main/kotlin/dev/restate/sdktesting/infra/ContainerLogger.kt +++ b/src/main/kotlin/dev/restate/sdktesting/infra/ContainerLogger.kt @@ -22,47 +22,36 @@ internal class ContainerLogger( ) : Consumer { private var startCount = 0 - private var stdoutStream: BufferedWriter? = null - private var stderrStream: BufferedWriter? = null + private var logStream: BufferedWriter? = null override fun accept(frame: OutputFrame) { when (frame.type) { OutputFrame.OutputType.STDOUT -> { - resolveStdoutStream().write(frame.utf8String) + resolveStream().write(frame.utf8String) } OutputFrame.OutputType.STDERR -> { - resolveStderrStream().write(frame.utf8String) + resolveStream().write(frame.utf8String) } else -> { - stdoutStream?.close() - stderrStream?.close() - stdoutStream = null - stderrStream = null + logStream?.close() + logStream = null startCount++ } } } - private fun resolveStdoutStream(): BufferedWriter { - if (stdoutStream == null) { - stdoutStream = newStream(testReportDirectory, loggerName, "stdout") + private fun resolveStream(): BufferedWriter { + if (logStream == null) { + logStream = newStream(testReportDirectory, loggerName) } - return stdoutStream!! - } - - private fun resolveStderrStream(): BufferedWriter { - if (stderrStream == null) { - stderrStream = newStream(testReportDirectory, loggerName, "stderr") - } - return stderrStream!! + return logStream!! } private fun newStream( testReportDirectory: String, loggerName: String, - type: String ): BufferedWriter { - val path = Path.of(testReportDirectory, "${loggerName}_${startCount}_${type}.log") + val path = Path.of(testReportDirectory, "${loggerName}_${startCount}.log") val fileExists = Files.exists(path) val writer = diff --git a/src/main/kotlin/dev/restate/sdktesting/infra/RestateContainer.kt b/src/main/kotlin/dev/restate/sdktesting/infra/RestateContainer.kt index d34bd27..079fbf5 100644 --- a/src/main/kotlin/dev/restate/sdktesting/infra/RestateContainer.kt +++ b/src/main/kotlin/dev/restate/sdktesting/infra/RestateContainer.kt @@ -13,9 +13,12 @@ import com.fasterxml.jackson.dataformat.toml.TomlFactory import com.github.dockerjava.api.command.InspectContainerResponse import dev.restate.sdktesting.infra.runtimeconfig.RestateConfigSchema import java.io.File +import java.util.UUID import java.util.concurrent.TimeUnit import kotlin.time.Duration.Companion.seconds import kotlin.time.toJavaDuration +import kotlin.use +import org.apache.logging.log4j.CloseableThreadContext import org.apache.logging.log4j.LogManager import org.rnorth.ducttape.ratelimits.RateLimiterBuilder import org.testcontainers.containers.BindMode @@ -29,10 +32,12 @@ import org.testcontainers.utility.DockerImageName class RestateContainer( config: RestateDeployerConfig, + val hostname: String, network: Network, envs: Map, configSchema: RestateConfigSchema?, - copyToContainer: List> + copyToContainer: List>, + enableLocalPortForward: Boolean = true, ) : GenericContainer(DockerImageName.parse(config.restateContainerImage)) { companion object { private val LOG = LogManager.getLogger(RestateContainer::class.java) @@ -45,71 +50,137 @@ class RestateContainer( .forPort(RUNTIME_INGRESS_ENDPOINT_PORT) .withRateLimiter( RateLimiterBuilder.newBuilder() - .withRate(100, TimeUnit.MILLISECONDS) + .withRate(200, TimeUnit.MILLISECONDS) .withConstantThroughput() - .build()) - .withStartupTimeout(20.seconds.toJavaDuration())) + .build())) .withStrategy( Wait.forHttp("/health") .forPort(RUNTIME_ADMIN_ENDPOINT_PORT) .withRateLimiter( RateLimiterBuilder.newBuilder() - .withRate(100, TimeUnit.MILLISECONDS) + .withRate(200, TimeUnit.MILLISECONDS) .withConstantThroughput() - .build()) - .withStartupTimeout(20.seconds.toJavaDuration())) + .build())) + .withStartupTimeout(120.seconds.toJavaDuration()) + + fun bootstrapRestateCluster( + config: RestateDeployerConfig, + network: Network, + envs: Map, + configSchema: RestateConfigSchema?, + copyToContainer: List>, + nodes: Int + ): List { + if (nodes == 1) { + return listOf( + RestateContainer(config, RESTATE_RUNTIME, network, envs, configSchema, copyToContainer)) + } else { + val clusterId = UUID.randomUUID().toString() + val leaderEnvs = + mapOf( + "RESTATE_CLUSTER_NAME" to clusterId, + "RESTATE_BIFROST__DEFAULT_PROVIDER" to "replicated", + "RESTATE_ALLOW_BOOTSTRAP" to "true", + "RESTATE_ROLES" to "[worker,log-server,admin,metadata-store]", + ) + val followerEnvs = + mapOf( + "RESTATE_CLUSTER_NAME" to clusterId, + "RESTATE_BIFROST__DEFAULT_PROVIDER" to "replicated", + "RESTATE_ROLES" to "[worker,admin,log-server]", + "RESTATE_METADATA_STORE_CLIENT__ADDRESS" to "http://$RESTATE_RUNTIME:5123") + + return listOf( + RestateContainer( + config, + // Leader will just have the default hostname as usual, this makes sure containers + // port injection annotations still work. + RESTATE_RUNTIME, + network, + envs + + leaderEnvs + + mapOf( + "RESTATE_ADVERTISED_ADDRESS" to + "http://$RESTATE_RUNTIME:$RUNTIME_NODE_PORT"), + configSchema, + copyToContainer)) + + (1.rangeUntil(config.restateNodes)).map { + RestateContainer( + config, + "$RESTATE_RUNTIME-$it", + network, + envs + + followerEnvs + + mapOf( + "RESTATE_ADVERTISED_ADDRESS" to + "http://$RESTATE_RUNTIME-$it:$RUNTIME_NODE_PORT"), + configSchema, + copyToContainer, + // Only the leader gets the privilege of local port forwarding + enableLocalPortForward = false) + } + } + } } init { - LOG.debug("Using runtime image '{}'", config.restateContainerImage) + CloseableThreadContext.put("containerHostname", hostname).use { + withImagePullPolicy(config.imagePullPolicy.toTestContainersImagePullPolicy()) - withImagePullPolicy(config.imagePullPolicy.toTestContainersImagePullPolicy()) + withEnv(envs) + // These envs should not be overriden by envs + withEnv("RESTATE_ADMIN__BIND_ADDRESS", "0.0.0.0:$RUNTIME_ADMIN_ENDPOINT_PORT") + withEnv("RESTATE_INGRESS__BIND_ADDRESS", "0.0.0.0:$RUNTIME_INGRESS_ENDPOINT_PORT") - withEnv(envs) - // These envs should not be overriden by envs - withEnv("RESTATE_ADMIN__BIND_ADDRESS", "0.0.0.0:$RUNTIME_ADMIN_ENDPOINT_PORT") - withEnv("RESTATE_INGRESS__BIND_ADDRESS", "0.0.0.0:$RUNTIME_INGRESS_ENDPOINT_PORT") + this.network = network + this.networkAliases = arrayListOf(hostname) + withCreateContainerCmdModifier { it.withHostName(hostname) } - this.network = network - this.networkAliases = arrayListOf(RESTATE_RUNTIME) - withStartupAttempts(3) // For podman - waitingFor(WAIT_STARTUP_STRATEGY) + withStartupAttempts(3) // For podman + waitingFor(WAIT_STARTUP_STRATEGY) - if (config.stateDirectoryMount != null) { - val stateDir = File(config.stateDirectoryMount) - stateDir.mkdirs() + if (config.stateDirectoryMount != null) { + val stateDir = File(config.stateDirectoryMount) + stateDir.mkdirs() - LOG.debug("Mounting state directory to '{}'", stateDir.toPath()) - addFileSystemBind(stateDir.toString(), "/state", BindMode.READ_WRITE, SelinuxContext.SINGLE) - } - withEnv("RESTATE_BASE_DIR", "/state") + LOG.debug("Mounting state directory to '{}'", stateDir.toPath()) + addFileSystemBind(stateDir.toString(), "/state", BindMode.READ_WRITE, SelinuxContext.SINGLE) + } + withEnv("RESTATE_BASE_DIR", "/state") - if (configSchema != null) { - withCopyToContainer( - Transferable.of(TOML_MAPPER.writeValueAsBytes(configSchema)), "/config.toml") - withEnv("RESTATE_CONFIG", "/config.toml") - } + if (configSchema != null) { + withCopyToContainer( + Transferable.of(TOML_MAPPER.writeValueAsBytes(configSchema)), "/config.toml") + withEnv("RESTATE_CONFIG", "/config.toml") + } - for (file in copyToContainer) { - withCopyToContainer(file.second, file.first) - } + for (file in copyToContainer) { + withCopyToContainer(file.second, file.first) + } - if (config.localAdminPort != null) { - LOG.info("Going to expose Admin port on localhost:{}", config.localAdminPort) - super.addFixedExposedPort(config.localAdminPort, RUNTIME_ADMIN_ENDPOINT_PORT) - } else { - addExposedPort(RUNTIME_ADMIN_ENDPOINT_PORT) - } - if (config.localIngressPort != null) { - LOG.info("Going to expose Admin port on localhost:{}", config.localIngressPort) - super.addFixedExposedPort(config.localIngressPort, RUNTIME_INGRESS_ENDPOINT_PORT) - } else { - addExposedPort(RUNTIME_INGRESS_ENDPOINT_PORT) + if (enableLocalPortForward && config.localAdminPort != null) { + LOG.info("Going to expose Admin port on 'localhost:{}'", config.localAdminPort) + super.addFixedExposedPort(config.localAdminPort, RUNTIME_ADMIN_ENDPOINT_PORT) + } else { + addExposedPort(RUNTIME_ADMIN_ENDPOINT_PORT) + } + if (enableLocalPortForward && config.localIngressPort != null) { + LOG.info("Going to expose Admin port on 'localhost:{}'", config.localIngressPort) + super.addFixedExposedPort(config.localIngressPort, RUNTIME_INGRESS_ENDPOINT_PORT) + } else { + addExposedPort(RUNTIME_INGRESS_ENDPOINT_PORT) + } + if (enableLocalPortForward && config.localNodePort != null) { + LOG.info("Going to expose node port on 'localhost:{}'", config.localNodePort) + super.addFixedExposedPort(config.localNodePort, RUNTIME_NODE_PORT) + } else { + addExposedPort(RUNTIME_NODE_PORT) + } } } fun configureLogger(testReportDir: String): RestateContainer { - this.withLogConsumer(ContainerLogger(testReportDir, "restate-runtime")) + this.withLogConsumer(ContainerLogger(testReportDir, hostname)) return this } @@ -117,6 +188,11 @@ class RestateContainer( WAIT_STARTUP_STRATEGY.waitUntilReady(this) } + fun dumpConfiguration() { + check(isRunning) { "The container is not running, can't dump configuration" } + dockerClient.killContainerCmd(containerId).withSignal("SIGUSR1").exec() + } + override fun getContainerInfo(): InspectContainerResponse { // We override container info to avoid getting outdated info when restarted val containerId = this.containerId diff --git a/src/main/kotlin/dev/restate/sdktesting/infra/RestateDeployer.kt b/src/main/kotlin/dev/restate/sdktesting/infra/RestateDeployer.kt index ca84473..62f056a 100644 --- a/src/main/kotlin/dev/restate/sdktesting/infra/RestateDeployer.kt +++ b/src/main/kotlin/dev/restate/sdktesting/infra/RestateDeployer.kt @@ -20,8 +20,12 @@ import java.net.URI import java.net.http.HttpClient import java.nio.file.Path import java.util.* +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Executors import java.util.concurrent.TimeUnit +import org.apache.logging.log4j.CloseableThreadContext import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.ThreadContext import org.junit.jupiter.api.extension.ExtensionContext import org.rnorth.ducttape.unreliables.Unreliables import org.testcontainers.containers.* @@ -153,15 +157,17 @@ private constructor( } } .associate { it.second.first to (it.first to it.second.second) } - private val runtimeContainer = - RestateContainer(config, network, runtimeContainerEnvs, configSchema, copyToContainer) + private val runtimeContainers: List = + RestateContainer.bootstrapRestateCluster( + config, network, runtimeContainerEnvs, configSchema, copyToContainer, config.restateNodes) + private val deployedContainers: Map = - mapOf( - RESTATE_RUNTIME to - ContainerHandle( - runtimeContainer, restartWaitStrategy = { runtimeContainer.waitStartup() })) + - serviceContainers.map { it.key to ContainerHandle(it.value.second) } + - additionalContainers.map { it.key to ContainerHandle(it.value) } + (runtimeContainers.map { + it.hostname to ContainerHandle(it, restartWaitStrategy = { it.waitStartup() }) + } + + serviceContainers.map { it.key to ContainerHandle(it.value.second) } + + additionalContainers.map { it.key to ContainerHandle(it.value) }) + .associate { it } init { // Configure additional containers to be deployed within the same network where we deploy @@ -210,7 +216,7 @@ private constructor( additionalContainers.forEach { (hostname, container) -> container.withLogConsumer(ContainerLogger(testReportDir, hostname)) } - runtimeContainer.configureLogger(testReportDir) + runtimeContainers.map { it.configureLogger(testReportDir) } } private fun deployServices() { @@ -231,11 +237,43 @@ private constructor( } private fun deployRuntime() { - runtimeContainer - .dependsOn(serviceContainers.values.map { it.second }) - .dependsOn(additionalContainers.values) - .start() - LOG.debug("Restate runtime started. Container id {}", runtimeContainer.containerId) + val ctx = ThreadContext.getContext() + val executor = + Executors.newFixedThreadPool(runtimeContainers.size) { runnable -> + Executors.defaultThreadFactory().newThread { + // Make sure we inject the thread context + ThreadContext.putAll(ctx) + runnable.run() + } + } + + val containerDependencies = + serviceContainers.values.map { it.second } + additionalContainers.values + + CompletableFuture.allOf( + *runtimeContainers + .map { container -> + CompletableFuture.runAsync( + { + CloseableThreadContext.put("containerHostname", container.hostname).use { + if (container.hostname != RESTATE_RUNTIME) { + Thread.sleep(5000) + // Sleep first because of an internal init issue of the runtime + } + LOG.debug( + "Restate container '${container.hostname}' using image '${config.restateContainerImage}' is starting") + container.dependsOn(containerDependencies).start() + container.dumpConfiguration() + LOG.debug( + "Restate container '${container.hostname}' id '${container.containerId}' started and is healthy") + } + }, + executor) + } + .toTypedArray()) + .get(150, TimeUnit.SECONDS) + + executor.shutdown() } private fun discoverDeployment(client: DeploymentApi, spec: ServiceSpec) { @@ -298,11 +336,22 @@ private constructor( // to let flush the logs and spans exported as files. // We keep a short timeout though as we don't want to influence too much the teardown time of // the tests. - runtimeContainer.dockerClient - .stopContainerCmd(runtimeContainer.containerId) - .withTimeout(1) // This is seconds - .exec() - runtimeContainer.stop() + runtimeContainers.forEach { + if (it.containerId == null) { + LOG.warn( + "During shutdown container ${it.hostname} has no container id, thus it's not running already.") + return@forEach + } + try { + it.dockerClient + .stopContainerCmd(it.containerId) + .withTimeout(1) // This is seconds + .exec() + } catch (e: Exception) { + LOG.warn("Error when trying to send stop container signal to ${it.containerId}", e) + } + } + runtimeContainers.forEach { it.stop() } } private fun teardownAll() { diff --git a/src/main/kotlin/dev/restate/sdktesting/infra/RestateDeployerConfig.kt b/src/main/kotlin/dev/restate/sdktesting/infra/RestateDeployerConfig.kt index caa5e51..c4bf5b7 100644 --- a/src/main/kotlin/dev/restate/sdktesting/infra/RestateDeployerConfig.kt +++ b/src/main/kotlin/dev/restate/sdktesting/infra/RestateDeployerConfig.kt @@ -23,17 +23,19 @@ data class RestateDeployerConfig( val serviceDeploymentConfig: Map, val restateContainerImage: String = "ghcr.io/restatedev/restate:main", val imagePullPolicy: PullPolicy = PullPolicy.ALWAYS, - val deployInParallel: Boolean = true, + val restateNodes: Int = 1, val additionalRuntimeEnvs: Map = mapOf(), val stateDirectoryMount: String? = null, val localIngressPort: Int? = null, val localAdminPort: Int? = null, - val retainAfterEnd: Boolean = false + val localNodePort: Int? = null, + val retainAfterEnd: Boolean = false, ) { init { check(serviceDeploymentConfig.containsKey(ServiceSpec.DEFAULT_SERVICE_NAME)) { "When configuring the deployer, you must provide the ServiceDeploymentConfig for service '${ServiceSpec.DEFAULT_SERVICE_NAME}'" } + check(restateNodes >= 1) { "Number of deployed Restate nodes must be >= 1" } } fun getServiceDeploymentConfig(name: String): ServiceDeploymentConfig { diff --git a/src/main/kotlin/dev/restate/sdktesting/infra/annotations.kt b/src/main/kotlin/dev/restate/sdktesting/infra/annotations.kt index 43f881b..42250b6 100644 --- a/src/main/kotlin/dev/restate/sdktesting/infra/annotations.kt +++ b/src/main/kotlin/dev/restate/sdktesting/infra/annotations.kt @@ -10,6 +10,7 @@ package dev.restate.sdktesting.infra const val RESTATE_RUNTIME = "runtime" const val RUNTIME_INGRESS_ENDPOINT_PORT = 8080 +const val RUNTIME_NODE_PORT = 5122 internal const val RUNTIME_ADMIN_ENDPOINT_PORT = 9070 @Target(AnnotationTarget.VALUE_PARAMETER) annotation class InjectClient diff --git a/src/main/kotlin/dev/restate/sdktesting/junit/TestSuite.kt b/src/main/kotlin/dev/restate/sdktesting/junit/TestSuite.kt index 3b2527d..5315f02 100644 --- a/src/main/kotlin/dev/restate/sdktesting/junit/TestSuite.kt +++ b/src/main/kotlin/dev/restate/sdktesting/junit/TestSuite.kt @@ -29,7 +29,8 @@ import org.junit.platform.reporting.legacy.xml.LegacyXmlReportGeneratingListener class TestSuite( val name: String, val additionalEnvs: Map, - val junitIncludeTags: String + val junitIncludeTags: String, + val restateNodes: Int = 1 ) { fun runTests( terminal: Terminal, @@ -51,7 +52,8 @@ class TestSuite( Configurator.reconfigure(log4j2Configuration) // Apply additional runtime envs - val restateDeployerConfig = getGlobalConfig().copy(additionalRuntimeEnvs = additionalEnvs) + val restateDeployerConfig = + getGlobalConfig().copy(additionalRuntimeEnvs = additionalEnvs, restateNodes = restateNodes) registerGlobalConfig(restateDeployerConfig) // Prepare launch request @@ -117,7 +119,9 @@ class TestSuite( val layout = builder .newLayout("PatternLayout") - .addAttribute("pattern", "%-4r %-5p [%X{test_class}][%t] %c{1.2.*} - %m%n") + .addAttribute( + "pattern", + "%-4r %-5p [%X{test_class}][%t]%notEmpty{[%X{containerHostname}]} %c{1.2.*} - %m%n") val fileAppender = builder @@ -133,7 +137,7 @@ class TestSuite( val testContainersLogger = builder - .newLogger("org.testcontainers", Level.INFO) + .newLogger("org.testcontainers", Level.TRACE) .add(builder.newAppenderRef("log")) .addAttribute("additivity", false) diff --git a/src/main/kotlin/dev/restate/sdktesting/junit/TestSuites.kt b/src/main/kotlin/dev/restate/sdktesting/junit/TestSuites.kt index a218e69..b192667 100644 --- a/src/main/kotlin/dev/restate/sdktesting/junit/TestSuites.kt +++ b/src/main/kotlin/dev/restate/sdktesting/junit/TestSuites.kt @@ -10,19 +10,36 @@ package dev.restate.sdktesting.junit object TestSuites { val DEFAULT_SUITE = TestSuite("default", emptyMap(), "none() | always-suspending") + val THREE_NODES_SUITE = + TestSuite( + "threeNodes", + mapOf( + "RESTATE_BOOTSTRAP_NUM_PARTITIONS" to "4", + ), + "(none() | always-suspending) & !only-single-node", + 3) private val ALWAYS_SUSPENDING_SUITE = TestSuite( "alwaysSuspending", mapOf("RESTATE_WORKER__INVOKER__INACTIVITY_TIMEOUT" to "0s"), "always-suspending | only-always-suspending") + private val THREE_NODES_ALWAYS_SUSPENDING_SUITE = + TestSuite( + "threeNodesAlwaysSuspending", + mapOf( + "RESTATE_WORKER__INVOKER__INACTIVITY_TIMEOUT" to "0s", + "RESTATE_BOOTSTRAP_NUM_PARTITIONS" to "4", + ), + "(always-suspending | only-always-suspending) & !only-single-node", + 3) private val SINGLE_THREAD_SINGLE_PARTITION_SUITE = TestSuite( "singleThreadSinglePartition", mapOf( - "RESTATE_WORKER__BOOTSTRAP_NUM_PARTITIONS" to "1", + "RESTATE_BOOTSTRAP_NUM_PARTITIONS" to "1", "RESTATE_DEFAULT_THREAD_POOL_SIZE" to "1", ), - "none() | always-suspending") + "none() | always-suspending | stop-runtime") private val LAZY_STATE_SUITE = TestSuite( "lazyState", @@ -37,7 +54,9 @@ object TestSuites { fun allSuites(): List { return listOf( DEFAULT_SUITE, + THREE_NODES_SUITE, ALWAYS_SUSPENDING_SUITE, + THREE_NODES_ALWAYS_SUSPENDING_SUITE, SINGLE_THREAD_SINGLE_PARTITION_SUITE, LAZY_STATE_SUITE, PERSISTED_TIMERS_SUITE) @@ -53,7 +72,10 @@ object TestSuites { result + when (configuration) { DEFAULT_SUITE.name -> listOf(DEFAULT_SUITE) + THREE_NODES_SUITE.name -> listOf(THREE_NODES_SUITE) ALWAYS_SUSPENDING_SUITE.name -> listOf(ALWAYS_SUSPENDING_SUITE) + THREE_NODES_ALWAYS_SUSPENDING_SUITE.name -> + listOf(THREE_NODES_ALWAYS_SUSPENDING_SUITE) SINGLE_THREAD_SINGLE_PARTITION_SUITE.name -> listOf(SINGLE_THREAD_SINGLE_PARTITION_SUITE) LAZY_STATE_SUITE.name -> listOf(LAZY_STATE_SUITE) diff --git a/src/main/kotlin/dev/restate/sdktesting/main.kt b/src/main/kotlin/dev/restate/sdktesting/main.kt index 6043648..c5b6547 100644 --- a/src/main/kotlin/dev/restate/sdktesting/main.kt +++ b/src/main/kotlin/dev/restate/sdktesting/main.kt @@ -120,7 +120,6 @@ Run test suite, executing the service as container. val restateDeployerConfig = RestateDeployerConfig( mapOf(ServiceSpec.DEFAULT_SERVICE_NAME to ContainerServiceDeploymentConfig(imageName)), - deployInParallel = parallel, ) // Register global config of the deployer @@ -254,8 +253,9 @@ Run test suite, without executing the service inside a container. option() .help( "Mount the given state directory as restate data when starting the runtime container") - val localIngressPort by option().int().help("Ingress port to bind the runtime container") - val localAdminPort by option().int().help("Ingress port to bind the admin container") + val localIngressPort by option().int().help("Ingress port to bind the restate container") + val localAdminPort by option().int().help("Admin port to bind the restate container") + val localNodePort by option().int().help("Node port to bind the restate container") override fun run() { val terminal = Terminal() @@ -268,6 +268,7 @@ Run test suite, without executing the service inside a container. }, localAdminPort = this.localAdminPort, localIngressPort = this.localIngressPort, + localNodePort = this.localNodePort, stateDirectoryMount = this.mountStateDirectory, retainAfterEnd = this.retainAfterEnd) registerGlobalConfig(testRunnerOptions.applyToDeployerConfig(restateDeployerConfig)) diff --git a/src/main/kotlin/dev/restate/sdktesting/tests/KillRuntime.kt b/src/main/kotlin/dev/restate/sdktesting/tests/KillRuntime.kt index 0e95074..dd181b8 100644 --- a/src/main/kotlin/dev/restate/sdktesting/tests/KillRuntime.kt +++ b/src/main/kotlin/dev/restate/sdktesting/tests/KillRuntime.kt @@ -21,6 +21,7 @@ import org.junit.jupiter.api.Timeout import org.junit.jupiter.api.extension.RegisterExtension @Tag("always-suspending") +@Tag("only-single-node") class KillRuntime { companion object { diff --git a/src/main/kotlin/dev/restate/sdktesting/tests/NonDeterminismErrors.kt b/src/main/kotlin/dev/restate/sdktesting/tests/NonDeterminismErrors.kt index 40c46cf..8d2a160 100644 --- a/src/main/kotlin/dev/restate/sdktesting/tests/NonDeterminismErrors.kt +++ b/src/main/kotlin/dev/restate/sdktesting/tests/NonDeterminismErrors.kt @@ -26,6 +26,7 @@ import org.junit.jupiter.params.provider.ValueSource /** Test non-determinism/journal mismatch checks in the SDKs. */ @Tag("only-always-suspending") +@Tag("only-single-node") class NonDeterminismErrors { companion object { @RegisterExtension diff --git a/src/main/kotlin/dev/restate/sdktesting/tests/SleepWithFailures.kt b/src/main/kotlin/dev/restate/sdktesting/tests/SleepWithFailures.kt index a6c4b64..14540a5 100644 --- a/src/main/kotlin/dev/restate/sdktesting/tests/SleepWithFailures.kt +++ b/src/main/kotlin/dev/restate/sdktesting/tests/SleepWithFailures.kt @@ -28,10 +28,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.Timeout import org.junit.jupiter.api.extension.RegisterExtension -// -- Simple sleep tests - -// -- Sleep tests with terminations/killings of runtime/service endpoint - +// -- Sleep tests with terminations/killings of service endpoint @Tag("always-suspending") class SleepWithFailures { diff --git a/src/main/kotlin/dev/restate/sdktesting/tests/StopRuntime.kt b/src/main/kotlin/dev/restate/sdktesting/tests/StopRuntime.kt index 1f5c80d..fb9fb39 100644 --- a/src/main/kotlin/dev/restate/sdktesting/tests/StopRuntime.kt +++ b/src/main/kotlin/dev/restate/sdktesting/tests/StopRuntime.kt @@ -21,6 +21,7 @@ import org.junit.jupiter.api.Timeout import org.junit.jupiter.api.extension.RegisterExtension @Tag("always-suspending") +@Tag("only-single-node") class StopRuntime { companion object { diff --git a/src/main/resources/junit-platform.properties b/src/main/resources/junit-platform.properties index cd3762a..4f7326c 100644 --- a/src/main/resources/junit-platform.properties +++ b/src/main/resources/junit-platform.properties @@ -1,5 +1,5 @@ # Timeout config -junit.jupiter.execution.timeout.testable.method.default=10 s +junit.jupiter.execution.timeout.testable.method.default=30 s junit.jupiter.execution.timeout.lifecycle.method.default=1 m # Parallelism config