11package core
22
33import (
4+ "crypto/sha256"
5+ "encoding/hex"
6+ "fmt"
47 "os"
58
69 "github.com/google/uuid"
710 "github.com/shirou/gopsutil/v4/process"
811 "github.com/testcontainers/testcontainers-go/internal/config"
912)
1013
11- // sessionID returns a unique session ID for the current test session.
14+ // sessionID returns a unique session ID for the current test session. Because each Go package
15+ // will be run in a separate process, we need a way to identify the current test session.
16+ // By test session, we mean:
17+ // - a single "go test" invocation (including flags)
18+ // - a single "go test ./..." invocation (including flags)
19+ // - the execution of a single test or a set of tests using the IDE
20+ //
21+ // As a consequence, with the sole goal of aggregating test execution across multiple
22+ // packages, this function will use the parent process ID (pid) of the current process
23+ // and its creation date, to use it to generate a unique session ID. We are using the parent pid because
24+ // the current process will be a child process of:
25+ // - the process that is running the tests, e.g.: "go test";
26+ // - the process that is running the application in development mode, e.g. "go run main.go -tags dev";
27+ // - the process that is running the tests in the IDE, e.g.: "go test ./...".
28+ //
29+ // Finally, we will hash the combination of the "testcontainers-go:" string with the parent pid
30+ // and the creation date of that parent process to generate a unique session ID.
31+ //
32+ // This sessionID will be used to:
33+ // - identify the test session, aggregating the test execution of multiple packages in the same test session.
34+ // - tag the containers created by testcontainers-go, adding a label to the container with the session ID.
1235var sessionID string
1336
1437// projectPath returns the current working directory of the parent test process running Testcontainers for Go.
@@ -20,17 +43,18 @@ var projectPath string
2043// we need a way to identify the current test process, in the form of a UUID
2144var processID string
2245
46+ const sessionIDPlaceholder = "testcontainers-go:%d:%d"
47+
2348func init () {
2449 cfg := config .Read ()
2550 if cfg .SessionID != "" {
2651 sessionID = cfg .SessionID
27- } else {
28- sessionID = uuid .New ().String ()
2952 }
3053
3154 processID = uuid .New ().String ()
3255
3356 parentPid := os .Getppid ()
57+ var createTime int64
3458 fallbackCwd , err := os .Getwd ()
3559 if err != nil {
3660 // very unlikely to fail, but if it does, we will use a temp dir
@@ -39,6 +63,9 @@ func init() {
3963
4064 processes , err := process .Processes ()
4165 if err != nil {
66+ if sessionID == "" {
67+ sessionID = uuid .New ().String ()
68+ }
4269 projectPath = fallbackCwd
4370 return
4471 }
@@ -54,8 +81,28 @@ func init() {
5481 }
5582 projectPath = cwd
5683
84+ t , err := p .CreateTime ()
85+ if err != nil {
86+ if sessionID == "" {
87+ sessionID = uuid .New ().String ()
88+ }
89+ return
90+ }
91+
92+ createTime = t
5793 break
5894 }
95+
96+ if sessionID == "" {
97+ hasher := sha256 .New ()
98+ _ , err = fmt .Fprintf (hasher , sessionIDPlaceholder , parentPid , createTime )
99+ if err != nil {
100+ sessionID = uuid .New ().String ()
101+ return
102+ }
103+
104+ sessionID = hex .EncodeToString (hasher .Sum (nil ))
105+ }
59106}
60107
61108func ProcessID () string {
0 commit comments