Skip to content

Housekeeping: Use org.testcontainer.*Container #2945

Open
ijusti wants to merge 25 commits into
developfrom
feature/org-testcontainers
Open

Housekeeping: Use org.testcontainer.*Container #2945
ijusti wants to merge 25 commits into
developfrom
feature/org-testcontainers

Conversation

@ijusti
Copy link
Copy Markdown
Collaborator

@ijusti ijusti commented May 7, 2026

Replace GenericContainer with AzuriteContainer and add testcontainers-azure dependency. Update container initialization to use AzuriteContainer API with command modifier for skipApiVersionCheck flag.

Summary by CodeRabbit

  • New Features

    • Added MemSQL support; introduced typed emulators/containers for Pub/Sub, Azurite, Google Storage (Fake GCS), NATS, WireMock, Kafka variants, Grafana LGTM, Keycloak, and MemSQL JDBC.
  • Bug Fixes

    • Improved stdout parsing and port parsing; adjusted default Pub/Sub port to 8085 and updated Grafana default image.
  • Documentation

    • Updated docs for Grafana, Selenium, NATS and others with new defaults and produced properties.
  • Refactor

    • Switched many generic containers to concrete container types and changed mounts to copy-to-container.

@ijusti ijusti self-assigned this May 7, 2026
@ijusti ijusti added enhancement dependencies Pull requests that update a dependency file labels May 7, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Migrates embedded modules from generic containers to typed Testcontainers, adds dependencies, replaces bind mounts with copy-to-container, removes legacy helpers, and applies Java idiom modernizations across code and tests.

Changes

Testcontainers Container Type & Dependency Upgrades

Layer / File(s) Summary
Data & Dependencies
embedded-azurite/pom.xml, embedded-google-pubsub/pom.xml, embedded-google-storage/pom.xml, embedded-keycloak/pom.xml, embedded-memsql/pom.xml, embedded-nats/pom.xml, embedded-wiremock/pom.xml
Added typed Testcontainers module dependencies and version properties for Azurite, PubSub, Fake GCS, Keycloak testcontainers, MemSQL JDBC, NATS, and WireMock testcontainers.
Azurite Container
embedded-azurite/...
Switches to AzuriteContainer, appends --skipApiVersionCheck via create-cmd modifier, and updates Toxiproxy wiring and test assertion typing.
Google Pub/Sub Emulator
embedded-google-pubsub/...
Uses PubSubEmulatorContainer; gRPC channel built from getEmulatorEndpoint(); image and test ports/command adjusted.
Google Cloud Storage FakeGCS
embedded-google-storage/...
Uses FakeGcsServerContainer; removes HTTP config-updater class; registers endpoint via container.url(); test expectations updated.
Grafana LGTM Stack
embedded-grafana/...
Uses LgtmStackContainer; removes custom wait strategy; adds Loki/Tempo/OTLP port properties and health checks; default image set to grafana/otel-lgtm:0.9.3.
Kafka & Native/Confluent Kafka
embedded-kafka/..., embedded-native-kafka/...
Switches to ConfluentKafkaContainer flows, writes advertised listeners at container start, and replaces host bind mounts with copy-to-container (MountableFile).
Keycloak
embedded-keycloak/...
Bootstrap now directly instantiates KeycloakContainer, removes legacy KeycloakContainer class, adds import-file validation and ImportFileNotFoundException, updates properties and tests.
MemSQL
embedded-memsql/...
Adds MemSqlContainer (JdbcDatabaseContainer) with MariaDB driver and fluent API; bootstrap registers JDBC properties and tests assert env values.
MinIO
embedded-minio/...
Migrates to MinIOContainer with inline HTTP health check; removes custom wait strategy/interface and adds conditional properties binding.
NATS
embedded-nats/...
Uses NatsContainer; environment registration simplified to container defaults and constants; logging switched to explicit SLF4J; tests adjusted.
WireMock
embedded-wiremock/...
Uses WireMockContainer; removes port property from properties class; environment registration uses container.getPort()/getHost(); docs updated.
Mount Volume Refactor
testcontainers-common/...
Replaces addFileSystemBind bind mounts with withCopyToContainer(MountableFile.forHostPath(...)) across container utilities and tests.
Java Modernization & Tests
several modules
Applies pattern matching, records in tests, Java text blocks, stream .toList(), Files.writeString, List.of(), var inference, AssertJ typed assertions, and other minor cleanups.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

housekeeping

Suggested reviewers

  • Periecle

🐰 "I hopped through code with curious paws,
Typed containers replaced the old claws.
Records and pattern matches make tests sing,
Copying mounts in — a cleaner spring.
Carrots for builders, cheers for each change!"

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/org-testcontainers

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/testscope/TestcontainerScope.java (1)

91-96: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Protect lifecycle iteration over instances from concurrent mutation.

get/remove synchronize on instances, but both lifecycle methods iterate instances.values() without the same lock. Under parallel test execution this can throw ConcurrentModificationException or skip callbacks.

Suggested fix
 public void afterTestMethod(TestContext testContext) {
-    instances.values().stream()
+    final var snapshot = synchronizedSnapshot();
+    snapshot.stream()
             .filter(TestLifecycleAware.class::isInstance)
             .map(TestLifecycleAware.class::cast)
             .forEach(value -> value.afterTest(testDescription(testContext), Optional.ofNullable(testContext.getTestException())));
  }
@@
 public void beforeTestMethod(TestContext testContext) {
-    instances.values().stream()
+    final var snapshot = synchronizedSnapshot();
+    snapshot.stream()
             .filter(TestLifecycleAware.class::isInstance)
             .map(TestLifecycleAware.class::cast)
             .forEach(value -> value.beforeTest(testDescription(testContext)));
 }
+
+private java.util.List<Object> synchronizedSnapshot() {
+    synchronized (this.instances) {
+        return new java.util.ArrayList<>(this.instances.values());
+    }
+}

Also applies to: 113-117

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/testscope/TestcontainerScope.java`
around lines 91 - 96, The iteration over the instances map in afterTestMethod
(and the analogous lifecycle method at lines 113-117) is not protected against
concurrent mutation; wrap the iteration and callback invocation in the same lock
used by get/remove (synchronize on the instances object) or alternatively take a
safe snapshot (e.g., new ArrayList<>(instances.values())) before streaming, so
TestLifecycleAware callbacks (afterTest in TestcontainerScope) cannot throw
ConcurrentModificationException or miss callbacks under parallel test execution;
apply the same fix to the other lifecycle method that iterates
instances.values().
embedded-google-pubsub/src/main/java/com/playtika/testcontainer/pubsub/EmbeddedPubsubBootstrapConfiguration.java (1)

64-83: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

PubSub emulator port must be explicitly configured to respect the embedded.google.pubsub.port property override.

Currently, PubSubEmulatorContainer starts with hardcoded port 8085 and only exposes that port. If embedded.google.pubsub.port is overridden to a different value, container.getMappedPort(properties.getPort()) at line 82 will fail because the overridden port is not exposed. Similarly, toxiproxy setup at line 55 will break when attempting to proxy a non-existent exposed port.

Add .withExposedPorts(properties.getPort()) and configure the emulator command to use the property-driven port via .withCommand() or environment variable, consistent with how other modules (Redis, MySQL, Solr, etc.) handle configurable ports. Additionally, add a test that verifies port override works correctly end-to-end.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-google-pubsub/src/main/java/com/playtika/testcontainer/pubsub/EmbeddedPubsubBootstrapConfiguration.java`
around lines 64 - 83, The PubSub emulator currently always exposes hardcoded
8085 which breaks overrides; update the pubsub(...) builder to call
.withExposedPorts(properties.getPort()) and configure the emulator to listen on
that port (use .withCommand(...) or an env var in PubSubEmulatorContainer) so
the started container actually exposes properties.getPort(); ensure
configureCommonsAndStart(...) and the toxiproxy setup use the exposed port, and
add an integration test that sets embedded.google.pubsub.port to a non-default
value and asserts registerPubsubEnvironment(...) returns the mapped port and
that pubsub accepts connections on that overridden port.
embedded-native-kafka/src/main/java/com/playtika/testcontainer/nativekafka/configuration/NativeKafkaContainerConfiguration.java (1)

86-97: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Bind→copy switch silently breaks data persistence to the host.

Same concern as in KafkaContainerConfiguration: replacing the bidirectional bind with withCopyToContainer(MountableFile.forHostPath(...), "/tmp/kafka-logs") makes the mount one-way (host → container at startup). Users who enabled fileSystemBind to inspect or reuse Kafka logs after the container stops will silently lose that capability.

Use withFileSystemBind(kafkaData.toString(), "/tmp/kafka-logs", BindMode.READ_WRITE) if persistence is intended, or update the property name/docs to reflect copy-in-only semantics.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-native-kafka/src/main/java/com/playtika/testcontainer/nativekafka/configuration/NativeKafkaContainerConfiguration.java`
around lines 86 - 97, The current configureFileSystemBind method uses
nativeKafka.withCopyToContainer(MountableFile.forHostPath(...),
"/tmp/kafka-logs") which performs a one-way copy and breaks host persistence;
change the behavior to mount a bidirectional bind when
fileSystemBind.isEnabled() by using
nativeKafka.withFileSystemBind(kafkaData.toString(), "/tmp/kafka-logs",
BindMode.READ_WRITE) (or otherwise surface the copy-only semantics in the
FileSystemBind property/docs) so that FileSystemBind results in persistent host
↔ container logs; update references in configureFileSystemBind, FileSystemBind
usage, and the call site that creates kafkaData to reflect this replacement.
embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/EmbeddedSeleniumBootstrapConfiguration.java (1)

76-95: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Behavior change: embedded.selenium.arguments is no longer applied to the container.

Previously, withCapabilities(capabilities) passed user-configured ChromeOptions/FirefoxOptions (populated via properties.apply(options)) to the container, so values like embedded.selenium.arguments=--headless were automatically used. With this refactor, the ChromeOptions/FirefoxOptions beans are still defined but never passed to BrowserWebDriverContainer. Users now have to manually @Autowired ChromeOptions options and pass it to new RemoteWebDriver(...) themselves. The README example does this, but users upgrading without reading the doc will silently lose their browser arguments.

Consider documenting this as a breaking change in the module's README/migration notes (the embedded.selenium.arguments doc on Line 21 still says "list of browser arguments passed to ChromeOptions/FirefoxOptions" which is technically still true, but no longer applied to the container automatically).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/EmbeddedSeleniumBootstrapConfiguration.java`
around lines 76 - 95, The container factory method selenium(...) no longer
applies user-configured browser options to BrowserWebDriverContainer, so
embedded.selenium.arguments are ignored; fix by creating and applying the
Capabilities built from the existing ChromeOptions/FirefoxOptions beans (the
same options that properties.apply(...) produces) to the
BrowserWebDriverContainer via withCapabilities(...) before starting it (update
the selenium(...) method to obtain the Options/Capabilities from
SeleniumProperties or call properties.apply(...) and pass the resulting
Capabilities to container.withCapabilities(...)); additionally document this
behavioral change in the module README/migration notes and clarify that
embedded.selenium.arguments are automatically applied to the container (or note
the breaking change if you prefer to require manual wiring).
embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/configuration/KafkaContainerConfiguration.java (1)

223-254: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Bind→copy switch silently breaks data persistence to the host.

Switching from addFileSystemBind(..., BindMode.READ_WRITE) to withCopyToContainer(MountableFile.forHostPath(...), ...) changes the semantics from a bidirectional bind (data written by Kafka/ZooKeeper inside the container is visible on the host after the run) to a one-way copy (host → container at start; nothing flows back). For users who enabled fileSystemBind/zookeeperFileSystemBind precisely to inspect or reuse Kafka/ZooKeeper data across runs, this is a silent regression.

If the intent is to keep persistence, prefer withFileSystemBind(host, target, BindMode.READ_WRITE) (the non-deprecated replacement for addFileSystemBind) so writes propagate back. If the intent is only to seed initial data, the user-facing property naming and docs should be updated to reflect the new "copy-in only" behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/configuration/KafkaContainerConfiguration.java`
around lines 223 - 254, The current kafkaFileSystemBind and
zookeperFileSystemBind methods use withCopyToContainer which only copies
host→container and breaks persistence; change both methods to call
kafka.withFileSystemBind(hostPath, containerPath, BindMode.READ_WRITE) (the
non-deprecated replacement for addFileSystemBind) so container writes are
visible on the host, keeping the existing createPathAndParentOrMakeWritable
calls to ensure the host dirs exist and are writable; if the original intent was
only seeding, instead update the property/docs to reflect copy-in-only behavior.
embedded-vault/src/main/java/com/playtika/testcontainer/vault/EmbeddedVaultBootstrapConfiguration.java (1)

73-78: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Secret values containing spaces will silently corrupt the kv put command.

String.join(" ", secrets) concatenates all key=value tokens with spaces. Internally, withInitCommand passes the command string through buildExecCommand which splits on whitespace. A value such as "my key=hello world" or "key=hello world" becomes extra broken tokens in the exec array, causing the vault CLI call to fail or store incorrect data.

Consider rejecting or quoting secret values with spaces at this level, or document that values containing spaces are unsupported:

🛡️ Proposed guard
         String[] secrets = properties.getSecrets().entrySet().stream()
                 .map(entry -> String.format("%s=%s", entry.getKey(), entry.getValue()))
                 .toArray(String[]::new);
+
+        boolean hasSpaces = properties.getSecrets().entrySet().stream()
+                .anyMatch(e -> e.getKey().contains(" ") || e.getValue().contains(" "));
+        if (hasSpaces) {
+            throw new IllegalArgumentException(
+                "Vault secret keys and values must not contain spaces when using withInitCommand");
+        }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-vault/src/main/java/com/playtika/testcontainer/vault/EmbeddedVaultBootstrapConfiguration.java`
around lines 73 - 78, The constructed init command in
EmbeddedVaultBootstrapConfiguration uses String.join(" ", secrets) which breaks
when secret values contain whitespace; update the code that builds the secrets
(the properties.getSecrets mapping before calling vault.withInitCommand) to
validate each value and reject any that contain whitespace by throwing an
IllegalArgumentException with a clear message (include the offending key and
hint to remove/escape spaces), so that vault.withInitCommand is never passed a
malformed command; alternatively, implement proper shell-quoting/escaping of
values before assembling the command if you prefer to support spaces.
🧹 Nitpick comments (6)
embedded-grafana/src/test/java/com/playtika/testcontainer/grafana/EmbeddedGrafanaBootstrapConfigurationTest.java (1)

19-20: 💤 Low value

otlpHttpPort is injected but unused.

The field is read from embedded.grafana.otlp.http.port but never referenced by any test in this class. Either drop it or add a corresponding reachability test (e.g. POSTing to /v1/traces or hitting /v1/health) to justify the injection.

