Skip to content

Commit 3bb3919

Browse files
committed
feat: make the session ID configurable
This allows for long-running sessions - e.g., across multiple runs - to reuse the reaper.
1 parent fcdde64 commit 3bb3919

File tree

2 files changed

+21
-44
lines changed

2 files changed

+21
-44
lines changed

internal/config/config.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ type Config struct {
5252
// Environment variable: TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX
5353
HubImageNamePrefix string `properties:"hub.image.name.prefix,default="`
5454

55+
// SessionID is the ID of the testing session.
56+
// Setting this value will preclude runs from creating more than one reaper. Therefore,
57+
// changes to ryuk settings past its creation will be ignored.
58+
//
59+
// Environment variable: TESTCONTAINERS_SESSION_ID
60+
SessionID string `properties:"session.id,default="`
61+
5562
// RyukDisabled is a flag to enable or disable the Garbage Collector.
5663
// Setting this to true will prevent testcontainers from automatically cleaning up
5764
// resources, which is particularly important in tests which timeout as they
@@ -111,6 +118,11 @@ func read() Config {
111118
config := Config{}
112119

113120
applyEnvironmentConfiguration := func(config Config) Config {
121+
sessionID := os.Getenv("TESTCONTAINERS_SESSION_ID")
122+
if sessionID != "" {
123+
config.SessionID = sessionID
124+
}
125+
114126
ryukDisabledEnv := os.Getenv("TESTCONTAINERS_RYUK_DISABLED")
115127
if parseBool(ryukDisabledEnv) {
116128
config.RyukDisabled = ryukDisabledEnv == "true"

internal/core/bootstrap.go

Lines changed: 9 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,14 @@
11
package core
22

33
import (
4-
"crypto/sha256"
5-
"encoding/hex"
6-
"fmt"
74
"os"
85

96
"github.com/google/uuid"
107
"github.com/shirou/gopsutil/v4/process"
8+
"github.com/testcontainers/testcontainers-go/internal/config"
119
)
1210

13-
// sessionID returns a unique session ID for the current test session. Because each Go package
14-
// will be run in a separate process, we need a way to identify the current test session.
15-
// By test session, we mean:
16-
// - a single "go test" invocation (including flags)
17-
// - a single "go test ./..." invocation (including flags)
18-
// - the execution of a single test or a set of tests using the IDE
19-
//
20-
// As a consequence, with the sole goal of aggregating test execution across multiple
21-
// packages, this function will use the parent process ID (pid) of the current process
22-
// and its creation date, to use it to generate a unique session ID. We are using the parent pid because
23-
// the current process will be a child process of:
24-
// - the process that is running the tests, e.g.: "go test";
25-
// - the process that is running the application in development mode, e.g. "go run main.go -tags dev";
26-
// - the process that is running the tests in the IDE, e.g.: "go test ./...".
27-
//
28-
// Finally, we will hash the combination of the "testcontainers-go:" string with the parent pid
29-
// and the creation date of that parent process to generate a unique session ID.
30-
//
31-
// This sessionID will be used to:
32-
// - identify the test session, aggregating the test execution of multiple packages in the same test session.
33-
// - tag the containers created by testcontainers-go, adding a label to the container with the session ID.
11+
// sessionID returns a unique session ID for the current test session.
3412
var sessionID string
3513

3614
// projectPath returns the current working directory of the parent test process running Testcontainers for Go.
@@ -42,13 +20,17 @@ var projectPath string
4220
// we need a way to identify the current test process, in the form of a UUID
4321
var processID string
4422

45-
const sessionIDPlaceholder = "testcontainers-go:%d:%d"
46-
4723
func init() {
24+
cfg := config.Read()
25+
if cfg.SessionID != "" {
26+
sessionID = cfg.SessionID
27+
} else {
28+
sessionID = uuid.New().String()
29+
}
30+
4831
processID = uuid.New().String()
4932

5033
parentPid := os.Getppid()
51-
var createTime int64
5234
fallbackCwd, err := os.Getwd()
5335
if err != nil {
5436
// very unlikely to fail, but if it does, we will use a temp dir
@@ -57,7 +39,6 @@ func init() {
5739

5840
processes, err := process.Processes()
5941
if err != nil {
60-
sessionID = uuid.New().String()
6142
projectPath = fallbackCwd
6243
return
6344
}
@@ -73,24 +54,8 @@ func init() {
7354
}
7455
projectPath = cwd
7556

76-
t, err := p.CreateTime()
77-
if err != nil {
78-
sessionID = uuid.New().String()
79-
return
80-
}
81-
82-
createTime = t
8357
break
8458
}
85-
86-
hasher := sha256.New()
87-
_, err = hasher.Write([]byte(fmt.Sprintf(sessionIDPlaceholder, parentPid, createTime)))
88-
if err != nil {
89-
sessionID = uuid.New().String()
90-
return
91-
}
92-
93-
sessionID = hex.EncodeToString(hasher.Sum(nil))
9459
}
9560

9661
func ProcessID() string {

0 commit comments

Comments
 (0)