Add execInArtemis helper to ArtemisContainer (#11589) - #11955
Conversation
…tainers#11589) Adds a convenience method that wraps execInContainer, prepending the Artemis CLI binary path and auto-injecting the configured user and password credentials, so callers no longer have to hard-code the container path or manually pass --user/--password on every invocation. Signed-off-by: klouds27 <adalwolf@gmail.com>
renechoi
left a comment
There was a problem hiding this comment.
I was looking at the ActiveMQ module and ran this locally. It's still a draft, so I'd rather flag these now than after you've polished it.
Setup: PR head 7a658e0f on top of 2ac3c977 (current main), JDK 21.0.9, Docker on linux/arm64, both apache/activemq-artemis:2.32.0-alpine and apache/artemis:2.53.0-alpine pulled natively.
What already works. ./gradlew :testcontainers-activemq:test is green on the PR head: 10 tests, 0 failures (4 in ActiveMQContainerTest, 6 in ArtemisContainerTest). I also checked /var/lib/artemis-instance/bin/artemis on apache/artemis:2.53.0-alpine, since a hard-coded path looked image-specific and that image is in the compatibility matrix. The image ships the CLI at /opt/artemis/bin/artemis, but its entrypoint creates the broker instance at /var/lib/artemis-instance, so the constant resolves on both supported images. No problem there.
Four things below.
1. ./gradlew check will fail on formatting
Both changed files violate the module's prettier config (printWidth 120):
> Task :testcontainers-activemq:spotlessJavaCheck FAILED
The following files had format violations:
src/main/java/org/testcontainers/activemq/ArtemisContainer.java
src/test/java/org/testcontainers/activemq/ArtemisContainerTest.java
./gradlew :testcontainers-activemq:spotlessApply fixes both. Worth doing before you mark it ready for review, since CI runs check.
2. A caller can no longer pass explicit credentials
The credentials are appended unconditionally, so supplying your own is a hard error rather than an override:
artemis.execInArtemis("queue", "create", "--name=q", "--auto-create-address", "--anycast", "--silent",
"--user=someone", "--password=secret");exit=1
stdout=Usage: artemis help [<args>...]
stderr=option '--user' (<user>) should be specified only once
This matters for a broker. Checking what a non-admin user is allowed to do is an ordinary Artemis test, and the helper currently removes that option with an error that doesn't point at the cause. Injecting only when the caller hasn't already supplied them keeps the sugar and drops the trap:
List<String> fullCommand = new ArrayList<>();
fullCommand.add(ARTEMIS_CLI);
fullCommand.addAll(Arrays.asList(command));
if (Stream.of(command).noneMatch(arg -> arg.startsWith("--user"))) {
fullCommand.add("--user=" + getUser());
}
if (Stream.of(command).noneMatch(arg -> arg.startsWith("--password"))) {
fullCommand.add("--password=" + getPassword());
}I ran that guard locally. Explicit --user=artemis --password=artemis creates the queue (exit 0), and explicit wrong credentials now fail with the broker's own error (AMQ229031: Unable to validate user ... Username: nope) rather than a CLI usage error. Treat the snippet as a sketch: the prefix match wants more care than startsWith if you go this way.
3. getExitCode() == 0 does not prove the queue was created
In fairness, the assertion is not empty. Run the same command with no credentials and it exits 1 (AMQ229031 ... Username: null), so exit code 0 does pin down the credential injection, which is the point of the PR.
What it doesn't pin down is the command itself. artemis queue create exits 0 when the create fails:
execInArtemis("queue", "create", "--silent")
exit=0
stderr=Failed to create queue . Reason: AMQ229216: Invalid queue name:
So a regression that mangles the command arguments while still passing credentials through would leave this test green. Asserting on the queue costs nothing on the container the test already started:
execInArtemis("queue", "stat", "--queueName=exec-test-queue")
|NAME |ADDRESS |CONSUMER_COUNT|...
|exec-test-queue|exec-test-queue|0 |...
execInArtemis("queue", "stat", "--queueName=no-such-queue")
|NAME|ADDRESS|CONSUMER_COUNT|... <- header row only
Both exit 0, so the assertion has to read stdout.
Related, and your call rather than a request: every other module under modules/ that shells out to a CLI checks the exit code itself and then throws or logs (SolrContainer, RabbitMQContainer, SolaceContainer, MongoDBContainer). This is the first public helper here that hands back a raw ExecResult. Keeping it raw is defensible, but given the measurement above, the javadoc probably shouldn't leave callers assuming exit 0 means the command did what they asked. Note that the example in #11589 throws on a non-zero exit, which wouldn't have caught the case above either.
4. The new API isn't in the docs
docs/modules/activemq.md pulls every existing ArtemisContainer feature out of the test file with <!--codeinclude--> and inside_block: (container, settingCredentials, enableAnonymousLogin). The new test carries no such markers and the docs aren't touched, so execInArtemis won't appear anywhere a user would look for it. #11589 asks for that directly ("It'd also be a nice way to promote that feature in the API"), so a // execInArtemis { block plus a short docs section would close the issue more completely.
Conditional credential injection: --user and --password are only appended when the caller has not already supplied them, so passing explicit credentials no longer fails with a duplicate-option error. Stronger test: after creating the queue, queue stat verifies it actually exists rather than relying on exit code alone, which artemis returns as 0 even on some failures. Docs: add execInArtemis codeinclude section to activemq.md and mark the test block so the docs generator picks it up. Signed-off-by: klouds27 <adalwolf@gmail.com>
Closes #11589
Invoking the Artemis CLI from a container required callers to hard-code the internal binary path and manually append
--user/--passwordon every call.execInArtemiswrapsexecInContainer, prepending the binary path and injecting the configured credentials automatically.The binary path and credentials are always resolved from the container's current configuration, so multiple CLI commands can be chained without any extra setup.