♻️ Proposed cleanup
-    `@Value`("${embedded.grafana.otlp.http.port}")
-    private int otlpHttpPort;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-grafana/src/test/java/com/playtika/testcontainer/grafana/EmbeddedGrafanaBootstrapConfigurationTest.java`
around lines 19 - 20, The field otlpHttpPort in
EmbeddedGrafanaBootstrapConfigurationTest is injected but never used; either
remove the field declaration or add a minimal reachability test that uses it
(e.g., in method within EmbeddedGrafanaBootstrapConfigurationTest perform an
HTTP request to the Grafana OTLP endpoint using otlpHttpPort — e.g., GET
http://localhost:{otlpHttpPort}/v1/health or a POST to /v1/traces with a small
payload — and assert a successful status) so the injected value is actually
referenced.
embedded-wiremock/src/main/java/com/playtika/testcontainers/wiremock/EmbeddedWiremockBootstrapConfiguration.java (1)

50-56: 💤 Low value

Extract the hard-coded internal port 8080 into a named constant.

8080 is repeated as a magic value here. Define a constant (e.g., WIREMOCK_INTERNAL_PORT = 8080) and reuse it for embedded.wiremock.internalPort to make intent explicit and ease future changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-wiremock/src/main/java/com/playtika/testcontainers/wiremock/EmbeddedWiremockBootstrapConfiguration.java`
around lines 50 - 56, Replace the hard-coded 8080 in registerWiremockEnvironment
with a named constant; declare a private static final int WIREMOCK_INTERNAL_PORT
= 8080 (or similar) in EmbeddedWiremockBootstrapConfiguration and use that
constant when putting "embedded.wiremock.internalPort" into the map to remove
the magic number and make the intent explicit.
embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/EmbeddedSeleniumBootstrapConfiguration.java (1)

161-189: 💤 Low value

Misleading fallback at the end of getHostName(...).

For any OS that is not Mac/Darwin/Windows/Linux (e.g. *BSD, Solaris), the method now returns DOCKER_FOR_LINUX_STATIC_IP (172.17.0.1), which is specifically the Docker bridge gateway on Linux and likely incorrect on other platforms. Either log a warning and return host.docker.internal (the more portable Docker default in modern engines) or make the fallback explicit so users know it's a Linux-only assumption.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/EmbeddedSeleniumBootstrapConfiguration.java`
around lines 161 - 189, The fallback in getHostName(...) currently returns the
Linux-specific DOCKER_FOR_LINUX_STATIC_IP for any unrecognized OS; change this
so unknown/non-mac-win-linux platforms do not silently get a Linux IP: detect
the branch where OS isn't mac/win/nux, log a warning (include the OS string)
using the existing logger, and return "host.docker.internal" instead of
DOCKER_FOR_LINUX_STATIC_IP; update references in getHostName and keep
DOCKER_FOR_LINUX_STATIC_IP only for the explicit linux branch so the Linux
assumption is not applied to other platforms.
embedded-azurite/src/main/java/com/playtika/testcontainer/azurite/EmbeddedAzuriteBootstrapConfiguration.java (1)

113-113: ⚡ Quick win

Consider making configureCommonsAndStart generic to eliminate the unchecked cast.

The (AzuriteContainer) cast is necessary because configureCommonsAndStart returns GenericContainer<?> while the variable is typed as AzuriteContainer. The method returns the same instance it receives (see ContainerUtils.java line 67-98), but the wildcard generic type forces callers to cast. Making the method generic—e.g., <T extends GenericContainer<T>> T configureCommonsAndStart(T container, ...)—would preserve type safety and eliminate this cast.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-azurite/src/main/java/com/playtika/testcontainer/azurite/EmbeddedAzuriteBootstrapConfiguration.java`
at line 113, The unchecked cast on azuriteContainer comes from
configureCommonsAndStart returning GenericContainer<?>; change
configureCommonsAndStart to a generic signature (e.g. <T extends
GenericContainer<?>> T configureCommonsAndStart(T container,
TestcontainersConfigurationProperties properties, Log log) or <T extends
GenericContainer<T>> T configureCommonsAndStart(...)) in the implementation
(ContainerUtils.configureCommonsAndStart) and its declaration so it preserves
the concrete container type, then call it from
EmbeddedAzuriteBootstrapConfiguration without casting (azuriteContainer =
configureCommonsAndStart(azuriteContainer, properties, log)); ensure method
usages elsewhere are updated to the new generic signature.
embedded-nats/src/main/java/com/playtika/testcontainer/nats/EmbeddedNatsBootstrapConfiguration.java (1)

39-39: 💤 Low value

Optional: keep Lombok @Slf4j for consistency.

The class previously used Lombok’s @Slf4j; switching to a manual LoggerFactory here introduces a stylistic inconsistency with the rest of the module (e.g., BaseNatsTest still uses @Slf4j). Unless there’s a specific reason (e.g., dropping Lombok), reverting to @Slf4j keeps things uniform.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-nats/src/main/java/com/playtika/testcontainer/nats/EmbeddedNatsBootstrapConfiguration.java`
at line 39, The class defines a manual Logger field "log" via LoggerFactory
which breaks module stylistic consistency; replace it by reintroducing Lombok's
`@Slf4j` on the EmbeddedNatsBootstrapConfiguration class and remove the private
static final Logger log declaration so the class uses the Lombok-generated "log"
instead (ensure Lombok is enabled in the module and imports are adjusted
accordingly).
embedded-google-storage/src/test/java/com/playtika/testcontainer/storage/EmbeddedStorageBootstrapConfigurationTest.java (1)

118-134: 💤 Low value

Consider using asInstanceOf for a type-safe assertion without an explicit cast.

The current pattern (.isInstanceOf(...) + manual cast inside .satisfies(...)) is functional, but AssertJ provides a cleaner single-step alternative that eliminates the unchecked cast:

♻️ Proposed refactor using asInstanceOf
+import org.assertj.core.api.InstanceOfAssertFactories;
 ...
         assertThat(beanFactory.getBean(BEAN_NAME_EMBEDDED_GOOGLE_STORAGE_SERVER))
             .isNotNull()
-            .isInstanceOf(FakeGcsServerContainer.class)
-            .satisfies(bean -> {
-                FakeGcsServerContainer container = (FakeGcsServerContainer) bean;
-
-                assertThat(container.getExposedPorts()).containsExactly(4443);
-                assertThat(container.getContainerInfo().getConfig().getEntrypoint())
-                    .containsExactly(
-                        "/bin/fake-gcs-server",
-                        "-backend", "memory",
-                        "-scheme", "http",
-                        "-host", "0.0.0.0",
-                        "-port", "4443",
-                        "-location", "US-EAST1");
-            });
+            .asInstanceOf(InstanceOfAssertFactories.type(FakeGcsServerContainer.class))
+            .satisfies(container -> {
+                assertThat(container.getExposedPorts()).containsExactly(4443);
+                assertThat(container.getContainerInfo().getConfig().getEntrypoint())
+                    .containsExactly(
+                        "/bin/fake-gcs-server",
+                        "-backend", "memory",
+                        "-scheme", "http",
+                        "-host", "0.0.0.0",
+                        "-port", "4443",
+                        "-location", "US-EAST1");
+            });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-google-storage/src/test/java/com/playtika/testcontainer/storage/EmbeddedStorageBootstrapConfigurationTest.java`
around lines 118 - 134, Replace the isInstanceOf + manual cast pattern in
shouldHaveContainerWithExpectedDefaultProperties with AssertJ's type-safe
asInstanceOf: call
asInstanceOf(InstanceOfAssertFactories.type(FakeGcsServerContainer.class)) on
the beanFactory.getBean(BEAN_NAME_EMBEDDED_GOOGLE_STORAGE_SERVER) assertion so
the lambda passed to satisfies receives a typed FakeGcsServerContainer (no
explicit cast), then keep the same assertions on getExposedPorts() and
getContainerInfo().getConfig().getEntrypoint().
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@embedded-azurite/src/main/java/com/playtika/testcontainer/azurite/EmbeddedAzuriteBootstrapConfiguration.java`:
- Around line 105-109: The lambda passed to withCreateContainerCmdModifier uses
Arrays.asList(cmd.getCmd()) which throws NPE because CreateContainerCmd.getCmd()
can be null; update the modifier in EmbeddedAzuriteBootstrapConfiguration so it
first checks cmd.getCmd() for null and builds the args list accordingly (e.g.,
start from an empty List if null or new ArrayList<>(Arrays.asList(cmd.getCmd()))
if non-null), then add "--skipApiVersionCheck" and call cmd.withCmd(args) as
before; reference the CreateContainerCmd instance named cmd and the existing
cmd.withCmd(...) call when making the change.

In `@embedded-grafana/README.adoc`:
- Around line 30-39: The example under embedded.grafana.filesToInclude uses the
standard Grafana path which is incorrect for the grafana/otel-lgtm image; update
the containerPath value in the example to the otel-lgtm provisioning location
(/otel-lgtm/grafana/conf/provisioning/datasources/my-datasource.yml) so that
embedded.grafana.filesToInclude points classpath resources into the correct
otel-lgtm container provisioning directory.

In `@embedded-keycloak/pom.xml`:
- Around line 17-18: The POM pins testcontainers-keycloak.version to 3.3.0 which
targets Keycloak 24 and Testcontainers 1.19.6; update the
testcontainers-keycloak.version property (reference:
testcontainers-keycloak.version) to a compatible release (e.g., 3.4.x if you
want Keycloak 25.x compatibility or 4.x if you plan to move to Keycloak
26+/Testcontainers 2.x), and also align any Keycloak docker image tags and the
Testcontainers baseline managed by the parent (Spring Boot) so the
testcontainers-keycloak client, Keycloak image tag and Testcontainers runtime
are mutually compatible before running tests.

In
`@embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/EmbeddedKeycloakBootstrapConfiguration.java`:
- Around line 82-109: The applyDbConfig method in
EmbeddedKeycloakBootstrapConfiguration is setting legacy DB_* env vars; change
it to set the Keycloak 25 names (e.g. KC_DB, KC_DB_URL_HOST, KC_DB_URL_PORT,
KC_DB_URL_DATABASE, KC_DB_SCHEMA, KC_DB_USERNAME, KC_DB_PASSWORD) on the
KeycloakContainer instead of DB_*; remove emitting DB_USER_FILE/DB_PASSWORD_FILE
env vars and, when KeycloakProperties.getDbUserFile() or getDbPasswordFile() is
provided, read those files' contents inside applyDbConfig and set the
corresponding KC_DB_USERNAME / KC_DB_PASSWORD values on the KeycloakContainer
(or fall back to getDbUser()/getDbPassword() if present), ensuring no *_FILE env
vars are passed to the container. Reference: applyDbConfig(KeycloakContainer,
KeycloakProperties), KeycloakContainer.withEnv(...),
KeycloakProperties.getDbUserFile()/getDbPasswordFile()/getDbUser()/getDbPassword().
- Around line 63-79: The container is not started with the configured context
path and the auth URL is being composed manually; update the KeycloakContainer
creation in keycloakContainer(...) to call
.withContextPath(properties.getAuthBasePath()) on the KeycloakContainer
instance, and after starting/configuring the container (i.e., after
configureCommonsAndStart(...)) replace any manual buildAuthServerUrl(...) usage
with keycloak.getAuthServerUrl() when registering/exporting the
embedded.keycloak.auth-server-url in registerEnvironment(...), ensuring
KeycloakContainer.getAuthServerUrl() is used to obtain the resolved URL.

In
`@embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/KeycloakProperties.java`:
- Around line 74-77: The override of getCommand() returns null and thus drops
any configured embedded.keycloak.command; restore inherited behavior by removing
this getCommand() override or change it to return super.getCommand() so
ContainerUtils.configureCommonsAndStart() can detect and apply the command (or
if you intentionally migrated to the new container API, map the configured
command into the newer API call such as the container's custom command setter
instead of returning null). Ensure references: getCommand(),
ContainerUtils.configureCommonsAndStart(), and the withCommand()/new custom
command API are handled accordingly.

