Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ type Config struct {
// Environment variable: TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX
HubImageNamePrefix string `properties:"hub.image.name.prefix,default="`

// SessionID is the ID of the testing session.
// Setting this value will preclude runs from creating more than one reaper. Therefore,
// changes to ryuk settings past its creation will be ignored.
//
// Environment variable: TESTCONTAINERS_SESSION_ID
SessionID string `properties:"session.id,default="`

// RyukDisabled is a flag to enable or disable the Garbage Collector.
// Setting this to true will prevent testcontainers from automatically cleaning up
// resources, which is particularly important in tests which timeout as they
Expand Down Expand Up @@ -121,6 +128,11 @@ func read() Config {
config.HubImageNamePrefix = hubImageNamePrefix
}

sessionID := os.Getenv("TESTCONTAINERS_SESSION_ID")
if sessionID != "" {
config.SessionID = sessionID
}

ryukPrivilegedEnv := os.Getenv("TESTCONTAINERS_RYUK_CONTAINER_PRIVILEGED")
if parseBool(ryukPrivilegedEnv) {
config.RyukPrivileged = ryukPrivilegedEnv == "true"
Expand Down
5 changes: 5 additions & 0 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const (
func resetTestEnv(t *testing.T) {
t.Helper()
t.Setenv("TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX", "")
t.Setenv("TESTCONTAINERS_SESSION_ID", "")
t.Setenv("TESTCONTAINERS_RYUK_DISABLED", "")
t.Setenv("TESTCONTAINERS_RYUK_CONTAINER_PRIVILEGED", "")
t.Setenv("RYUK_VERBOSE", "")
Expand Down Expand Up @@ -76,6 +77,7 @@ func TestReadTCConfig(t *testing.T) {
t.Setenv("USERPROFILE", "") // Windows support
t.Setenv("TESTCONTAINERS_RYUK_DISABLED", "true")
t.Setenv("TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX", defaultHubPrefix)
t.Setenv("TESTCONTAINERS_SESSION_ID", "foo")
t.Setenv("TESTCONTAINERS_RYUK_CONTAINER_PRIVILEGED", "true")
t.Setenv("RYUK_RECONNECTION_TIMEOUT", "13s")
t.Setenv("RYUK_CONNECTION_TIMEOUT", "12s")
Expand All @@ -84,6 +86,7 @@ func TestReadTCConfig(t *testing.T) {

expected := Config{
HubImageNamePrefix: defaultHubPrefix,
SessionID: "foo",
RyukDisabled: true,
RyukPrivileged: true,
Host: "", // docker socket is empty at the properties file
Expand Down Expand Up @@ -124,6 +127,7 @@ func TestReadTCConfig(t *testing.T) {
t.Setenv("USERPROFILE", tmpDir) // Windows support
t.Setenv("TESTCONTAINERS_RYUK_DISABLED", "true")
t.Setenv("TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX", defaultHubPrefix)
t.Setenv("TESTCONTAINERS_SESSION_ID", "foo")
t.Setenv("TESTCONTAINERS_RYUK_CONTAINER_PRIVILEGED", "true")
t.Setenv("RYUK_VERBOSE", "true")
t.Setenv("RYUK_RECONNECTION_TIMEOUT", "13s")
Expand All @@ -132,6 +136,7 @@ func TestReadTCConfig(t *testing.T) {
config := read()
expected := Config{
HubImageNamePrefix: defaultHubPrefix,
SessionID: "foo",
RyukDisabled: true,
RyukPrivileged: true,
RyukVerbose: true,
Expand Down
31 changes: 22 additions & 9 deletions internal/core/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (

"github.com/google/uuid"
"github.com/shirou/gopsutil/v4/process"

"github.com/testcontainers/testcontainers-go/internal/config"
)

// sessionID returns a unique session ID for the current test session. Because each Go package
Expand Down Expand Up @@ -45,6 +47,11 @@ var processID string
const sessionIDPlaceholder = "testcontainers-go:%d:%d"

func init() {
cfg := config.Read()
Copy link
Contributor

Choose a reason for hiding this comment

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

@mdelapenya could calling config.Read() in init cause undesired behaviour due to how early it called?

I'm thinking this would prevent things like changing the environment variables in a test from having the desired effect as an example.

Copy link
Author

@jcmfernandes jcmfernandes Sep 13, 2025

Choose a reason for hiding this comment

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

Thanks for the feedback, @stevenh. I understand your concern: reading the config in an init() function felt wrong.

I change the code so that config.Read falls back to the session in core/bootstrap (I moved bootstrap.go to a new package to avoid import cycle between internal/config and internal/core). Please let me know what you think.

if cfg.SessionID != "" {
sessionID = cfg.SessionID
}

processID = uuid.New().String()

parentPid := os.Getppid()
Expand All @@ -57,7 +64,9 @@ func init() {

processes, err := process.Processes()
if err != nil {
sessionID = uuid.New().String()
if sessionID == "" {
sessionID = uuid.New().String()
}
projectPath = fallbackCwd
return
}
Expand All @@ -75,22 +84,26 @@ func init() {

t, err := p.CreateTime()
if err != nil {
sessionID = uuid.New().String()
if sessionID == "" {
sessionID = uuid.New().String()
}
return
}

createTime = t
break
}

hasher := sha256.New()
_, err = fmt.Fprintf(hasher, sessionIDPlaceholder, parentPid, createTime)
if err != nil {
sessionID = uuid.New().String()
return
}
if sessionID == "" {
hasher := sha256.New()
_, err = fmt.Fprintf(hasher, sessionIDPlaceholder, parentPid, createTime)
if err != nil {
sessionID = uuid.New().String()
return
}

sessionID = hex.EncodeToString(hasher.Sum(nil))
sessionID = hex.EncodeToString(hasher.Sum(nil))
}
}

func ProcessID() string {
Expand Down
Loading