From f0e5ad819b6607bc2f957892ace44c66702c9171 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 2 Aug 2025 02:04:36 +0900 Subject: [PATCH 1/5] testing: allow specify TempDir() by GOTMPDIR --- src/testing/testing.go | 2 +- src/testing/testing_test.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/testing/testing.go b/src/testing/testing.go index 3475bfca4a6976..18b63164f4ec6f 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -1362,7 +1362,7 @@ func (c *common) TempDir() string { return -1 } pattern = strings.Map(mapper, pattern) - c.tempDir, c.tempDirErr = os.MkdirTemp("", pattern) + c.tempDir, c.tempDirErr = os.MkdirTemp(os.Getenv("GOTMPDIR"), pattern) if c.tempDirErr == nil { c.Cleanup(func() { if err := removeAll(c.tempDir); err != nil { diff --git a/src/testing/testing_test.go b/src/testing/testing_test.go index f4f5817a37ddb3..2110ba7582dfad 100644 --- a/src/testing/testing_test.go +++ b/src/testing/testing_test.go @@ -147,6 +147,41 @@ func testTempDir(t *testing.T) { } } +func TestTempDirGOTMPDIR(t *testing.T) { + customTmpDir := filepath.Join(os.TempDir(), "custom-gotmpdir-test") + if err := os.MkdirAll(customTmpDir, 0777); err != nil { + t.Fatal(err) + } + defer os.RemoveAll(customTmpDir) + + oldValue, hadOld := os.LookupEnv("GOTMPDIR") + if err := os.Setenv("GOTMPDIR", customTmpDir); err != nil { + t.Fatal(err) + } + if hadOld { + defer os.Setenv("GOTMPDIR", oldValue) + } else { + defer os.Unsetenv("GOTMPDIR") + } + + dir := t.TempDir() + if dir == "" { + t.Fatal("expected dir") + } + + if !strings.HasPrefix(dir, customTmpDir) { + t.Errorf("TempDir did not use GOTMPDIR: got %q, want prefix %q", dir, customTmpDir) + } + + fi, err := os.Stat(dir) + if err != nil { + t.Fatal(err) + } + if !fi.IsDir() { + t.Errorf("dir %q is not a dir", dir) + } +} + func TestSetenv(t *testing.T) { tests := []struct { name string From 87143d622695db9086a76b7f02cdb89fa14b28a6 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 2 Aug 2025 03:10:00 +0900 Subject: [PATCH 2/5] use t.Setenv to simplify test --- src/testing/testing_test.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/testing/testing_test.go b/src/testing/testing_test.go index 2110ba7582dfad..5250e5ff5a7700 100644 --- a/src/testing/testing_test.go +++ b/src/testing/testing_test.go @@ -154,15 +154,7 @@ func TestTempDirGOTMPDIR(t *testing.T) { } defer os.RemoveAll(customTmpDir) - oldValue, hadOld := os.LookupEnv("GOTMPDIR") - if err := os.Setenv("GOTMPDIR", customTmpDir); err != nil { - t.Fatal(err) - } - if hadOld { - defer os.Setenv("GOTMPDIR", oldValue) - } else { - defer os.Unsetenv("GOTMPDIR") - } + t.Setenv("GOTMPDIR", customTmpDir) dir := t.TempDir() if dir == "" { From ed612870b981dc60520264a46d31d86ac3584623 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 2 Aug 2025 15:56:09 +0900 Subject: [PATCH 3/5] Update go help doc --- src/cmd/go/alldocs.go | 5 +++-- src/cmd/go/internal/help/helpdoc.go | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 7403b92cd14a3c..a0d7b4a8ea5df5 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -2405,8 +2405,9 @@ // The name of checksum database to use and optionally its public key and // URL. See https://golang.org/ref/mod#authenticating. // GOTMPDIR -// The directory where the go command will write -// temporary source files, packages, and binaries. +// The directory where the go command will write temporary source files, +// packages, and binaries. +// Also used to specify the prefix of TmpDir function in testing package. // GOTOOLCHAIN // Controls which Go toolchain is used. See https://go.dev/doc/toolchain. // GOVCS diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index 7f8565a3cbab82..a49578f47f2e75 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -573,8 +573,9 @@ General-purpose environment variables: The name of checksum database to use and optionally its public key and URL. See https://golang.org/ref/mod#authenticating. GOTMPDIR - The directory where the go command will write - temporary source files, packages, and binaries. + The directory where the go command will write temporary source files, + packages, and binaries. + Also used to specify the prefix of TmpDir function in testing package. GOTOOLCHAIN Controls which Go toolchain is used. See https://go.dev/doc/toolchain. GOVCS From 2d2c3fd7e82cbd4c150498496976dbf365718e83 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 2 Aug 2025 21:40:45 +0900 Subject: [PATCH 4/5] Update test case --- src/testing/testing_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/testing/testing_test.go b/src/testing/testing_test.go index 5250e5ff5a7700..97324724a3414b 100644 --- a/src/testing/testing_test.go +++ b/src/testing/testing_test.go @@ -172,6 +172,13 @@ func TestTempDirGOTMPDIR(t *testing.T) { if !fi.IsDir() { t.Errorf("dir %q is not a dir", dir) } + + t.Setenv("GOTMPDIR", "another-custom-gotmpdir-test") + + dir2 := t.TempDir() + if filepath.Dir(dir) != filepath.Dir(dir2) { + t.Fatalf("calls to TempDir after changed GOTMPDIR do not share a parent; got %q, %q", dir, dir2) + } } func TestSetenv(t *testing.T) { From aeacea00952b11990b49a0fde6a0ce4fe910b777 Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 12 Aug 2025 23:02:30 +0900 Subject: [PATCH 5/5] Update by comment --- src/cmd/go/alldocs.go | 7 ++++--- src/cmd/go/internal/help/helpdoc.go | 7 ++++--- src/testing/testing.go | 2 ++ src/testing/testing_test.go | 13 ++++++------- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index a0d7b4a8ea5df5..f29e16782064f6 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -2405,9 +2405,10 @@ // The name of checksum database to use and optionally its public key and // URL. See https://golang.org/ref/mod#authenticating. // GOTMPDIR -// The directory where the go command will write temporary source files, -// packages, and binaries. -// Also used to specify the prefix of TmpDir function in testing package. +// Temporary directory used by the go command and testing package. +// Overrides the platform-specific temporary directory such as "/tmp". +// The go command and testing package will write temporary source files, +// packages, and binaries here. // GOTOOLCHAIN // Controls which Go toolchain is used. See https://go.dev/doc/toolchain. // GOVCS diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index a49578f47f2e75..8319e9ad133ab1 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -573,9 +573,10 @@ General-purpose environment variables: The name of checksum database to use and optionally its public key and URL. See https://golang.org/ref/mod#authenticating. GOTMPDIR - The directory where the go command will write temporary source files, - packages, and binaries. - Also used to specify the prefix of TmpDir function in testing package. + Temporary directory used by the go command and testing package. + Overrides the platform-specific temporary directory such as "/tmp". + The go command and testing package will write temporary source files, + packages, and binaries here. GOTOOLCHAIN Controls which Go toolchain is used. See https://go.dev/doc/toolchain. GOVCS diff --git a/src/testing/testing.go b/src/testing/testing.go index 18b63164f4ec6f..2f0206b0a4dae1 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -1318,6 +1318,8 @@ func (c *common) Cleanup(f func()) { // all its subtests complete. // Each subsequent call to TempDir returns a unique directory; // if the directory creation fails, TempDir terminates the test by calling Fatal. +// If the environment variable GOTMPDIR is set, the temporary directory will +// be created somewhere beneath it. func (c *common) TempDir() string { c.checkFuzzFn("TempDir") // Use a single parent directory for all the temporary directories diff --git a/src/testing/testing_test.go b/src/testing/testing_test.go index 97324724a3414b..cc89e4144e6a78 100644 --- a/src/testing/testing_test.go +++ b/src/testing/testing_test.go @@ -148,6 +148,12 @@ func testTempDir(t *testing.T) { } func TestTempDirGOTMPDIR(t *testing.T) { + // The first call to t.TempDir will create a parent temporary directory + // that will contain all temporary directories created by TempDir. + // + // Use os.TempDir (not t.TempDir) to get a temporary directory, + // set GOTMPDIR to that directory, + // and then verify that t.TempDir creates a directory in GOTMPDIR. customTmpDir := filepath.Join(os.TempDir(), "custom-gotmpdir-test") if err := os.MkdirAll(customTmpDir, 0777); err != nil { t.Fatal(err) @@ -172,13 +178,6 @@ func TestTempDirGOTMPDIR(t *testing.T) { if !fi.IsDir() { t.Errorf("dir %q is not a dir", dir) } - - t.Setenv("GOTMPDIR", "another-custom-gotmpdir-test") - - dir2 := t.TempDir() - if filepath.Dir(dir) != filepath.Dir(dir2) { - t.Fatalf("calls to TempDir after changed GOTMPDIR do not share a parent; got %q, %q", dir, dir2) - } } func TestSetenv(t *testing.T) {