In
`@embedded-memsql/src/main/java/com/playtika/testcontainer/memsql/EmbeddedMemSqlBootstrapConfiguration.java`:
- Around line 97-103: The code currently adds the plaintext password via
memsql.getPassword() into the properties map and then logs the entire map with
log.info in EmbeddedMemSqlBootstrapConfiguration, which leaks credentials;
remove the plaintext secret from the logged data by either not adding
"embedded.memsql.password" to the map used for logging or replacing its value
with a redaction (e.g., "REDACTED" or masked string) before calling log.info,
leaving the actual property assignment to the internal configuration if needed;
update references around map, memsql.getPassword(), and the log.info("Started
memsql server. Connection details {} ", map) call so only non-sensitive
connection details are logged.
- Around line 79-81: The code incorrectly checks
System.getProperty("system.arch") and uses memsql.withCommand(...) to try to set
Docker platform; change to read System.getProperty("os.arch") (null-safe) and
detect ARM variants (e.g. check if the string contains or starts with "arm" or
"aarch" or equals "aarch64"), and replace the withCommand call on the memsql
object with the Testcontainers API memsql.withCreateContainerCmdModifier(cmd ->
cmd.withPlatform("linux/amd64")) so the container is created with the correct
platform; update any surrounding null/empty checks accordingly around memsql and
the os.arch value.

In
`@embedded-memsql/src/main/java/com/playtika/testcontainer/memsql/MemSqlContainer.java`:
- Around line 28-31: The withUsername method in MemSqlContainer currently
accepts arbitrary usernames while the container only provisions root
credentials, causing unreachable credentials; update withUsername(String
username) in class MemSqlContainer to validate input and fail fast by throwing
an IllegalArgumentException (or IllegalStateException) if the caller passes a
non-root username (i.e., anything other than "root"), or alternatively implement
user provisioning in the container configuration flow (the configure/start
methods) to create the requested user; reference the withUsername method and the
container configuration/start logic (where root credentials are set) and ensure
getUsername/getPassword/getJdbcUrl return only credentials that the container
actually provisions.

In
`@embedded-minio/src/test/java/com/playtika/testcontainer/minio/EmbeddedMinioBootstrapConfigurationTest.java`:
- Around line 100-102: The convertStreamToString helper creates a Scanner over
the provided InputStream but never closes it, leaking resources; update
convertStreamToString to use a try-with-resources (or explicitly close) for the
Scanner (which will also close the InputStream) so the Scanner and underlying
stream are always closed after reading, and return the same string result;
reference: convertStreamToString(java.io.InputStream).

In `@embedded-selenium/README.adoc`:
- Around line 40-57: The README is inconsistent with the bootstrap wiring:
either restore the embedded.selenium.browser property to the documented
"Consumes" list and clarify Edge is unsupported, or change
EmbeddedSeleniumBootstrapConfiguration so options are derived from the Docker
image; to fix quickly, update the docs to mention embedded.selenium.browser and
that Chrome/Firefox selection still requires setting
embedded.selenium.browser=CHROMIUM|FIREFOX and that Edge is not yet supported
(no EdgeOptions bean), or alternatively implement EdgeOptions and add logic in
EmbeddedSeleniumBootstrapConfiguration (see chromeOptions, firefoxOptions
factory methods) to parse the selenium image name and select/create the matching
Options bean automatically instead of relying on the property.

In `@embedded-wiremock/pom.xml`:
- Line 18: Update the wiremock-testcontainers-module version property value from
1.0-alpha-13 to 1.0-alpha-15 in the Maven POM by changing the
<wiremock-testcontainers-module.version> property (the property named
wiremock-testcontainers-module.version) so the project uses the newer alpha-15
release; then run a quick mvn -U test or dependency:resolve to ensure the new
artifact resolves and adjust any failing tests if API/behavior changed.

In
`@testcontainers-common/src/main/java/com/playtika/testcontainer/common/utils/ContainerUtils.java`:
- Around line 86-88: The change from addFileSystemBind to withCopyToContainer
breaks bind-mount semantics and drops BindMode and getBinds(); revert the loop
in ContainerUtils that iterates properties.getMountVolumes() to call
addFileSystemBind(...) (using mountVolume.getHostPath(),
mountVolume.getContainerPath(), and mountVolume.getMode()) instead of
withCopyToContainer, and capture the returned GenericContainer into
updatedContainer (consistent with the withCopyFileToContainer usage) so binds
and modes are preserved and tests like
ContainerUtilsTest.configureCommonsAndStart still see getBinds(); if you
intentionally wanted one-way copy instead, update ContainerUtilsTest to assert
getCopyToFileContainerPathMap() and remove/annotate MountVolume.getMode() as
ignored.

---

Outside diff comments:
In
`@embedded-google-pubsub/src/main/java/com/playtika/testcontainer/pubsub/EmbeddedPubsubBootstrapConfiguration.java`:
- Around line 64-83: The PubSub emulator currently always exposes hardcoded 8085
which breaks overrides; update the pubsub(...) builder to call
.withExposedPorts(properties.getPort()) and configure the emulator to listen on
that port (use .withCommand(...) or an env var in PubSubEmulatorContainer) so
the started container actually exposes properties.getPort(); ensure
configureCommonsAndStart(...) and the toxiproxy setup use the exposed port, and
add an integration test that sets embedded.google.pubsub.port to a non-default
value and asserts registerPubsubEnvironment(...) returns the mapped port and
that pubsub accepts connections on that overridden port.

In
`@embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/configuration/KafkaContainerConfiguration.java`:
- Around line 223-254: The current kafkaFileSystemBind and
zookeperFileSystemBind methods use withCopyToContainer which only copies
host→container and breaks persistence; change both methods to call
kafka.withFileSystemBind(hostPath, containerPath, BindMode.READ_WRITE) (the
non-deprecated replacement for addFileSystemBind) so container writes are
visible on the host, keeping the existing createPathAndParentOrMakeWritable
calls to ensure the host dirs exist and are writable; if the original intent was
only seeding, instead update the property/docs to reflect copy-in-only behavior.

In
`@embedded-native-kafka/src/main/java/com/playtika/testcontainer/nativekafka/configuration/NativeKafkaContainerConfiguration.java`:
- Around line 86-97: The current configureFileSystemBind method uses
nativeKafka.withCopyToContainer(MountableFile.forHostPath(...),
"/tmp/kafka-logs") which performs a one-way copy and breaks host persistence;
change the behavior to mount a bidirectional bind when
fileSystemBind.isEnabled() by using
nativeKafka.withFileSystemBind(kafkaData.toString(), "/tmp/kafka-logs",
BindMode.READ_WRITE) (or otherwise surface the copy-only semantics in the
FileSystemBind property/docs) so that FileSystemBind results in persistent host
↔ container logs; update references in configureFileSystemBind, FileSystemBind
usage, and the call site that creates kafkaData to reflect this replacement.

In
`@embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/EmbeddedSeleniumBootstrapConfiguration.java`:
- Around line 76-95: The container factory method selenium(...) no longer
applies user-configured browser options to BrowserWebDriverContainer, so
embedded.selenium.arguments are ignored; fix by creating and applying the
Capabilities built from the existing ChromeOptions/FirefoxOptions beans (the
same options that properties.apply(...) produces) to the
BrowserWebDriverContainer via withCapabilities(...) before starting it (update
the selenium(...) method to obtain the Options/Capabilities from
SeleniumProperties or call properties.apply(...) and pass the resulting
Capabilities to container.withCapabilities(...)); additionally document this
behavioral change in the module README/migration notes and clarify that
embedded.selenium.arguments are automatically applied to the container (or note
the breaking change if you prefer to require manual wiring).

In
`@embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/testscope/TestcontainerScope.java`:
- Around line 91-96: The iteration over the instances map in afterTestMethod
(and the analogous lifecycle method at lines 113-117) is not protected against
concurrent mutation; wrap the iteration and callback invocation in the same lock
used by get/remove (synchronize on the instances object) or alternatively take a
safe snapshot (e.g., new ArrayList<>(instances.values())) before streaming, so
TestLifecycleAware callbacks (afterTest in TestcontainerScope) cannot throw
ConcurrentModificationException or miss callbacks under parallel test execution;
apply the same fix to the other lifecycle method that iterates
instances.values().

In
`@embedded-vault/src/main/java/com/playtika/testcontainer/vault/EmbeddedVaultBootstrapConfiguration.java`:
- Around line 73-78: The constructed init command in
EmbeddedVaultBootstrapConfiguration uses String.join(" ", secrets) which breaks
when secret values contain whitespace; update the code that builds the secrets
(the properties.getSecrets mapping before calling vault.withInitCommand) to
validate each value and reject any that contain whitespace by throwing an
IllegalArgumentException with a clear message (include the offending key and
hint to remove/escape spaces), so that vault.withInitCommand is never passed a
malformed command; alternatively, implement proper shell-quoting/escaping of
values before assembling the command if you prefer to support spaces.

---

Nitpick comments:
In
`@embedded-azurite/src/main/java/com/playtika/testcontainer/azurite/EmbeddedAzuriteBootstrapConfiguration.java`:
- Line 113: The unchecked cast on azuriteContainer comes from
configureCommonsAndStart returning GenericContainer<?>; change
configureCommonsAndStart to a generic signature (e.g. <T extends
GenericContainer<?>> T configureCommonsAndStart(T container,
TestcontainersConfigurationProperties properties, Log log) or <T extends
GenericContainer<T>> T configureCommonsAndStart(...)) in the implementation
(ContainerUtils.configureCommonsAndStart) and its declaration so it preserves
the concrete container type, then call it from
EmbeddedAzuriteBootstrapConfiguration without casting (azuriteContainer =
configureCommonsAndStart(azuriteContainer, properties, log)); ensure method
usages elsewhere are updated to the new generic signature.

In
`@embedded-google-storage/src/test/java/com/playtika/testcontainer/storage/EmbeddedStorageBootstrapConfigurationTest.java`:
- Around line 118-134: Replace the isInstanceOf + manual cast pattern in
shouldHaveContainerWithExpectedDefaultProperties with AssertJ's type-safe
asInstanceOf: call
asInstanceOf(InstanceOfAssertFactories.type(FakeGcsServerContainer.class)) on
the beanFactory.getBean(BEAN_NAME_EMBEDDED_GOOGLE_STORAGE_SERVER) assertion so
the lambda passed to satisfies receives a typed FakeGcsServerContainer (no
explicit cast), then keep the same assertions on getExposedPorts() and
getContainerInfo().getConfig().getEntrypoint().

In
`@embedded-grafana/src/test/java/com/playtika/testcontainer/grafana/EmbeddedGrafanaBootstrapConfigurationTest.java`:
- Around line 19-20: The field otlpHttpPort in
EmbeddedGrafanaBootstrapConfigurationTest is injected but never used; either
remove the field declaration or add a minimal reachability test that uses it
(e.g., in method within EmbeddedGrafanaBootstrapConfigurationTest perform an
HTTP request to the Grafana OTLP endpoint using otlpHttpPort — e.g., GET
http://localhost:{otlpHttpPort}/v1/health or a POST to /v1/traces with a small
payload — and assert a successful status) so the injected value is actually
referenced.

In
`@embedded-nats/src/main/java/com/playtika/testcontainer/nats/EmbeddedNatsBootstrapConfiguration.java`:
- Line 39: The class defines a manual Logger field "log" via LoggerFactory which
breaks module stylistic consistency; replace it by reintroducing Lombok's `@Slf4j`
on the EmbeddedNatsBootstrapConfiguration class and remove the private static
final Logger log declaration so the class uses the Lombok-generated "log"
instead (ensure Lombok is enabled in the module and imports are adjusted
accordingly).

In
`@embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/EmbeddedSeleniumBootstrapConfiguration.java`:
- Around line 161-189: The fallback in getHostName(...) currently returns the
Linux-specific DOCKER_FOR_LINUX_STATIC_IP for any unrecognized OS; change this
so unknown/non-mac-win-linux platforms do not silently get a Linux IP: detect
the branch where OS isn't mac/win/nux, log a warning (include the OS string)
using the existing logger, and return "host.docker.internal" instead of
DOCKER_FOR_LINUX_STATIC_IP; update references in getHostName and keep
DOCKER_FOR_LINUX_STATIC_IP only for the explicit linux branch so the Linux
assumption is not applied to other platforms.

In
`@embedded-wiremock/src/main/java/com/playtika/testcontainers/wiremock/EmbeddedWiremockBootstrapConfiguration.java`:
- Around line 50-56: Replace the hard-coded 8080 in registerWiremockEnvironment
with a named constant; declare a private static final int WIREMOCK_INTERNAL_PORT
= 8080 (or similar) in EmbeddedWiremockBootstrapConfiguration and use that
constant when putting "embedded.wiremock.internalPort" into the map to remove
the magic number and make the intent explicit.
🪄 Autofix (Beta)

❌ Autofix failed (check again to retry)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a4d3e000-d1bd-4c59-a57c-5eb97f5b7957

📥 Commits

Reviewing files that changed from the base of the PR and between f86368d and fdf8c9f.

📒 Files selected for processing (71)
  • embedded-aerospike/src/main/java/com/playtika/testcontainer/aerospike/AerospikeTestOperations.java
  • embedded-aerospike/src/main/java/com/playtika/testcontainer/aerospike/AerospikeWaitStrategy.java
  • embedded-azurite/pom.xml
  • embedded-azurite/src/main/java/com/playtika/testcontainer/azurite/EmbeddedAzuriteBootstrapConfiguration.java
  • embedded-azurite/src/test/java/com/playtika/testcontainer/azurite/EmbeddedAzuriteBoostrapConfigurationTest.java
  • embedded-consul/src/test/java/com/playtika/testcontainer/consul/EmbeddedConsulBootstrapConfigurationTest.java
  • embedded-couchbase/src/test/java/com/playtika/testcontainer/couchbase/springdata/SpringDataTest.java
  • embedded-git/src/test/java/config/CustomTransportConfigCallback.java
  • embedded-google-pubsub/pom.xml
  • embedded-google-pubsub/src/main/java/com/playtika/testcontainer/pubsub/EmbeddedPubsubBootstrapConfiguration.java
  • embedded-google-pubsub/src/main/java/com/playtika/testcontainer/pubsub/PubsubProperties.java
  • embedded-google-pubsub/src/test/java/com/playtika/testcontainer/pubsub/EmbeddedPubsubBootstrapConfigurationTest.java
  • embedded-google-storage/pom.xml
  • embedded-google-storage/src/main/java/com/playtika/testcontainer/storage/EmbeddedStorageBootstrapConfiguration.java
  • embedded-google-storage/src/main/java/com/playtika/testcontainer/storage/GoogleCloudStorageHttpClient.java
  • embedded-google-storage/src/test/java/com/playtika/testcontainer/storage/EmbeddedStorageBootstrapConfigurationTest.java
  • embedded-grafana/README.adoc
  • embedded-grafana/src/main/java/com/playtika/testcontainer/grafana/EmbeddedGrafanaBootstrapConfiguration.java
  • embedded-grafana/src/main/java/com/playtika/testcontainer/grafana/GrafanaProperties.java
  • embedded-grafana/src/test/java/com/playtika/testcontainer/grafana/EmbeddedGrafanaBootstrapConfigurationTest.java
  • embedded-grafana/src/test/resources/bootstrap.yaml
  • embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/configuration/KafkaContainerConfiguration.java
  • embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/properties/KafkaConfigurationProperties.java
  • embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/properties/SchemaRegistryConfigurationProperties.java
  • embedded-keycloak/pom.xml
  • embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/EmbeddedKeycloakBootstrapConfiguration.java
  • embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/KeycloakContainer.java
  • embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/KeycloakContainerFactory.java
  • embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/KeycloakProperties.java
  • embedded-keycloak/src/test/java/com/playtika/testcontainer/keycloak/spring/EmbeddedKeycloakBootstrapConfigurationTest.java
  • embedded-keycloak/src/test/java/com/playtika/testcontainer/keycloak/util/KeycloakJwtAuthenticationConverter.java
  • embedded-keycloak/src/test/java/com/playtika/testcontainer/keycloak/vanilla/KeycloakContainerTest.java
  • embedded-keydb/src/main/java/com/playtika/testcontainer/keydb/wait/KeyDbClusterStatusCheck.java
  • embedded-memsql/pom.xml
  • embedded-memsql/src/main/java/com/playtika/testcontainer/memsql/EmbeddedMemSqlBootstrapConfiguration.java
  • embedded-memsql/src/main/java/com/playtika/testcontainer/memsql/MemSqlContainer.java
  • embedded-memsql/src/test/java/com/playtika/testcontainer/memsql/EmbeddedMemSqlBootstrapConfigurationTest.java
  • embedded-minio/src/main/java/com/playtika/testcontainer/minio/DefaultMinioWaitStrategy.java
  • embedded-minio/src/main/java/com/playtika/testcontainer/minio/EmbeddedMinioBootstrapConfiguration.java
  • embedded-minio/src/main/java/com/playtika/testcontainer/minio/MinioWaitStrategy.java
  • embedded-minio/src/test/java/com/playtika/testcontainer/minio/EmbeddedMinioBootstrapConfigurationTest.java
  • embedded-mongodb/src/test/java/com/playtika/testcontainer/mongodb/EmbeddedMongodbBootstrapAuthConfigurationTest.java
  • embedded-mongodb/src/test/java/com/playtika/testcontainer/mongodb/EmbeddedMongodbBootstrapConfigurationTest.java
  • embedded-mongodb/src/test/java/com/playtika/testcontainer/mongodb/EmbeddedMongodbBootstrapReplicaSetConfigurationTest.java
  • embedded-native-kafka/src/main/java/com/playtika/testcontainer/nativekafka/configuration/NativeKafkaContainerConfiguration.java
  • embedded-native-kafka/src/test/java/com/playtika/testcontainer/nativekafka/EmbeddedNativeKafkaWithBindingTest.java
  • embedded-native-kafka/src/test/java/com/playtika/testcontainer/nativekafka/NativeKafkaTopicsConfigurerTest.java
  • embedded-nats/README.adoc
  • embedded-nats/pom.xml
  • embedded-nats/src/main/java/com/playtika/testcontainer/nats/EmbeddedNatsBootstrapConfiguration.java
  • embedded-nats/src/test/java/com/playtika/testcontainer/nats/BaseNatsTest.java
  • embedded-neo4j/src/test/java/com/playtika/testcontainer/neo4j/Person.java
  • embedded-redis/src/main/java/com/playtika/testcontainer/redis/wait/RedisClusterStatusCheck.java
  • embedded-selenium/README.adoc
  • embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/EmbeddedSeleniumBootstrapConfiguration.java
  • embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/VncRecordingMode.java
  • embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/testscope/TestcontainerContextCustomizerFactory.java
  • embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/testscope/TestcontainerScope.java
  • embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/testscope/TestcontainerTestExecutionListener.java
  • embedded-temporal/src/test/java/com/playtika/testcontainer/temporal/EmbeddedTemporalBootstrapConfigurationTest.java
  • embedded-vault/src/main/java/com/playtika/testcontainer/vault/EmbeddedVaultBootstrapConfiguration.java
  • embedded-wiremock/README.adoc
  • embedded-wiremock/pom.xml
  • embedded-wiremock/src/main/java/com/playtika/testcontainers/wiremock/EmbeddedWiremockBootstrapConfiguration.java
  • embedded-wiremock/src/main/java/com/playtika/testcontainers/wiremock/WiremockProperties.java
  • testcontainers-common/src/main/java/com/playtika/testcontainer/common/spring/AbstractDependsOnPostProcessor.java
  • testcontainers-common/src/main/java/com/playtika/testcontainer/common/utils/ContainerUtils.java
  • testcontainers-common/src/main/java/com/playtika/testcontainer/common/utils/DateUtils.java
  • testcontainers-common/src/main/java/com/playtika/testcontainer/common/utils/FileUtils.java
  • testcontainers-common/src/test/java/com/playtika/testcontainer/common/utils/ContainerUtilsTest.java
  • testcontainers-common/src/test/java/com/playtika/testcontainer/common/utils/MountVolumesTest.java
💤 Files with no reviewable changes (7)
  • embedded-minio/src/main/java/com/playtika/testcontainer/minio/MinioWaitStrategy.java
  • embedded-memsql/src/test/java/com/playtika/testcontainer/memsql/EmbeddedMemSqlBootstrapConfigurationTest.java
  • embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/KeycloakContainerFactory.java
  • embedded-minio/src/main/java/com/playtika/testcontainer/minio/DefaultMinioWaitStrategy.java
  • embedded-google-storage/src/main/java/com/playtika/testcontainer/storage/GoogleCloudStorageHttpClient.java
  • embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/KeycloakContainer.java
  • embedded-wiremock/src/main/java/com/playtika/testcontainers/wiremock/WiremockProperties.java

Comment on lines +105 to +109
.withCreateContainerCmdModifier(cmd -> {
List<String> args = new ArrayList<>(Arrays.asList(cmd.getCmd()));
args.add("--skipApiVersionCheck");
cmd.withCmd(args);
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether AzuriteContainer in testcontainers-java calls withCommand() internally,
# which would determine if cmd.getCmd() can safely return non-null.
fd -i "AzuriteContainer.java" --exec cat {}

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 64


🏁 Script executed:

fd "EmbeddedAzuriteBootstrapConfiguration.java" --exec cat {}

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 7654


🏁 Script executed:

cd embedded-azurite && find . -name "pom.xml" -o -name "build.gradle" | head -1 | xargs cat | grep -A 5 -i testcontainers

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 1089


🌐 Web query:

testcontainers CreateContainerCmd getCmd() null Docker Java SDK

💡 Result:

No definitive evidence found of CreateContainerCmd.getCmd returning null in Testcontainers or Docker Java SDK under normal usage. The getCmd method in docker-java's CreateContainerCmd interface returns String[] annotated with @CheckForNull, meaning it can be null if no command (CMD) has been set via withCmd [1][2][3][4]. Testcontainers' GenericContainer creates a CreateContainerCmd via dockerClient.createContainerCmd(image) and applies modifiers, including command if withCommand is used [5][6]. If no explicit command is set, getCmd may legitimately return null, as the container uses the image's default CMD [7]. No GitHub issues or docs report getCmd unexpectedly null in Testcontainers contexts, including with Testcontainers Desktop [1-33]. Potential related issues include Docker connection problems [8][9][10] or modifier deadlocks [11], but not getCmd null specifically. Ensure withCommand is called if a custom CMD is needed, or check Docker client initialization.

Citations:


🌐 Web query:

AzuriteContainer testcontainers withCommand entrypoint

💡 Result:

AzuriteContainer is available in multiple Testcontainers libraries for different languages, providing a convenient way to spin up Azurite (Azure Storage emulator) in tests. Official modules handle the default command/entrypoint automatically, matching the Azurite Dockerfile CMD: ["azurite", "-l", "/data", "--blobHost", "0.0.0.0","--queueHost", "0.0.0.0", "--tableHost", "0.0.0.0"][1][2]. To customize using withCommand (overrides CMD) or entrypoint (overrides ENTRYPOINT), use language-specific methods on the AzuriteContainer or underlying GenericContainer: Java (org.testcontainers:azure module): AzuriteContainer extends SingleOffsetMapContainer and configures ports/envs but inherits.withCommand(String... cmd) and.withEntrypoint(String... entrypoint) from GenericContainer[3][4][5]. Example: AzuriteContainer azurite = new AzuriteContainer("mcr.microsoft.com/azure-storage/azurite:3.33.0") .withCommand("azurite", "--loose", "--blobHost", "0.0.0.0") .withExposedPorts(10000, 10001, 10002); azurite.start(); Default usage without custom command: new AzuriteContainer(image).start;[6][5]..NET (Testcontainers.Azurite): Use AzuriteBuilder.WithCommand(params string[] command)[7]. Example for HTTPS: var container = new AzuriteBuilder("mcr.microsoft.com/azure-storage/azurite:latest") .WithCommand("--cert", "/workspace/127.0.0.1.pem", "--key", "/workspace/127.0.0.1-key.pem", "--oauth", "basic") .WithResourceMapping(...) .Build(); [6]. Rust (testcontainers-modules): Azurite implements ImageArgsExt.with_cmd(vec![String])[8]. Example: let azurite = Azurite::default().with_cmd(vec!["azurite".to_owned(), "--loose".to_owned()]).start(); [8]. Python/Node.js: Specialized methods like withSsl internally handle commands; fall back to GenericContainer equivalents[9][10]. For blob-only:.withCommand("azurite-blob", "--blobHost", "0.0.0.0")[2][11]. Expose only needed ports. Official Testcontainers docs prioritize simple new AzuriteContainer.start as it uses correct defaults[12][6][5]. Custom commands needed for options like --loose, custom ports, SSL[9][7].

Citations:


cmd.getCmd() returns null when no command is explicitly set, causing an NPE via Arrays.asList.

The CreateContainerCmd.getCmd() method is annotated with @CheckForNull in the Docker Java SDK, confirming it can return null when no command has been set via withCmd. Since AzuriteContainer does not call withCommand() internally and relies on the image's default CMD, getCmd() returns null when new AzuriteContainer(image) is created without prior customization. Calling Arrays.asList(cmd.getCmd()) on a null input throws a NullPointerException.

Add a null guard to safely handle this case:

Proposed fix
.withCreateContainerCmdModifier(cmd -> {
-    List<String> args = new ArrayList<>(Arrays.asList(cmd.getCmd()));
+    String[] existing = cmd.getCmd();
+    List<String> args = existing != null ? new ArrayList<>(Arrays.asList(existing)) : new ArrayList<>();
     args.add("--skipApiVersionCheck");
     cmd.withCmd(args);
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.withCreateContainerCmdModifier(cmd -> {
List<String> args = new ArrayList<>(Arrays.asList(cmd.getCmd()));
args.add("--skipApiVersionCheck");
cmd.withCmd(args);
});
.withCreateContainerCmdModifier(cmd -> {
String[] existing = cmd.getCmd();
List<String> args = existing != null ? new ArrayList<>(Arrays.asList(existing)) : new ArrayList<>();
args.add("--skipApiVersionCheck");
cmd.withCmd(args);
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-azurite/src/main/java/com/playtika/testcontainer/azurite/EmbeddedAzuriteBootstrapConfiguration.java`
around lines 105 - 109, The lambda passed to withCreateContainerCmdModifier uses
Arrays.asList(cmd.getCmd()) which throws NPE because CreateContainerCmd.getCmd()
can be null; update the modifier in EmbeddedAzuriteBootstrapConfiguration so it
first checks cmd.getCmd() for null and builds the args list accordingly (e.g.,
start from an empty List if null or new ArrayList<>(Arrays.asList(cmd.getCmd()))
if non-null), then add "--skipApiVersionCheck" and call cmd.withCmd(args) as
before; reference the CreateContainerCmd instance named cmd and the existing
cmd.withCmd(...) call when making the change.

Comment on lines +30 to +39
* `embedded.grafana.filesToInclude` Classpath resources to copy into the container at startup. Use this to provision custom Grafana datasources, dashboards, or alert rules. Example `bootstrap.yaml`:

[source,yaml]
----
embedded:
grafana:
filesToInclude:
- classpathResource: /embedded/grafana/provisioning/datasources/my-datasource.yml
containerPath: /etc/grafana/provisioning/datasources/my-datasource.yml
----
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

grafana otel-lgtm image grafana provisioning datasources path location

💡 Result:

In the grafana/otel-lgtm Docker image, Grafana provisioning files for datasources are located at /otel-lgtm/grafana/conf/provisioning/datasources/. The default datasource configuration file is grafana-datasources.yaml, which provisions Prometheus, Tempo, Loki, and Pyroscope datasources.[1][2][3] This follows standard Grafana provisioning conventions, where YAML files in the provisioning/datasources directory define datasources.[4] For dashboards, provisioning files are at /otel-lgtm/grafana/conf/provisioning/dashboards/, with examples like grafana-dashboards.yaml.[5][2][6] To customize, mount your own YAML files into these paths via Docker volumes, as shown in the repo examples for dashboards (analogous for datasources).[5] Grafana data is at /data/grafana (overridable via GF_PATHS_DATA), but provisioning configs are in the fixed /otel-lgtm/grafana/conf/provisioning structure.[7]

Citations:


Update the filesToInclude example to use the correct provisioning path for otel-lgtm.

The example path /etc/grafana/provisioning/datasources/my-datasource.yml is the standard Grafana OSS location, but the grafana/otel-lgtm image uses a custom bundled layout. Change the example to /otel-lgtm/grafana/conf/provisioning/datasources/my-datasource.yml so users who copy it will actually provision datasources correctly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@embedded-grafana/README.adoc` around lines 30 - 39, The example under
embedded.grafana.filesToInclude uses the standard Grafana path which is
incorrect for the grafana/otel-lgtm image; update the containerPath value in the
example to the otel-lgtm provisioning location
(/otel-lgtm/grafana/conf/provisioning/datasources/my-datasource.yml) so that
embedded.grafana.filesToInclude points classpath resources into the correct
otel-lgtm container provisioning directory.

Comment thread embedded-keycloak/pom.xml Outdated
Comment on lines +17 to +18
<!-- renovate: datasource=github-releases depName=dasniko/testcontainers-keycloak -->
<testcontainers-keycloak.version>3.3.0</testcontainers-keycloak.version>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the embedded-keycloak/pom.xml file
cat -n embedded-keycloak/pom.xml | head -40

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 1958


🏁 Script executed:

# Check the KeycloakProperties.java file for the image version
find . -name "KeycloakProperties.java" -type f

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 176


🏁 Script executed:

# Check the parent POM for Testcontainers version
find . -name "pom.xml" -type f -path "*/testcontainers-*" | head -5
cat pom.xml | grep -A 5 -B 5 "testcontainers" | head -40

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 1846


🌐 Web query:

testcontainers-keycloak 3.3.0 compatibility Keycloak Testcontainers version matrix

💡 Result:

testcontainers-keycloak version 3.3.0 (released around March 2024 [1]) is compatible with Keycloak 24.0, as per the official version matrix in the project's docs [2]. It uses Testcontainers 1.19.6 [2]. The full version compatibility matrix from the official docs/versions.md [2] is: | Testcontainers-Keycloak | Testcontainers | Keycloak | |-------------------------|----------------|----------| | 4.2.x | 2.0.4 | 26.6 | | 4.1.x | 2.0.3 | 26.5 | | 4.0.x (Docker 29+) | 2.0.2 | 26.4 | | 3.9.x | 1.21.3 | 26.4 | | 3.8.x | 1.21.3 | 26.3 | | 3.7.x | 1.20.6 | 26.2 | | 3.6.x | 1.20.4 | 26.1 | | 3.5.x | 1.20.2 | 26.0 | | 3.4.x | 1.19.8 | 25.0 | | 3.3.x | 1.19.6 | 24.0 | | 3.2.x | 1.19.3 | 23.0 | | 3.1.x | 1.18.3 | 22.0.5 | | 3.0.x | 1.18.3 | 22.0 | A GitHub issue [3] groups 3.0.x-3.3.x as supporting Keycloak 22.x-25.x, which aligns with the matrix since 3.3.x defaults to 24.0 but may support the range via custom images. Newer versions like 3.4.x require Keycloak 25.x+ due to wait strategy changes [3], and 3.5.x requires 26.x+ [3]. The repo README notes version 3.x handles Keycloak 22.x and up [4]. By default, it uses quay.io/keycloak/keycloak:24.0 [2].

Citations:


🏁 Script executed:

# Read KeycloakProperties.java to find the image version
cat embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/KeycloakProperties.java | grep -A 2 -B 2 "image\|25\.0\|keycloak:" | head -20

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 225


🏁 Script executed:

# Check testcontainers-spring-boot-parent/pom.xml for Testcontainers version
cat -n testcontainers-spring-boot-parent/pom.xml | grep -A 5 -B 5 "testcontainers.version" | head -30

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 64


🏁 Script executed:

# Also check what Testcontainers version is in the parent or BOM
rg "testcontainers" testcontainers-spring-boot-parent/pom.xml -A 2 -B 2

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 1488


🏁 Script executed:

# Check the full testcontainers-spring-boot-parent/pom.xml for version properties
cat testcontainers-spring-boot-parent/pom.xml | head -100

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 4481


🏁 Script executed:

# Look for testcontainers BOM import or version in the parent
rg "org.testcontainers" testcontainers-spring-boot-parent/pom.xml -B 2 -A 5

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 382


🏁 Script executed:

# Check full parent pom.xml for any testcontainers BOM import
cat testcontainers-spring-boot-parent/pom.xml | grep -A 10 "testcontainers"

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 2451


🏁 Script executed:

# Check BOM pom.xml for testcontainers configuration
cat testcontainers-spring-boot-bom/pom.xml | head -100

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 4496


🌐 Web query:

Spring Boot 4.0.6 testcontainers version dependency

💡 Result:

For Spring Boot 4.0.6, the Testcontainers dependency version managed by the Spring Boot BOM (spring-boot-dependencies) is 2.0.5. This is confirmed in the official release notes for v4.0.6, which explicitly state "Upgrade to Testcontainers 2.0.5 #50135" [1]. Spring Boot manages third-party dependencies like Testcontainers (org.testcontainers:testcontainers) through its BOM, so when using Spring Boot 4.0.6 as the parent or importing the BOM, Testcontainers is aligned to this version without needing an explicit version declaration. To use Testcontainers support in tests with Spring Boot 4.0.6, add the test-scoped dependency: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-testcontainers</artifactId> <scope>test</scope> </dependency> The spring-boot-testcontainers artifact itself is version 4.0.6 (aligned with Spring Boot), and it depends on org.testcontainers:testcontainers 2.0.5 as managed [2][1]. Official docs recommend spring-boot-testcontainers for @ServiceConnection with Testcontainers [3]. Spring Boot 4.0.6 was released on 2026-04-23 [1][4].

Citations:


Upgrade testcontainers-keycloak to align with Keycloak 25.0.6 and Testcontainers 2.x baseline.

testcontainers-keycloak 3.3.0 is designed for Keycloak 24.0 and Testcontainers 1.19.6, but this module defaults to Keycloak 25.0.6 and the repo parent manages Testcontainers 2.0.5 (via Spring Boot 4.0.6). This mismatch is likely to cause startup or API breakage. Consider upgrading to a compatible version—e.g., 3.4.x (Keycloak 25.0, Testcontainers 1.19.8) or 4.x (Keycloak 26.x, Testcontainers 2.x, requires Docker 29+), potentially paired with a corresponding Keycloak image update.

Affected locations

Lines 17-18, 31-33

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@embedded-keycloak/pom.xml` around lines 17 - 18, The POM pins
testcontainers-keycloak.version to 3.3.0 which targets Keycloak 24 and
Testcontainers 1.19.6; update the testcontainers-keycloak.version property
(reference: testcontainers-keycloak.version) to a compatible release (e.g.,
3.4.x if you want Keycloak 25.x compatibility or 4.x if you plan to move to
Keycloak 26+/Testcontainers 2.x), and also align any Keycloak docker image tags
and the Testcontainers baseline managed by the parent (Spring Boot) so the
testcontainers-keycloak client, Keycloak image tag and Testcontainers runtime
are mutually compatible before running tests.

Comment on lines +63 to +79
public KeycloakContainer keycloakContainer(ConfigurableEnvironment environment,
KeycloakProperties properties,
ResourceLoader resourceLoader,
Optional<Network> network) {
KeycloakContainer keycloak = new KeycloakContainer(ContainerUtils.getDockerImageName(properties).toString())
.withNetworkAliases(KEYCLOAK_NETWORK_ALIAS)
.withAdminUsername(properties.getAdminUser())
.withAdminPassword(properties.getAdminPassword());

applyDbConfig(keycloak, properties);
applyImportFile(keycloak, properties, resourceLoader);

network.ifPresent(keycloak::withNetwork);

keycloak = (KeycloakContainer) configureCommonsAndStart(keycloak, properties, log);
registerEnvironment(keycloak, environment, properties);
return keycloak;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

find . -name "EmbeddedKeycloakBootstrapConfiguration.java" -type f

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 196


🏁 Script executed:

find . -name "KeycloakProperties.java" -type f

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 176


🏁 Script executed:

find . -name "*.java" -path "*keycloak*" | head -20

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 1358


🏁 Script executed:

wc -l ./embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/EmbeddedKeycloakBootstrapConfiguration.java

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 200


🏁 Script executed:

cat -n ./embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/EmbeddedKeycloakBootstrapConfiguration.java

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 8972


🏁 Script executed:

cat -n ./embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/KeycloakProperties.java

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 3621


🏁 Script executed:

find ./embedded-keycloak -name "pom.xml" -type f

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 110


🏁 Script executed:

cat ./embedded-keycloak/pom.xml | grep -A 5 -B 5 "dasniko"

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 820


🌐 Web query:

dasniko testcontainers-keycloak 3.3.0 withContextPath getAuthServerUrl

💡 Result:

In dasniko/testcontainers-keycloak 3.3.0, KeycloakContainer.getAuthServerUrl appends the configured context path (KEYCLOAK_CONTEXT_PATH) to the returned auth server URL. If you do not change the context path (default is “/”), the returned URL ends with a trailing “/”. [1][2][3] What this means for withContextPath - If you call.withContextPath("/auth"), then getAuthServerUrl ends with "/auth" (so you should use keycloak.getAuthServerUrl as-is when building endpoints like.../realms/{realm}/...). This behavior is explicitly tested for a non-default context path. [3] - If you do not modify the context path (default “/”), then getAuthServerUrl ends with “/”. A known issue is that this can lead to double-slash problems when consumers build URLs by concatenation; the project discusses that getAuthServerUrl ends with the context path and that the default “/” causes a trailing “/”. [1] Quick example (issuer-uri construction) - Use string concatenation exactly once, e.g. registry.add("...issuer-uri", -> keycloak.getAuthServerUrl + "/realms/test"); (the official README example does this). [2] Sources: [1][2][3]

Citations:


🌐 Web query:

dasniko testcontainers-keycloak KeycloakContainer API documentation 3.3.0

💡 Result:

The official API documentation for the KeycloakContainer class in dasniko/testcontainers-keycloak version 3.3.0 is available in the project's Javadoc JAR, published to Maven Central [1][2]. Download testcontainers-keycloak-3.3.0-javadoc.jar from https://repo1.maven.org/maven2/com/github/dasniko/testcontainers-keycloak/3.3.0/testcontainers-keycloak-3.3.0-javadoc.jar [2] and extract it to view the full API docs, including dasniko.testcontainers.keycloak.KeycloakContainer. No hosted online Javadoc specific to 3.3.0 was found; current javadoc.io hosts latest version (4.1.1+) [3]. The primary usage and method documentation is in the GitHub README [4][5], which covers version 3.3.0 features like withDefaultProviderClasses added in 3.3 [4]. Key methods and usage from README and tests [4][6][7]: - Constructors: new KeycloakContainer (default, deprecated in later versions) [4]; new KeycloakContainer(String imageName) e.g., new KeycloakContainer("quay.io/keycloak/keycloak:26.4") [4]. - withRealmImportFile(String path) - Import realm JSON from classpath [6][7]. - withRealmImportFiles(String... paths) - Multiple realms [6]. - withProviderClassesFrom(String... classpaths) or withDefaultProviderClasses (since 3.3) - Add custom providers [8][4]. - withContextPath(String path) e.g., "/auth" [4]. - getAuthServerUrl - Returns http(s)://host:port/contextPath/realms [4][6]. - getKeycloakAdminClient - Returns org.keycloak.admin.Keycloak instance with admin credentials [4]. - withAdminPassword(String password) - Set admin password [6]. - withStartupTimeout(Duration) [6]. - withCustomCommand(String... parts) - Added around 3.4, may be available [8]. - useTls, withOptimizedFlag, etc. [9]. Full source code is viewable on GitHub main branch (post-3.3.0, minor changes) at https://github.com/dasniko/testcontainers-keycloak/blob/main/src/main/java/dasniko/testcontainers/keycloak/KeycloakContainer.java (inferred path from tests [6]). For exact 3.3.0 source, check tag v3.3.0 [10][11]. Example usage [4][7]: `@Container` KeycloakContainer keycloak = new KeycloakContainer("quay.io/keycloak/keycloak:25.0") .withRealmImportFile("test-realm.json"); keycloak.start(); String authServerUrl = keycloak.getAuthServerUrl(); Keycloak admin = keycloak.getKeycloakAdminClient(); Version 3.3.0 released 2024-03-04 [1][12].

Citations:


🏁 Script executed:

rg "withContextPath|getAuthServerUrl" ./embedded-keycloak --type java

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 64


🏁 Script executed:

rg "getAuthServerUrl" . --type java

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 64


🏁 Script executed:

rg "withContextPath" . --type java

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 64


🏁 Script executed:

grep -n "authBasePath" ./embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/EmbeddedKeycloakBootstrapConfiguration.java

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 64


🏁 Script executed:

grep -n "getAuthBasePath" ./embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/EmbeddedKeycloakBootstrapConfiguration.java

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 201


Wire authBasePath into the container using withContextPath(...), not just the exported property.

authBasePath is only used when composing embedded.keycloak.auth-server-url (line 150), so a non-default value like /auth will publish an /auth URL even though the container is still started on /. The dasniko container provides withContextPath(...) to configure the context path and getAuthServerUrl() to retrieve the resolved auth server URL, which should be used instead of manual URL composition.

  • Add .withContextPath(properties.getAuthBasePath()) to the container initialization (line 67-70)
  • Replace the manual buildAuthServerUrl(...) call with keycloak.getAuthServerUrl() (line 134)
Suggested changes
         KeycloakContainer keycloak = new KeycloakContainer(ContainerUtils.getDockerImageName(properties).toString())
                 .withNetworkAliases(KEYCLOAK_NETWORK_ALIAS)
+                .withContextPath(properties.getAuthBasePath())
                 .withAdminUsername(properties.getAdminUser())
                 .withAdminPassword(properties.getAdminPassword());
-        String authServerUrl = buildAuthServerUrl(keycloak, properties);
+        String authServerUrl = keycloak.getAuthServerUrl();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/EmbeddedKeycloakBootstrapConfiguration.java`
around lines 63 - 79, The container is not started with the configured context
path and the auth URL is being composed manually; update the KeycloakContainer
creation in keycloakContainer(...) to call
.withContextPath(properties.getAuthBasePath()) on the KeycloakContainer
instance, and after starting/configuring the container (i.e., after
configureCommonsAndStart(...)) replace any manual buildAuthServerUrl(...) usage
with keycloak.getAuthServerUrl() when registering/exporting the
embedded.keycloak.auth-server-url in registerEnvironment(...), ensuring
KeycloakContainer.getAuthServerUrl() is used to obtain the resolved URL.

Comment on lines +82 to +109
private void applyDbConfig(KeycloakContainer keycloak, KeycloakProperties properties) {
if (properties.getDbVendor() != null) {
keycloak.withEnv("DB", properties.getDbVendor());
}
if (properties.getDbAddr() != null) {
keycloak.withEnv("DB_URL_HOST", properties.getDbAddr());
}
if (properties.getDbPort() != null) {
keycloak.withEnv("DB_URL_PORT", properties.getDbPort());
}
if (properties.getDbDatabase() != null) {
keycloak.withEnv("DB_URL_DATABASE", properties.getDbDatabase());
}
if (properties.getDbSchema() != null) {
keycloak.withEnv("DB_SCHEMA", properties.getDbSchema());
}
if (properties.getDbUser() != null) {
keycloak.withEnv("DB_USERNAME", properties.getDbUser());
}
if (properties.getDbUserFile() != null) {
keycloak.withEnv("DB_USER_FILE", properties.getDbUserFile());
}
if (properties.getDbPassword() != null) {
keycloak.withEnv("DB_PASSWORD", properties.getDbPassword());
}
if (properties.getDbPasswordFile() != null) {
keycloak.withEnv("DB_PASSWORD_FILE", properties.getDbPasswordFile());
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Keycloak 25 database environment variables KC_DB documentation

💡 Result:

In Keycloak 25, database configuration via environment variables uses the KC_DB_* format, corresponding to CLI options and keycloak.conf properties. This has not changed from previous versions based on official documentation and release notes [1][2][3]. Key KC_DB environment variables for the main (default) datasource include: - KC_DB: Specifies the database vendor (e.g., postgres, mariadb, mysql, mssql, oracle, dev-file). CLI: --db, default: dev-file (deprecated in production) [1][4]. - KC_DB_USERNAME: Database username. CLI: --db-username [1][5]. - KC_DB_PASSWORD: Database password. Use KCRAW_DB_PASSWORD if password contains $ or ${...} to preserve literals [1][6]. - KC_DB_URL: Full JDBC URL (overrides host/database/port). CLI: --db-url [1][4]. - KC_DB_URL_HOST: Database host. CLI: --db-url-host [1]. - KC_DB_URL_PORT: Database port. CLI: --db-url-port [1]. - KC_DB_URL_DATABASE: Database name. CLI: --db-url-database [1]. - KC_DB_SCHEMA: Database schema (default: keycloak for most DBs). CLI: --db-schema [1][5]. Additional pool/options: - KC_DB_POOL_MIN_SIZE, KC_DB_POOL_MAX_SIZE: Connection pool sizes [4]. - KC_DB_CONNECT_TIMEOUT: Connection timeout in milliseconds [4]. - KC_TRANSACTION_XA_ENABLED: Enable XA transactions (default: true) [5]. Examples from docs [1][5]: For Docker/container: ENV KC_DB=postgres ENV KC_DB_URL_HOST=keycloak-postgres ENV KC_DB_USERNAME=keycloak ENV KC_DB_PASSWORD=change_me Configuration can be set at build or start steps. In production, explicitly set KC_DB (dev-file unsuitable) [1]. For passwords with special chars, use KCRAW_ prefix [1][6]. Full list at https://www.keycloak.org/server/all-config [4]. No breaking DB env var changes in Keycloak 25 release notes [2][3][7].

Citations:


🌐 Web query:

Keycloak Quarkus database configuration environment variables KC_DB_USERNAME KC_DB_PASSWORD

💡 Result:

Environment variables for Keycloak (Quarkus distribution) database credentials are: 1) KC_DB_USERNAME - Maps to the Keycloak database config option db-username, exposed as environment variable KC_DB_USERNAME [1]. 2) KC_DB_PASSWORD - Maps to the Keycloak database config option db-password, exposed as environment variable KC_DB_PASSWORD [1]. Notes (important when using env vars) - If your DB password contains $ or ${…} characters, Keycloak documentation says to use the KCRAW_DB_PASSWORD environment variable instead of KC_DB_PASSWORD so the value is preserved as-is [2][3]. - Configuration via environment variables is supported as an alternative to configuring via conf/keycloak.conf or CLI args [2]. Example (PostgreSQL) export KC_DB=postgres export KC_DB_URL_HOST=keycloak-postgres export KC_DB_USERNAME=keycloak export KC_DB_PASSWORD='change_me' [2][4][1] If you want, tell me your database type (postgres/mysql/mssql/oracle) and whether you run kc.sh build before kc.sh start, and I can suggest the exact minimal set of env vars for your setup.

Citations:


🌐 Web query:

Keycloak 25 DB_USER_FILE DB_PASSWORD_FILE environment variable support

💡 Result:

Keycloak 25 does not natively support DB_USER_FILE or DB_PASSWORD_FILE environment variables for reading database credentials from files. Official documentation lists the environment variable for database password as KC_DB_PASSWORD and for username as KC_DB_USERNAME, with no mention of *_FILE variants [1][2][3][4]. A feature request for general *_FILE support exists but remains open without implementation [5]. The kc.sh script does not process *_FILE variables [6].

Citations:


Use the Keycloak 25 KC_* database env keys instead of legacy DB_* variables.

The code currently uses unprefixed DB* variables, which are not the documented or supported environment variables in Keycloak 25. The official Keycloak documentation specifies the proper keys as KC_DB, KC_DB_URL_HOST, KC_DB_URL_PORT, KC_DB_URL_DATABASE, KC_DB_SCHEMA, KC_DB_USERNAME, and KC_DB_PASSWORD. Configuration using the current DB* names will not be applied and Keycloak will fall back to its defaults.

Additionally, Keycloak does not support *_FILE variants for reading credentials from files. The DB_USER_FILE and DB_PASSWORD_FILE branches need alternative implementations, such as reading the file contents in this configuration method and passing them directly via KC_DB_USERNAME and KC_DB_PASSWORD, or using Docker secrets/volume mounts with a custom entrypoint.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/EmbeddedKeycloakBootstrapConfiguration.java`
around lines 82 - 109, The applyDbConfig method in
EmbeddedKeycloakBootstrapConfiguration is setting legacy DB_* env vars; change
it to set the Keycloak 25 names (e.g. KC_DB, KC_DB_URL_HOST, KC_DB_URL_PORT,
KC_DB_URL_DATABASE, KC_DB_SCHEMA, KC_DB_USERNAME, KC_DB_PASSWORD) on the
KeycloakContainer instead of DB_*; remove emitting DB_USER_FILE/DB_PASSWORD_FILE
env vars and, when KeycloakProperties.getDbUserFile() or getDbPasswordFile() is
provided, read those files' contents inside applyDbConfig and set the
corresponding KC_DB_USERNAME / KC_DB_PASSWORD values on the KeycloakContainer
(or fall back to getDbUser()/getDbPassword() if present), ensuring no *_FILE env
vars are passed to the container. Reference: applyDbConfig(KeycloakContainer,
KeycloakProperties), KeycloakContainer.withEnv(...),
KeycloakProperties.getDbUserFile()/getDbPasswordFile()/getDbUser()/getDbPassword().

Comment on lines +28 to +31
public MemSqlContainer withUsername(String username) {
this.username = username;
return self();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

withUsername currently allows credentials the container never provisions

Line 28 accepts any username, but Line 45-53 only configures root credentials, while Line 66 returns the custom username. This can produce unreachable credentials (jdbcUrl + username/password that cannot authenticate).

Proposed fix (fail fast unless root is used)
 public MemSqlContainer withUsername(String username) {
-    this.username = username;
+    if (!"root".equals(username)) {
+        throw new IllegalArgumentException("MemSqlContainer currently supports only 'root' username");
+    }
+    this.username = username;
     return self();
 }

Also applies to: 45-53, 66-68

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-memsql/src/main/java/com/playtika/testcontainer/memsql/MemSqlContainer.java`
around lines 28 - 31, The withUsername method in MemSqlContainer currently
accepts arbitrary usernames while the container only provisions root
credentials, causing unreachable credentials; update withUsername(String
username) in class MemSqlContainer to validate input and fail fast by throwing
an IllegalArgumentException (or IllegalStateException) if the caller passes a
non-root username (i.e., anything other than "root"), or alternatively implement
user provisioning in the container configuration flow (the configure/start
methods) to create the requested user; reference the withUsername method and the
container configuration/start logic (where root credentials are set) and ensure
getUsername/getPassword/getJdbcUrl return only credentials that the container
actually provisions.

Comment on lines 100 to 102
private static String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = new java.util.Scanner(is, StandardCharsets.UTF_8.name()).useDelimiter("\\A");
java.util.Scanner s = new java.util.Scanner(is, StandardCharsets.UTF_8).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Close stream/scanner in convertStreamToString to avoid leaked resources.

This helper creates a Scanner over an InputStream and never closes either. In repeated test runs this can leak response streams.

Suggested fix
-    private static String convertStreamToString(java.io.InputStream is) {
-        java.util.Scanner s = new java.util.Scanner(is, StandardCharsets.UTF_8).useDelimiter("\\A");
-        return s.hasNext() ? s.next() : "";
-    }
+    private static String convertStreamToString(java.io.InputStream is) {
+        try (java.io.InputStream in = is;
+             java.util.Scanner s = new java.util.Scanner(in, StandardCharsets.UTF_8).useDelimiter("\\A")) {
+            return s.hasNext() ? s.next() : "";
+        }
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-minio/src/test/java/com/playtika/testcontainer/minio/EmbeddedMinioBootstrapConfigurationTest.java`
around lines 100 - 102, The convertStreamToString helper creates a Scanner over
the provided InputStream but never closes it, leaking resources; update
convertStreamToString to use a try-with-resources (or explicitly close) for the
Scanner (which will also close the InputStream) so the Scanner and underlying
stream are always closed after reading, and return the same string result;
reference: convertStreamToString(java.io.InputStream).

Comment thread embedded-selenium/README.adoc
Comment thread embedded-wiremock/pom.xml

<properties>
<wiremock.version>3.13.2</wiremock.version>
<wiremock-testcontainers-module.version>1.0-alpha-13</wiremock-testcontainers-module.version>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, let's find and read the pom.xml file mentioned
find . -name "pom.xml" -path "*/embedded-wiremock/*" | head -20

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 110


🏁 Script executed:

# Read the embedded-wiremock/pom.xml file to verify line 18
cat -n embedded-wiremock/pom.xml | sed -n '15,25p'

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 530


🌐 Web query:

wiremock-testcontainers-module latest version Maven Central 2025

💡 Result:

The latest version of wiremock-testcontainers-module on Maven Central is 1.0-alpha-15, released on 2025-03-30 [1][2][3]. This is confirmed by the official Maven Central artifact page, GitHub packages, and repository, with no newer versions listed as of 2026-05-07 [1][4][2][5]. Maven dependency: <dependency><groupId>org.wiremock.integrations.testcontainers</groupId><artifactId>wiremock-testcontainers-module</artifactId><version>1.0-alpha-15</version><scope>test</scope></dependency> [1][3].

Citations:


Update wiremock-testcontainers-module from 1.0-alpha-13 to 1.0-alpha-15.

The current version is two alpha releases behind the latest available version on Maven Central. Upgrading captures bug fixes and potential Testcontainers compatibility improvements from alpha-14 and alpha-15.

Proposed update
-<wiremock-testcontainers-module.version>1.0-alpha-13</wiremock-testcontainers-module.version>
+<wiremock-testcontainers-module.version>1.0-alpha-15</wiremock-testcontainers-module.version>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@embedded-wiremock/pom.xml` at line 18, Update the
wiremock-testcontainers-module version property value from 1.0-alpha-13 to
1.0-alpha-15 in the Maven POM by changing the
<wiremock-testcontainers-module.version> property (the property named
wiremock-testcontainers-module.version) so the project uses the newer alpha-15
release; then run a quick mvn -U test or dependency:resolve to ensure the new
artifact resolves and adjust any failing tests if API/behavior changed.

Comment on lines 86 to 88
for (MountVolume mountVolume : properties.getMountVolumes()) {
updatedContainer.addFileSystemBind(mountVolume.getHostPath(), mountVolume.getContainerPath(), mountVolume.getMode());
updatedContainer.withCopyToContainer(MountableFile.forHostPath(mountVolume.getHostPath()), mountVolume.getContainerPath());
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

addFileSystemBindwithCopyToContainer is a breaking semantic change and causes the CI failure.

withCopyToContainer copies files into the container once at startup (one-way); it does not create a live bind-mount. This has two direct consequences:

  1. BindMode is silently droppedREAD_WRITE callers (e.g., a pgdata volume intended for persistence) will no longer see writes reflected on the host.
  2. getBinds() now returns an empty list, directly causing the pipeline failure in ContainerUtilsTest.configureCommonsAndStart at line 88 (Expected size: 2 but was: 0).

Additionally, the return value of withCopyToContainer is not captured (unlike the withCopyFileToContainer call at line 83), which is a stylistic inconsistency (though harmless since GenericContainer mutates in-place).

If the intent is to keep bind-mount semantics, revert to addFileSystemBind:

🐛 Proposed fix — restore bind-mount semantics and fix return-value capture
 for (MountVolume mountVolume : properties.getMountVolumes()) {
-    updatedContainer.withCopyToContainer(MountableFile.forHostPath(mountVolume.getHostPath()), mountVolume.getContainerPath());
+    updatedContainer = updatedContainer.withFileSystemBind(mountVolume.getHostPath(), mountVolume.getContainerPath(), mountVolume.getMode());
 }

If withCopyToContainer is intentional (e.g., to support read-only container filesystems), the test assertions in ContainerUtilsTest lines 82–89 must be rewritten to verify getCopyToFileContainerPathMap() instead of getBinds(), and MountVolume.getMode() should either be removed or have its ignored state documented.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@testcontainers-common/src/main/java/com/playtika/testcontainer/common/utils/ContainerUtils.java`
around lines 86 - 88, The change from addFileSystemBind to withCopyToContainer
breaks bind-mount semantics and drops BindMode and getBinds(); revert the loop
in ContainerUtils that iterates properties.getMountVolumes() to call
addFileSystemBind(...) (using mountVolume.getHostPath(),
mountVolume.getContainerPath(), and mountVolume.getMode()) instead of
withCopyToContainer, and capture the returned GenericContainer into
updatedContainer (consistent with the withCopyFileToContainer usage) so binds
and modes are preserved and tests like
ContainerUtilsTest.configureCommonsAndStart still see getBinds(); if you
intentionally wanted one-way copy instead, update ContainerUtilsTest to assert
getCopyToFileContainerPathMap() and remove/annotate MountVolume.getMode() as
ignored.

}

return String.join(",", servers);
protected void containerIsStarting(InspectContainerResponse containerInfo) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change is driven by the migration from KafkaContainer to ConfluentKafkaContainer. These two classes use different extension mechanisms: Old KafkaContainer — exposed getBootstrapServers() as the override point. Overriding it let you control what address string clients receive when they ask "where is Kafka?"
New ConfluentKafkaContainer — uses an entrypoint script pattern. The container's startup script is /tmp/testcontainers_start.sh, which sets KAFKA_ADVERTISED_LISTENERS as an env var before launching Kafka's actual process (/etc/confluent/docker/run). containerIsStarting(InspectContainerResponse) is a lifecycle hook on GenericContainer that fires after the container is created and ports are mapped, but before the wait strategy runs. This is exactly the right moment to write the startup script — at this point getMappedPort() is available (so you know the actual host ports), but Kafka hasn't launched yet (so the script will be read before Kafka starts).
In short: getBootstrapServers() no longer exists as an override point on ConfluentKafkaContainer, so the equivalent configuration had to move to containerIsStarting() where you write the KAFKA_ADVERTISED_LISTENERS value into the startup script that Confluent's Docker image reads on launch.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/configuration/KafkaContainerConfiguration.java (1)

233-243: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

withCopyToContainer drops the fileSystemBind persistence behavior.

This is now a one-way snapshot taken before startup, not a writable host mount. Kafka/ZooKeeper writes will stay inside the container, so the embedded.*.fileSystemBind paths created here will remain empty and the existing persistence contract is broken. Please keep these paths mounted read/write instead of copied.

Also applies to: 246-263

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/configuration/KafkaContainerConfiguration.java`
around lines 233 - 243, The code currently uses withCopyToContainer which
snapshots files into the container and breaks the intended persistent read/write
mount behavior; replace the withCopyToContainer calls in
KafkaContainerConfiguration.kafkaFileSystemBind and the analogous Zookeeper bind
block (lines ~246-263) with testcontainers' bind mount API (e.g.,
GenericContainer/ConfluentKafkaContainer.withFileSystemBind or
withFileSystemBind(hostPath, containerPath, BindMode.RW)) so the host kafkaData
path is mounted into the container as a read/write volume (keep
createPathAndParentOrMakeWritable(kafkaData) as-is and use BindMode.RW). Ensure
you reference the same container paths ("/var/lib/kafka/data" and the Zookeeper
container path) and import/namespace BindMode if required.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/configuration/KafkaContainerConfiguration.java`:
- Around line 233-243: The code currently uses withCopyToContainer which
snapshots files into the container and breaks the intended persistent read/write
mount behavior; replace the withCopyToContainer calls in
KafkaContainerConfiguration.kafkaFileSystemBind and the analogous Zookeeper bind
block (lines ~246-263) with testcontainers' bind mount API (e.g.,
GenericContainer/ConfluentKafkaContainer.withFileSystemBind or
withFileSystemBind(hostPath, containerPath, BindMode.RW)) so the host kafkaData
path is mounted into the container as a read/write volume (keep
createPathAndParentOrMakeWritable(kafkaData) as-is and use BindMode.RW). Ensure
you reference the same container paths ("/var/lib/kafka/data" and the Zookeeper
container path) and import/namespace BindMode if required.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: da0f235f-da41-4938-a6fc-3cebc0b606b3

📥 Commits

Reviewing files that changed from the base of the PR and between ba943f3 and 528c5eb.

📒 Files selected for processing (1)
  • embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/configuration/KafkaContainerConfiguration.java

@ijusti ijusti force-pushed the feature/org-testcontainers branch from 528c5eb to fef2ab8 Compare May 11, 2026 13:21
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
testcontainers-common/src/test/java/com/playtika/testcontainer/common/utils/ContainerUtilsTest.java (1)

96-101: 💤 Low value

Reflection on this private Testcontainers field is an intentional testing pattern, but extraction remains worthwhile.

The field copyToTransferableContainerPathMap is internal to GenericContainer and annotated @VisibleForTesting, indicating deliberate design by Testcontainers for test access. There is no public API to inspect this map (the public withCopyToContainer() method only writes to it), so reflection here is the only practical approach. That said, consider extracting this helper into a shared test utility so future Testcontainers API changes require updates in only one place. The existing NoSuchFieldException handling is sufficient.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@testcontainers-common/src/test/java/com/playtika/testcontainer/common/utils/ContainerUtilsTest.java`
around lines 96 - 101, Extract the reflection helper
getCopyToTransferableContainerPathMap into a shared test utility class (e.g.,
TestcontainerReflectionUtils) so all tests reuse a single implementation; the
method should still use reflection to access GenericContainer's private field
copyToTransferableContainerPathMap, keep the same `@SuppressWarnings` and
NoSuchFieldException/reflective access handling, and update callers (like the
current EchoContainer test) to call
TestcontainerReflectionUtils.getCopyToTransferableContainerPathMap(container) to
centralize future maintenance when Testcontainers internals change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/configuration/KafkaContainerConfiguration.java`:
- Line 226: The zookeperFileSystemBind(...) call and setting
withEnv("ZOOKEEPER_SASL_ENABLED", "false") are ineffective for
ConfluentKafkaContainer running in KRaft mode; remove the
zookeperFileSystemBind(...) invocation and the ZOOKEEPER_SASL_ENABLED env set
from KafkaContainerConfiguration (and clean up related
ZookeeperConfigurationProperties.FileSystemBind usage) OR keep the property for
compatibility but add a clear warning when zookeeperFileSystemBind.isEnabled()
is true (log via the class logger in KafkaContainerConfiguration stating the
setting is ignored under KRaft); also add a brief migration note to the
changelog if you remove the feature.

---

Nitpick comments:
In
`@testcontainers-common/src/test/java/com/playtika/testcontainer/common/utils/ContainerUtilsTest.java`:
- Around line 96-101: Extract the reflection helper
getCopyToTransferableContainerPathMap into a shared test utility class (e.g.,
TestcontainerReflectionUtils) so all tests reuse a single implementation; the
method should still use reflection to access GenericContainer's private field
copyToTransferableContainerPathMap, keep the same `@SuppressWarnings` and
NoSuchFieldException/reflective access handling, and update callers (like the
current EchoContainer test) to call
TestcontainerReflectionUtils.getCopyToTransferableContainerPathMap(container) to
centralize future maintenance when Testcontainers internals change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d012582c-6f1b-497d-9856-228bd0a67729

📥 Commits

Reviewing files that changed from the base of the PR and between 528c5eb and fef2ab8.

📒 Files selected for processing (71)
  • embedded-aerospike/src/main/java/com/playtika/testcontainer/aerospike/AerospikeTestOperations.java
  • embedded-aerospike/src/main/java/com/playtika/testcontainer/aerospike/AerospikeWaitStrategy.java
  • embedded-azurite/pom.xml
  • embedded-azurite/src/main/java/com/playtika/testcontainer/azurite/EmbeddedAzuriteBootstrapConfiguration.java
  • embedded-azurite/src/test/java/com/playtika/testcontainer/azurite/EmbeddedAzuriteBoostrapConfigurationTest.java
  • embedded-consul/src/test/java/com/playtika/testcontainer/consul/EmbeddedConsulBootstrapConfigurationTest.java
  • embedded-couchbase/src/test/java/com/playtika/testcontainer/couchbase/springdata/SpringDataTest.java
  • embedded-git/src/test/java/config/CustomTransportConfigCallback.java
  • embedded-google-pubsub/pom.xml
  • embedded-google-pubsub/src/main/java/com/playtika/testcontainer/pubsub/EmbeddedPubsubBootstrapConfiguration.java
  • embedded-google-pubsub/src/main/java/com/playtika/testcontainer/pubsub/PubsubProperties.java
  • embedded-google-pubsub/src/test/java/com/playtika/testcontainer/pubsub/EmbeddedPubsubBootstrapConfigurationTest.java
  • embedded-google-storage/pom.xml
  • embedded-google-storage/src/main/java/com/playtika/testcontainer/storage/EmbeddedStorageBootstrapConfiguration.java
  • embedded-google-storage/src/main/java/com/playtika/testcontainer/storage/GoogleCloudStorageHttpClient.java
  • embedded-google-storage/src/test/java/com/playtika/testcontainer/storage/EmbeddedStorageBootstrapConfigurationTest.java
  • embedded-grafana/README.adoc
  • embedded-grafana/src/main/java/com/playtika/testcontainer/grafana/EmbeddedGrafanaBootstrapConfiguration.java
  • embedded-grafana/src/main/java/com/playtika/testcontainer/grafana/GrafanaProperties.java
  • embedded-grafana/src/test/java/com/playtika/testcontainer/grafana/EmbeddedGrafanaBootstrapConfigurationTest.java
  • embedded-grafana/src/test/resources/bootstrap.yaml
  • embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/configuration/KafkaContainerConfiguration.java
  • embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/properties/KafkaConfigurationProperties.java
  • embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/properties/SchemaRegistryConfigurationProperties.java
  • embedded-keycloak/pom.xml
  • embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/EmbeddedKeycloakBootstrapConfiguration.java
  • embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/KeycloakContainer.java
  • embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/KeycloakContainerFactory.java
  • embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/KeycloakProperties.java
  • embedded-keycloak/src/test/java/com/playtika/testcontainer/keycloak/spring/EmbeddedKeycloakBootstrapConfigurationTest.java
  • embedded-keycloak/src/test/java/com/playtika/testcontainer/keycloak/util/KeycloakJwtAuthenticationConverter.java
  • embedded-keycloak/src/test/java/com/playtika/testcontainer/keycloak/vanilla/KeycloakContainerTest.java
  • embedded-keydb/src/main/java/com/playtika/testcontainer/keydb/wait/KeyDbClusterStatusCheck.java
  • embedded-memsql/pom.xml
  • embedded-memsql/src/main/java/com/playtika/testcontainer/memsql/EmbeddedMemSqlBootstrapConfiguration.java
  • embedded-memsql/src/main/java/com/playtika/testcontainer/memsql/MemSqlContainer.java
  • embedded-memsql/src/test/java/com/playtika/testcontainer/memsql/EmbeddedMemSqlBootstrapConfigurationTest.java
  • embedded-minio/src/main/java/com/playtika/testcontainer/minio/DefaultMinioWaitStrategy.java
  • embedded-minio/src/main/java/com/playtika/testcontainer/minio/EmbeddedMinioBootstrapConfiguration.java
  • embedded-minio/src/main/java/com/playtika/testcontainer/minio/MinioWaitStrategy.java
  • embedded-minio/src/test/java/com/playtika/testcontainer/minio/EmbeddedMinioBootstrapConfigurationTest.java
  • embedded-mongodb/src/test/java/com/playtika/testcontainer/mongodb/EmbeddedMongodbBootstrapAuthConfigurationTest.java
  • embedded-mongodb/src/test/java/com/playtika/testcontainer/mongodb/EmbeddedMongodbBootstrapConfigurationTest.java
  • embedded-mongodb/src/test/java/com/playtika/testcontainer/mongodb/EmbeddedMongodbBootstrapReplicaSetConfigurationTest.java
  • embedded-native-kafka/src/main/java/com/playtika/testcontainer/nativekafka/configuration/NativeKafkaContainerConfiguration.java
  • embedded-native-kafka/src/test/java/com/playtika/testcontainer/nativekafka/EmbeddedNativeKafkaWithBindingTest.java
  • embedded-native-kafka/src/test/java/com/playtika/testcontainer/nativekafka/NativeKafkaTopicsConfigurerTest.java
  • embedded-nats/README.adoc
  • embedded-nats/pom.xml
  • embedded-nats/src/main/java/com/playtika/testcontainer/nats/EmbeddedNatsBootstrapConfiguration.java
  • embedded-nats/src/test/java/com/playtika/testcontainer/nats/BaseNatsTest.java
  • embedded-neo4j/src/test/java/com/playtika/testcontainer/neo4j/Person.java
  • embedded-redis/src/main/java/com/playtika/testcontainer/redis/wait/RedisClusterStatusCheck.java
  • embedded-selenium/README.adoc
  • embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/EmbeddedSeleniumBootstrapConfiguration.java
  • embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/VncRecordingMode.java
  • embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/testscope/TestcontainerContextCustomizerFactory.java
  • embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/testscope/TestcontainerScope.java
  • embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/testscope/TestcontainerTestExecutionListener.java
  • embedded-temporal/src/test/java/com/playtika/testcontainer/temporal/EmbeddedTemporalBootstrapConfigurationTest.java
  • embedded-vault/src/main/java/com/playtika/testcontainer/vault/EmbeddedVaultBootstrapConfiguration.java
  • embedded-wiremock/README.adoc
  • embedded-wiremock/pom.xml
  • embedded-wiremock/src/main/java/com/playtika/testcontainers/wiremock/EmbeddedWiremockBootstrapConfiguration.java
  • embedded-wiremock/src/main/java/com/playtika/testcontainers/wiremock/WiremockProperties.java
  • testcontainers-common/src/main/java/com/playtika/testcontainer/common/spring/AbstractDependsOnPostProcessor.java
  • testcontainers-common/src/main/java/com/playtika/testcontainer/common/utils/ContainerUtils.java
  • testcontainers-common/src/main/java/com/playtika/testcontainer/common/utils/DateUtils.java
  • testcontainers-common/src/main/java/com/playtika/testcontainer/common/utils/FileUtils.java
  • testcontainers-common/src/test/java/com/playtika/testcontainer/common/utils/ContainerUtilsTest.java
  • testcontainers-common/src/test/java/com/playtika/testcontainer/common/utils/MountVolumesTest.java
💤 Files with no reviewable changes (7)
  • embedded-minio/src/main/java/com/playtika/testcontainer/minio/DefaultMinioWaitStrategy.java
  • embedded-wiremock/src/main/java/com/playtika/testcontainers/wiremock/WiremockProperties.java
  • embedded-google-storage/src/main/java/com/playtika/testcontainer/storage/GoogleCloudStorageHttpClient.java
  • embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/KeycloakContainerFactory.java
  • embedded-minio/src/main/java/com/playtika/testcontainer/minio/MinioWaitStrategy.java
  • embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/KeycloakContainer.java
  • embedded-memsql/src/test/java/com/playtika/testcontainer/memsql/EmbeddedMemSqlBootstrapConfigurationTest.java
✅ Files skipped from review due to trivial changes (17)
  • embedded-nats/pom.xml
  • embedded-git/src/test/java/config/CustomTransportConfigCallback.java
  • embedded-keycloak/src/test/java/com/playtika/testcontainer/keycloak/spring/EmbeddedKeycloakBootstrapConfigurationTest.java
  • embedded-aerospike/src/main/java/com/playtika/testcontainer/aerospike/AerospikeWaitStrategy.java
  • embedded-aerospike/src/main/java/com/playtika/testcontainer/aerospike/AerospikeTestOperations.java
  • embedded-consul/src/test/java/com/playtika/testcontainer/consul/EmbeddedConsulBootstrapConfigurationTest.java
  • testcontainers-common/src/test/java/com/playtika/testcontainer/common/utils/MountVolumesTest.java
  • embedded-wiremock/README.adoc
  • embedded-nats/README.adoc
  • embedded-temporal/src/test/java/com/playtika/testcontainer/temporal/EmbeddedTemporalBootstrapConfigurationTest.java
  • embedded-redis/src/main/java/com/playtika/testcontainer/redis/wait/RedisClusterStatusCheck.java
  • embedded-keycloak/src/test/java/com/playtika/testcontainer/keycloak/util/KeycloakJwtAuthenticationConverter.java
  • testcontainers-common/src/main/java/com/playtika/testcontainer/common/utils/FileUtils.java
  • embedded-grafana/README.adoc
  • embedded-neo4j/src/test/java/com/playtika/testcontainer/neo4j/Person.java
  • embedded-native-kafka/src/test/java/com/playtika/testcontainer/nativekafka/EmbeddedNativeKafkaWithBindingTest.java
  • embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/properties/KafkaConfigurationProperties.java
🚧 Files skipped from review as they are similar to previous changes (41)
  • embedded-wiremock/pom.xml
  • embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/testscope/TestcontainerContextCustomizerFactory.java
  • embedded-minio/src/test/java/com/playtika/testcontainer/minio/EmbeddedMinioBootstrapConfigurationTest.java
  • embedded-google-storage/pom.xml
  • embedded-mongodb/src/test/java/com/playtika/testcontainer/mongodb/EmbeddedMongodbBootstrapConfigurationTest.java
  • embedded-google-storage/src/test/java/com/playtika/testcontainer/storage/EmbeddedStorageBootstrapConfigurationTest.java
  • embedded-memsql/src/main/java/com/playtika/testcontainer/memsql/MemSqlContainer.java
  • embedded-memsql/pom.xml
  • embedded-mongodb/src/test/java/com/playtika/testcontainer/mongodb/EmbeddedMongodbBootstrapAuthConfigurationTest.java
  • embedded-keydb/src/main/java/com/playtika/testcontainer/keydb/wait/KeyDbClusterStatusCheck.java
  • embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/properties/SchemaRegistryConfigurationProperties.java
  • embedded-keycloak/pom.xml
  • embedded-google-pubsub/pom.xml
  • testcontainers-common/src/main/java/com/playtika/testcontainer/common/utils/DateUtils.java
  • embedded-azurite/pom.xml
  • embedded-google-pubsub/src/test/java/com/playtika/testcontainer/pubsub/EmbeddedPubsubBootstrapConfigurationTest.java
  • embedded-native-kafka/src/main/java/com/playtika/testcontainer/nativekafka/configuration/NativeKafkaContainerConfiguration.java
  • testcontainers-common/src/main/java/com/playtika/testcontainer/common/utils/ContainerUtils.java
  • testcontainers-common/src/main/java/com/playtika/testcontainer/common/spring/AbstractDependsOnPostProcessor.java
  • embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/VncRecordingMode.java
  • embedded-memsql/src/main/java/com/playtika/testcontainer/memsql/EmbeddedMemSqlBootstrapConfiguration.java
  • embedded-vault/src/main/java/com/playtika/testcontainer/vault/EmbeddedVaultBootstrapConfiguration.java
  • embedded-couchbase/src/test/java/com/playtika/testcontainer/couchbase/springdata/SpringDataTest.java
  • embedded-mongodb/src/test/java/com/playtika/testcontainer/mongodb/EmbeddedMongodbBootstrapReplicaSetConfigurationTest.java
  • embedded-nats/src/test/java/com/playtika/testcontainer/nats/BaseNatsTest.java
  • embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/EmbeddedSeleniumBootstrapConfiguration.java
  • embedded-grafana/src/main/java/com/playtika/testcontainer/grafana/EmbeddedGrafanaBootstrapConfiguration.java
  • embedded-azurite/src/test/java/com/playtika/testcontainer/azurite/EmbeddedAzuriteBoostrapConfigurationTest.java
  • embedded-grafana/src/test/java/com/playtika/testcontainer/grafana/EmbeddedGrafanaBootstrapConfigurationTest.java
  • embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/KeycloakProperties.java
  • embedded-google-storage/src/main/java/com/playtika/testcontainer/storage/EmbeddedStorageBootstrapConfiguration.java
  • embedded-selenium/src/main/java/com/playtika/testcontainer/selenium/testscope/TestcontainerTestExecutionListener.java
  • embedded-keycloak/src/test/java/com/playtika/testcontainer/keycloak/vanilla/KeycloakContainerTest.java
  • embedded-azurite/src/main/java/com/playtika/testcontainer/azurite/EmbeddedAzuriteBootstrapConfiguration.java
  • embedded-google-pubsub/src/main/java/com/playtika/testcontainer/pubsub/EmbeddedPubsubBootstrapConfiguration.java
  • embedded-grafana/src/test/resources/bootstrap.yaml
  • embedded-native-kafka/src/test/java/com/playtika/testcontainer/nativekafka/NativeKafkaTopicsConfigurerTest.java
  • embedded-selenium/README.adoc
  • embedded-keycloak/src/main/java/com/playtika/testcontainer/keycloak/EmbeddedKeycloakBootstrapConfiguration.java
  • embedded-minio/src/main/java/com/playtika/testcontainer/minio/EmbeddedMinioBootstrapConfiguration.java
  • embedded-nats/src/main/java/com/playtika/testcontainer/nats/EmbeddedNatsBootstrapConfiguration.java

@@ -217,12 +225,12 @@ public String getBootstrapServers() {
kafkaFileSystemBind(kafkaProperties, kafka);
zookeperFileSystemBind(zookeeperProperties, kafka);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Confluent ConfluentKafkaContainer testcontainers KRaft ZooKeeper data directory

💡 Result:

In Confluent Platform images used by Testcontainers (confluentinc/cp-kafka), Kafka’s on-disk data directory is /var/lib/kafka/data (Kafka log storage is persisted there via the image’s configured VOLUME and Confluent’s Docker guidance) [1][2]. If you run cp-kafka in KRaft mode (the ConfluentDocker examples default to KRaft, and Confluent’s config docs describe KRaft metadata stored in the configured metadata/KRaft log directories), the KRaft metadata log location is controlled by metadata.log.dir (otherwise placed in the first log directory from log.dirs) [3]. For Testcontainers specifics: - The Java module docs confirm ConfluentKafkaContainer supports confluentinc/cp-kafka (7.4.0+) and runs Kafka via the Confluent image startup scripts [4][5]. - The Confluent Platform Docker documentation for external volumes explicitly shows mounting host /var/lib/kafka/data to the container path /var/lib/kafka/data (example using -v /vol1/kafka-data:/var/lib/kafka/data) [1]. ZooKeeper data directory (only relevant for ZooKeeper-mode setups): - ZooKeeper uses /var/lib/zookeeper/data and /var/lib/zookeeper/log (as set via the zookeeper.properties in Testcontainers’ KafkaContainer implementation) [6] and aligns with Confluent’s docker-volume guidance that ZooKeeper persists “transaction logs” via volumes (and that you should mount the relevant directories) [1]. Practical takeaway for your testcontainers setup: - For ConfluentKafkaContainer (cp-kafka), bind-mount/persist /var/lib/kafka/data. - For any ZooKeeper-mode container, persist /var/lib/zookeeper/data (and, if needed, /var/lib/zookeeper/log). [1][6]

Citations:


🏁 Script executed:

# Find the zookeperFileSystemBind method definition
rg -A 10 "def zookeperFileSystemBind|void zookeperFileSystemBind" --type java

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 2098


🏁 Script executed:

# Check the KafkaContainerConfiguration class around lines 226 and 215-264
fd "KafkaContainerConfiguration.java" --type f | head -1 | xargs wc -l

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 195


🏁 Script executed:

# Get the relevant sections of the file
fd "KafkaContainerConfiguration.java" --type f | head -1 | xargs cat -n | sed -n '210,270p'

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 4364


🏁 Script executed:

# Verify the kafkaFileSystemBind method (for comparison with zookeperFileSystemBind)
# to understand the intended behavior
sed -n '233,244p' embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/configuration/KafkaContainerConfiguration.java

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 862


🏁 Script executed:

# Check if there are any properties or configurations that control whether 
# ZooKeeper filesystem binding should be skipped in KRaft mode
rg "zookeeperFileSystemBind|ZookeeperConfigurationProperties" --type java -B 2 -A 2 | head -60

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 8093


🏁 Script executed:

# Check if there's any documentation or comments about the KRaft migration
rg "KRaft|kraft" --type java -B 1 -A 1 | head -40

Repository: PlaytikaOSS/testcontainers-spring-boot

Length of output: 64


zookeperFileSystemBind has no effect under ConfluentKafkaContainer running in KRaft mode.

ConfluentKafkaContainer (using confluentinc/cp-kafka image) runs Kafka in KRaft mode without a ZooKeeper process. The method copies directories to /var/lib/zookeeper/data and /var/lib/zookeeper/log inside the container, but KRaft metadata is persisted elsewhere (/var/lib/kafka/data via metadata.log.dir). Users who enable embedded.zookeeper.fileSystemBind.enabled=true will see logs and directories created on the host, but persistence will not work as expected — the copied ZooKeeper directories remain unused.

Consider:

  • Removing zookeperFileSystemBind(...) and the related ZookeeperConfigurationProperties.FileSystemBind usage entirely, with a migration note in the changelog.
  • Or, if retaining the property surface for backward compatibility, log a warning when zookeeperFileSystemBind.isEnabled() is true to alert users that the setting is now ignored.

Similarly, withEnv("ZOOKEEPER_SASL_ENABLED", "false") (line 215) is no longer meaningful under KRaft and can be removed in the same cleanup.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-kafka/src/main/java/com/playtika/testcontainer/kafka/configuration/KafkaContainerConfiguration.java`
at line 226, The zookeperFileSystemBind(...) call and setting
withEnv("ZOOKEEPER_SASL_ENABLED", "false") are ineffective for
ConfluentKafkaContainer running in KRaft mode; remove the
zookeperFileSystemBind(...) invocation and the ZOOKEEPER_SASL_ENABLED env set
from KafkaContainerConfiguration (and clean up related
ZookeeperConfigurationProperties.FileSystemBind usage) OR keep the property for
compatibility but add a clear warning when zookeeperFileSystemBind.isEnabled()
is true (log via the class logger in KafkaContainerConfiguration stating the
setting is ignored under KRaft); also add a brief migration note to the
changelog if you remove the feature.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

❌ Failed to clone repository into sandbox. Please try again.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
embedded-native-kafka/src/main/java/com/playtika/testcontainer/nativekafka/configuration/NativeKafkaContainerConfiguration.java (1)

78-82: ⚡ Quick win

Update parameter type to KafkaContainer for consistency.

The nativeKafka bean now returns KafkaContainer, but this method still accepts GenericContainer<?>. For consistency with the typed container migration, update the parameter type to match.

♻️ Proposed fix to use KafkaContainer type
 `@Bean`
 `@ConditionalOnMissingBean`
 public NativeKafkaTopicsConfigurer nativeKafkaTopicsConfigurer(
-        GenericContainer<?> nativeKafka,
+        KafkaContainer nativeKafka,
         NativeKafkaConfigurationProperties nativeKafkaProperties) {
     return new NativeKafkaTopicsConfigurer(nativeKafka, nativeKafkaProperties);
 }

Note: This requires updating the NativeKafkaTopicsConfigurer constructor to accept KafkaContainer instead of GenericContainer<?>.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@embedded-native-kafka/src/main/java/com/playtika/testcontainer/nativekafka/configuration/NativeKafkaContainerConfiguration.java`
around lines 78 - 82, Change the parameter type of the
nativeKafkaTopicsConfigurer factory method from GenericContainer<?> to
KafkaContainer and update the NativeKafkaTopicsConfigurer constructor signature
to accept KafkaContainer as well (replace usages of GenericContainer<?> in the
class to KafkaContainer) so the method
nativeKafkaTopicsConfigurer(GenericContainer<?> nativeKafka, ...) becomes
nativeKafkaTopicsConfigurer(KafkaContainer nativeKafka, ...) and the
NativeKafkaTopicsConfigurer(GenericContainer<?> nativeKafka, ...) constructor
becomes NativeKafkaTopicsConfigurer(KafkaContainer nativeKafka, ...); ensure all
internal references and imports are adjusted to KafkaContainer.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@embedded-native-kafka/src/main/java/com/playtika/testcontainer/nativekafka/configuration/NativeKafkaContainerConfiguration.java`:
- Around line 78-82: Change the parameter type of the
nativeKafkaTopicsConfigurer factory method from GenericContainer<?> to
KafkaContainer and update the NativeKafkaTopicsConfigurer constructor signature
to accept KafkaContainer as well (replace usages of GenericContainer<?> in the
class to KafkaContainer) so the method
nativeKafkaTopicsConfigurer(GenericContainer<?> nativeKafka, ...) becomes
nativeKafkaTopicsConfigurer(KafkaContainer nativeKafka, ...) and the
NativeKafkaTopicsConfigurer(GenericContainer<?> nativeKafka, ...) constructor
becomes NativeKafkaTopicsConfigurer(KafkaContainer nativeKafka, ...); ensure all
internal references and imports are adjusted to KafkaContainer.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3f8dabf4-58bc-4f3f-90e5-f3b6788c0f23

📥 Commits

Reviewing files that changed from the base of the PR and between fef2ab8 and 14e3a1b.

📒 Files selected for processing (1)
  • embedded-native-kafka/src/main/java/com/playtika/testcontainer/nativekafka/configuration/NativeKafkaContainerConfiguration.java

@codecov
Copy link
Copy Markdown

codecov Bot commented May 14, 2026

Codecov Report

❌ Patch coverage is 77.44361% with 60 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.82%. Comparing base (337f1aa) to head (021b29f).
⚠️ Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
...azurite/EmbeddedAzuriteBootstrapConfiguration.java 36.36% 18 Missing and 3 partials ⚠️
...ycloak/EmbeddedKeycloakBootstrapConfiguration.java 66.07% 9 Missing and 10 partials ⚠️
...playtika/testcontainer/memsql/MemSqlContainer.java 84.12% 7 Missing and 3 partials ⚠️
...lenium/EmbeddedSeleniumBootstrapConfiguration.java 42.85% 1 Missing and 3 partials ⚠️
...tcontainer/keydb/wait/KeyDbClusterStatusCheck.java 0.00% 1 Missing ⚠️
...r/memsql/EmbeddedMemSqlBootstrapConfiguration.java 92.85% 0 Missing and 1 partial ⚠️
...tcontainer/redis/wait/RedisClusterStatusCheck.java 0.00% 1 Missing ⚠️
...stscope/TestcontainerContextCustomizerFactory.java 0.00% 1 Missing ⚠️
...playtika/testcontainer/common/utils/DateUtils.java 50.00% 0 Missing and 1 partial ⚠️
...playtika/testcontainer/common/utils/FileUtils.java 0.00% 1 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##             develop    #2945      +/-   ##
=============================================
- Coverage      82.45%   81.82%   -0.64%     
+ Complexity       692      683       -9     
=============================================
  Files            205      202       -3     
  Lines           3147     3092      -55     
  Branches         146      150       +4     
=============================================
- Hits            2595     2530      -65     
- Misses           483      492       +9     
- Partials          69       70       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

admitrov added 18 commits May 22, 2026 12:24
Replace GenericContainer with AzuriteContainer and add testcontainers-azure dependency. Update container initialization to use AzuriteContainer API with command modifier for skipApiVersionCheck flag.
Replace custom KeycloakContainer and KeycloakContainerFactory implementations with dasniko/testcontainers-keycloak dependency. Consolidate container configuration logic into EmbeddedKeycloakBootstrapConfiguration and refactor tests to use ApplicationContextRunner.
… Zookeeper

Replace deprecated KafkaContainer imports with new testcontainers-kafka module classes. Use KafkaContainer for embedded-kafka and ConfluentKafkaContainer for embedded-native-kafka. Remove withEmbeddedZookeeper() call as newer Kafka versions use KRaft mode.
…it strategies

Replace custom MinioWaitStrategy with built-in Wait.forHttp() from testcontainers. Update container initialization to use MinIOContainer's withUserName/withPassword API instead of environment variables. Remove DefaultMinioWaitStrategy and MinioWaitStrategy classes. Add wiremock-testcontainers-module version property.
…move redundant port exposure

Replace withSecretInVault API with withInitCommand using kv put command. Remove withExposedPorts call as port exposure is handled by VaultContainer. Remove unused Arrays import.
…stcontainers-gcloud module

Replace GenericContainer with PubSubEmulatorContainer and add testcontainers-gcloud dependency. Update container initialization to use PubSubEmulatorContainer API with getEmulatorEndpoint(). Change default port from 8089 to 8085 and update Docker image to gcr.io/google.com/cloudsdktool/google-cloud-cli:559.0.0-emulators. Remove custom command construction and wait strategy as they are handled by PubSubEmulatorContainer.
…stcontainers-fake-gcs-server library

Replace GenericContainer with FakeGcsServerContainer and add testcontainers-fake-gcs-server dependency. Remove GoogleCloudStorageHttpClient and custom endpoint configuration logic as they are handled by FakeGcsServerContainer's url() method. Update container initialization to use FakeGcsServerContainer API.
…atabaseContainer

Replace GenericContainer with MemSqlContainer extending JdbcDatabaseContainer. Add testcontainers-jdbc dependency. Implement MemSqlContainer with withDatabaseName/withUsername/withPassword/withLicenseKey API and JDBC-specific methods (getJdbcUrl, getDriverClassName, getTestQueryString). Update container initialization to use MemSqlContainer API and remove manual environment variable configuration. Add jdbcUrl to registered environment properties.
…i, Tempo, and OTLP support

Replace GenericContainer with LgtmStackContainer and update default image to grafana/otel-lgtm:0.9.3. Add port configurations for Loki (3100), Tempo (3200), OTLP gRPC (4317), and OTLP HTTP (4318). Remove custom wait strategy and manual port exposure as they are handled by LgtmStackContainer. Update environment properties to expose all service ports. Comment out gitflow-incremental-builder plugin. Update README documentation with new image source and port configurations. Simplify test configuration.
…containers-module

Replace GenericContainer with WireMockContainer and add wiremock-testcontainers-module dependency. Remove custom wait strategy and port configuration as they are handled by WireMockContainer. Update container initialization to use WireMockContainer API and remove manual command/port exposure. Replace Lombok @slf4j with standard LoggerFactory. Update registered environment properties to use container's getPort() and getHost() methods with hardcoded internal port 8080. Remove port property from WiremockProperties.
…ibrary

Replace GenericContainer with NatsContainer and add nats-testcontainers dependency. Remove custom wait strategy, port configuration, and nats-server.conf as they are handled by NatsContainer. Update container initialization to use NatsContainer API and remove manual port exposure. Replace Lombok @slf4j with standard LoggerFactory. Update registered environment properties to use container's getClientPort(), getHttpMonitoringPort(), and getRoutingPort() methods with hardcoded internal ports. Remove port properties from NatsProperties.
…n and remove port configuration

Remove port property from configuration section and update bean type from GenericContainer to WireMockContainer in produces section.
…selenium library

Replace BrowserWebDriverContainer import from core with testcontainers-selenium module. Remove deprecated wait strategy implementation and capabilities/docker-image conditional logic. Update container initialization to use BrowserWebDriverContainer constructor with getDockerImageName(). Remove unused utility methods (isNotBlank, getWaitStrategy). Update README to reflect browser selection via Docker image instead of capabilities. Simplify TestcontainerScope and TestcontainerTestExecutionListener implementations. Replace indexOf with contains for OS detection.
Remove unnecessary lambda braces in AbstractDependsOnPostProcessor. Replace Files.write with Files.writeString in FileUtils. Replace addFileSystemBind with withCopyToContainer in ContainerUtils. Use pattern matching for instanceof in DateUtils. Remove redundant type parameters in ContainerUtilsTest. Make ApplicationContextRunner final in MountVolumesTest.
Replace Arrays.asList with List.of for single-element and immutable collections. Use pattern matching for instanceof checks. Replace replaceAll with replace for literal strings. Convert Lombok @value classes to records. Remove unnecessary lambda braces and redundant toString() calls. Use text blocks for multi-line log messages. Replace Integer.valueOf with Integer.parseInt. Remove unused imports and parameters. Replace addFileSystemBind with withCopyToContainer. Use StandardCharsets.UTF_8 directly instead of name(). Replace Hamcrest matchers with AssertJ assertions. Simplify Optional assertions with hasValue().
…nstead of getBinds

Replace deprecated getBinds() assertions with reflection-based access to copyToTransferableContainerPathMap field. Update mount volume verification to check Transferable entries instead of Bind objects. Remove unused docker-java imports (AccessMode, Bind) and add reflection-related imports (Field, GenericContainer, Transferable).
…ntainerIsStarting for advertised listeners configuration

Replace KafkaContainer with ConfluentKafkaContainer. Override containerIsStarting() instead of getBootstrapServers() to dynamically configure advertised listeners using Transferable script injection. Add CONTROLLER listener configuration for KRaft mode. Update all method signatures and type casts from KafkaContainer to ConfluentKafkaContainer.
…entKafkaContainer

Replace ConfluentKafkaContainer with KafkaContainer and remove asCompatibleSubstituteFor() call. Update all method signatures and type casts from ConfluentKafkaContainer to KafkaContainer.
admitrov added 7 commits May 22, 2026 12:25
…precated getWebDriver()

Replace container.getWebDriver() calls with getDriver() helper method that creates RemoteWebDriver from container's Selenium address and autowired capabilities. Update package import from testcontainers.containers to testcontainers.selenium. Add capabilities autowiring and lazy driver initialization. Re-enable EmbeddedFirefoxSeleniumBeanConfigurationTest with proper browser and image configuration. Update space formatting in type casts.
…ion check

Override waitUntilContainerStarted() to connect to root URL and create database before delegating to parent. This prevents "Unknown database" error since JdbcDatabaseContainer connects to getJdbcUrl() which includes the database name. Add database existence verification and proper exception handling. Simplify status check query by removing schema.sql sourcing and database USE statement.
…otstrapConfiguration

Remove manual logger instantiation and use @slf4j annotation. Remove unused LoggerFactory and Logger imports.
…otstrapConfiguration

Remove manual logger instantiation and use @slf4j annotation. Remove unused LoggerFactory and Logger imports.
…gned certificate

Add httpsEnabled and oauthEnabled properties to AzuriteProperties. Implement configureSsl() to handle PEM/PFX certificates with fallback to embedded self-signed certificate for localhost. Update endpoint URLs to use https:// protocol when HTTPS is enabled. Add --oauth basic command line argument when OAuth is enabled. Include certificate resolution logic supporting both classpath and file system paths. Update README with HTTPS/OAuth configuration examples and fix typo (convient → convenient).
Add `anonymousAuthEnabled` and `anonymousOrgRole` properties to GrafanaProperties. Configure `GF_AUTH_ANONYMOUS_ENABLED` and `GF_AUTH_ANONYMOUS_ORG_ROLE` environment variables when anonymous auth is enabled. Add test to verify environment variables and unauthenticated API access. Update README with configuration examples.
Enable Toxiproxy in bootstrap properties. Add ToxiproxyClientProxy autowiring and implement latency emulation test using toxics API. Update JDBC URL to use toxiproxy host/port. Replace disabled test with working implementation using upstream latency toxic and assertion with offset tolerance.
@ijusti ijusti force-pushed the feature/org-testcontainers branch from 79d588e to 021b29f Compare May 22, 2026 11:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant