Skip to content

Conversation

@mdelapenya
Copy link
Member

  • chore(artemis): use Run function
  • chore: use a constant
  • chore: more robust wait strategy using listening port
  • chore: set credentials properly

What does this PR do?

Use Run function in the Artemis module

Why is it important?

Migrate modules to the new API

Related issues

@mdelapenya mdelapenya requested a review from a team as a code owner September 29, 2025 14:44
@mdelapenya mdelapenya added the chore Changes that do not impact the existing functionality label Sep 29, 2025
@mdelapenya mdelapenya self-assigned this Sep 29, 2025
@netlify
Copy link

netlify bot commented Sep 29, 2025

Deploy Preview for testcontainers-go ready!

Name Link
🔨 Latest commit ed0abaa
🔍 Latest deploy log https://app.netlify.com/projects/testcontainers-go/deploys/68daa55b5885690008ddfd0b
😎 Deploy Preview https://deploy-preview-3320--testcontainers-go.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link

coderabbitai bot commented Sep 29, 2025

Summary by CodeRabbit

  • Refactor

    • Improved container startup with modular options and clearer error messages.
    • Safer console URL handling to avoid embedding credentials.
    • Automatically refreshes runtime credentials from the environment.
  • Tests

    • Strengthened assertions to fail fast for clearer failures.
    • Ensured test resource cleanup to prevent leaks.
    • Added clarifying comments for default credentials.

Walkthrough

Refactors Artemis module to use testcontainers.Run with functional options, sets default credentials, inspects started container to derive ARTEMIS_USER/ARTEMIS_PASSWORD, and updates tests to use require.Equal with ticker cleanup. Public API unchanged.

Changes

Cohort / File(s) Summary
Artemis module refactor
modules/artemis/artemis.go
Replace prior GenericContainer/ContainerRequest flow with testcontainers.Run(ctx, img, moduleOpts...). Add defaultUser/defaultPassword, build moduleOpts (WithExposedPorts, WithEnv, composite wait), initialize creds from defaults, inspect container post-start and parse ARTEMIS_USER/ARTEMIS_PASSWORD from inspect.Config.Env, and improve error wrapping.
Tests: assertion & cleanup
modules/artemis/artemis_test.go
Swap assert.Equalrequire.Equal, remove testify/assert import, add defer ticker.Stop(), and add short comments for default creds; test logic preserved.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Caller
  participant ArtemisRun as modules/artemis.Run
  participant TC as testcontainers.Run
  participant Container
  participant Inspector as Container.Inspect
  participant Parser as Env Parser

  Caller->>ArtemisRun: Run(ctx, opts...)
  ArtemisRun->>TC: Run(ctx, image, moduleOpts...)
  alt Run error
    TC-->>ArtemisRun: error
    ArtemisRun-->>Caller: wrapped start error
  else Run success
    TC-->>ArtemisRun: Container handle
    ArtemisRun->>Inspector: Inspect(ctx)
    alt Inspect error
      Inspector-->>ArtemisRun: error
      ArtemisRun-->>Caller: wrapped inspect error
    else Inspect success
      Inspector-->>ArtemisRun: Config.Env list
      ArtemisRun->>Parser: parse ARTEMIS_USER / ARTEMIS_PASSWORD
      Parser-->>ArtemisRun: resolved credentials
      ArtemisRun-->>Caller: container + credentials
    end
  end

  rect rgba(46,125,50,0.06)
    note right of Parser: credential derivation is post-start
  end
  rect rgba(211,47,47,0.06)
    note right of TC: Run/inspect/parse errors propagate
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • stevenh

Poem

I hopped to the broker, ears held high,
Spun up a crate beneath moonlit sky.
I peeked the env for a secret key,
Found user and pass to guide my spree.
Tests now require — a confident hop! 🥕🐇

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly and succinctly captures the primary change of the pull request by indicating the use of the new Run function in the Artemis module without extraneous details or unrelated topics, making it immediately understandable to reviewers.
Description Check ✅ Passed The description directly outlines the key chore tasks performed—using the Run function, introducing a constant, improving the wait strategy, and setting credentials—as well as the purpose and rationale, making it clearly related to the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f202755 and ed0abaa.

📒 Files selected for processing (1)
  • modules/artemis/artemis.go (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • modules/artemis/artemis.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: test (1.25.x, modules/artemis) / test: modules/artemis/1.25.x
  • GitHub Check: test (1.24.x, modules/artemis) / test: modules/artemis/1.24.x
  • GitHub Check: Analyze (go)

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@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

Caution

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

⚠️ Outside diff range comments (1)
modules/artemis/artemis.go (1)

54-61: Avoid potential nil map writes; reuse WithEnv helper

req.Env may be nil depending on option ordering/usage outside this module. Use testcontainers.WithEnv to ensure initialization and merge behavior.

 func WithCredentials(user, password string) testcontainers.CustomizeRequestOption {
-    return func(req *testcontainers.GenericContainerRequest) error {
-        req.Env["ARTEMIS_USER"] = user
-        req.Env["ARTEMIS_PASSWORD"] = password
-
-        return nil
-    }
+    return testcontainers.WithEnv(map[string]string{
+        "ARTEMIS_USER":     user,
+        "ARTEMIS_PASSWORD": password,
+    })
 }
 
 func WithAnonymousLogin() testcontainers.CustomizeRequestOption {
-    return func(req *testcontainers.GenericContainerRequest) error {
-        req.Env["ANONYMOUS_LOGIN"] = "true"
-
-        return nil
-    }
+    return testcontainers.WithEnv(map[string]string{
+        "ANONYMOUS_LOGIN": "true",
+    })
 }
 
 func WithExtraArgs(args string) testcontainers.CustomizeRequestOption {
-    return func(req *testcontainers.GenericContainerRequest) error {
-        req.Env["EXTRA_ARGS"] = args
-
-        return nil
-    }
+    return testcontainers.WithEnv(map[string]string{
+        "EXTRA_ARGS": args,
+    })
 }

Also applies to: 64-70, 76-82

🧹 Nitpick comments (6)
modules/artemis/artemis.go (4)

113-115: Clarify error message context

“generic container” is ambiguous now that Run() is used. Recommend a clearer message.

-    return c, fmt.Errorf("generic container: %w", err)
+    return c, fmt.Errorf("run artemis: %w", err)

117-121: Guard against nil container before dereference

Improbable, but if ctr == nil with err == nil, c.user assignments will panic. Add a defensive check.

 // initialize the credentials
-c.user = defaultUser
-c.password = defaultPassword
+if c == nil {
+    return nil, fmt.Errorf("run artemis: container is nil")
+}
+c.user = defaultUser
+c.password = defaultPassword

126-139: Break early after both creds found

Small efficiency/readability tweak: stop scanning once both ARTEMIS_USER and ARTEMIS_PASSWORD are found.

-// refresh the credentials from the environment variables
-for _, env := range inspect.Config.Env {
-    value, ok := strings.CutPrefix(env, "ARTEMIS_USER=")
-    if ok {
-        c.user = value
-        continue
-    }
-
-    value, ok = strings.CutPrefix(env, "ARTEMIS_PASSWORD=")
-    if ok {
-        c.password = value
-        continue
-    }
-}
+foundUser, foundPass := false, false
+for _, env := range inspect.Config.Env {
+    if v, ok := strings.CutPrefix(env, "ARTEMIS_USER="); ok {
+        c.user, foundUser = v, true
+    } else if v, ok := strings.CutPrefix(env, "ARTEMIS_PASSWORD="); ok {
+        c.password, foundPass = v, true
+    }
+    if foundUser && foundPass {
+        break
+    }
+}

98-104: Consider a longer wait deadline for CI stability

Artemis can take >60s on shared runners. Optionally raise the default deadline.

+   // import "time"
-   testcontainers.WithWaitStrategy(wait.ForAll(
+   testcontainers.WithWaitStrategyAndDeadline(120*time.Second, wait.ForAll(
        ...
    )),

If you prefer keeping 60s, expose a WithWaitDeadline option for callers to override.

modules/artemis/artemis_test.go (2)

95-97: Tighten login condition

Only set STOMP login if both user and pass are non-empty to avoid accidental empty credentials.

- if test.user != "" || test.pass != "" {
+ if test.user != "" && test.pass != "" {
     opt = append(opt, stomp.ConnOpt.Login(test.user, test.pass))
 }

110-116: Stop ticker to avoid goroutine leak on early returns

Defer ticker.Stop() so it’s cleaned up if the test fails before receiving.

- ticker := time.NewTicker(10 * time.Second)
+ ticker := time.NewTicker(10 * time.Second)
+ defer ticker.Stop()
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4b48dd2 and 348c175.

📒 Files selected for processing (2)
  • modules/artemis/artemis.go (3 hunks)
  • modules/artemis/artemis_test.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
modules/artemis/artemis.go (5)
options.go (3)
  • WithExposedPorts (464-469)
  • WithEnv (75-85)
  • WithWaitStrategy (376-378)
wait/all.go (1)
  • ForAll (44-48)
wait/host_port.go (1)
  • ForListeningPort (67-69)
wait/log.go (1)
  • ForLog (118-120)
container.go (1)
  • Container (41-73)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: test (1.25.x, modules/artemis) / test: modules/artemis/1.25.x
  • GitHub Check: test (1.24.x, modules/artemis) / test: modules/artemis/1.24.x
  • GitHub Check: Analyze (go)
🔇 Additional comments (4)
modules/artemis/artemis_test.go (3)

56-57: LGTM on documenting defaults inline

The explicit comments improve readability; matches defaultUser/defaultPassword in module.


11-11: Switch to require is appropriate here

Using require.* short-circuits on fatal conditions and avoids cascaded failures in integration tests.

Based on learnings


66-70: CleanupContainer is nil-safe — no changes required
TerminateContainer (called by CleanupContainer) returns early if ctr is nil (cleanup.go around lines 97–104), so there’s no panic risk.

modules/artemis/artemis.go (1)

128-137: Go version requirement satisfied; no changes needed
go.mod declares go 1.24.0, which is ≥ 1.20—strings.CutPrefix is supported.

Copy link

@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: 0

Caution

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

⚠️ Outside diff range comments (3)
modules/artemis/artemis.go (3)

54-61: Prevent panic: initialize req.Env before writes in WithCredentials

req.Env may be nil; writing to a nil map panics. Initialize it first, mirroring WithEnv’s behavior.

Apply:

 func WithCredentials(user, password string) testcontainers.CustomizeRequestOption {
   return func(req *testcontainers.GenericContainerRequest) error {
-    req.Env["ARTEMIS_USER"] = user
-    req.Env["ARTEMIS_PASSWORD"] = password
+    if req.Env == nil {
+      req.Env = map[string]string{}
+    }
+    req.Env["ARTEMIS_USER"] = user
+    req.Env["ARTEMIS_PASSWORD"] = password
     return nil
   }
 }

64-70: Same nil‑map risk in WithAnonymousLogin

Guard against nil maps before setting ANONYMOUS_LOGIN.

 func WithAnonymousLogin() testcontainers.CustomizeRequestOption {
   return func(req *testcontainers.GenericContainerRequest) error {
-    req.Env["ANONYMOUS_LOGIN"] = "true"
+    if req.Env == nil {
+      req.Env = map[string]string{}
+    }
+    req.Env["ANONYMOUS_LOGIN"] = "true"
     return nil
   }
 }

76-82: Same nil‑map risk in WithExtraArgs

Initialize req.Env before setting EXTRA_ARGS.

 func WithExtraArgs(args string) testcontainers.CustomizeRequestOption {
   return func(req *testcontainers.GenericContainerRequest) error {
-    req.Env["EXTRA_ARGS"] = args
+    if req.Env == nil {
+      req.Env = map[string]string{}
+    }
+    req.Env["EXTRA_ARGS"] = args
     return nil
   }
 }
🧹 Nitpick comments (1)
modules/artemis/artemis.go (1)

45-51: PortEndpoint returns host:port when proto is blank; use net/url for URL construction

  • Verified that calling PortEndpoint(ctx, _, "") returns just host:port (no scheme) per the implementations in modules/ollama/local.go and docker.go.
  • Replace the manual fmt.Sprintf with net/url to ensure proper escaping of credentials and path:
@@
-import (
-  "context"
-  "fmt"
-  "strings"
+import (
+  "context"
+  "fmt"
+  "net/url"
+  "strings"
 )
@@
-  host, err := c.PortEndpoint(ctx, nat.Port(defaultHTTPPort), "")
+  hostPort, err := c.PortEndpoint(ctx, nat.Port(defaultHTTPPort), "")
   if err != nil {
     return "", err
   }
-  return fmt.Sprintf("http://%s:%s@%s/console", c.user, c.password, host), nil
+  u := url.URL{
+    Scheme: "http",
+    User:   url.UserPassword(c.user, c.password),
+    Host:   hostPort,
+    Path:   "/console",
+  }
+  return u.String(), nil
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 348c175 and f202755.

📒 Files selected for processing (2)
  • modules/artemis/artemis.go (3 hunks)
  • modules/artemis/artemis_test.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • modules/artemis/artemis_test.go
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-29T15:08:18.668Z
Learnt from: mdelapenya
PR: testcontainers/testcontainers-go#3320
File: modules/artemis/artemis.go:98-103
Timestamp: 2025-09-29T15:08:18.668Z
Learning: In testcontainers-go, nat.Port is a type alias for string, so untyped string constants can be passed directly to functions expecting nat.Port (like wait.ForListeningPort) without explicit type conversion - the Go compiler handles the implicit conversion automatically.

Applied to files:

  • modules/artemis/artemis.go
📚 Learning: 2025-09-29T13:57:14.629Z
Learnt from: mdelapenya
PR: testcontainers/testcontainers-go#3319
File: modules/arangodb/arangodb.go:46-57
Timestamp: 2025-09-29T13:57:14.629Z
Learning: In testcontainers-go ArangoDB module, the wait strategy combines port listening check with HTTP readiness check using wait.ForAll - both strategies are required and complementary, not redundant.

Applied to files:

  • modules/artemis/artemis.go
🧬 Code graph analysis (1)
modules/artemis/artemis.go (5)
options.go (4)
  • ContainerCustomizer (22-24)
  • WithExposedPorts (464-469)
  • WithEnv (75-85)
  • WithWaitStrategy (376-378)
wait/all.go (1)
  • ForAll (44-48)
wait/host_port.go (1)
  • ForListeningPort (67-69)
wait/log.go (1)
  • ForLog (118-120)
container.go (1)
  • Container (41-73)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: test (1.25.x, modules/artemis) / test: modules/artemis/1.25.x
  • GitHub Check: test (1.24.x, modules/artemis) / test: modules/artemis/1.24.x
  • GitHub Check: Analyze (go)
🔇 Additional comments (2)
modules/artemis/artemis.go (2)

98-103: ForListeningPort with untyped string constants is correct

Passing untyped string constants to ForListeningPort (nat.Port) is valid; no explicit nat.Port(...) cast is required.

Based on learnings.


129-135: strings.CutPrefix supported by Go 1.24
go.mod declares go 1.24, so strings.CutPrefix is available; no fallback needed.

@mdelapenya mdelapenya merged commit 13b5737 into testcontainers:main Sep 29, 2025
16 checks passed
@mdelapenya mdelapenya deleted the use-run-artemis branch September 29, 2025 15:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore Changes that do not impact the existing functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant