aboutsummaryrefslogtreecommitdiff
path: root/src/testing/testing_test.go
diff options
context:
space:
mode:
authorDamien Neil <dneil@google.com>2025-08-15 15:24:05 -0700
committerDamien Neil <dneil@google.com>2025-10-07 14:39:32 -0700
commitbb1ca7ae81ea8ca49a2773ace8ccff8fbc7f4dfd (patch)
tree0b65e043ac16bc325d7c36e615c65715bcf06626 /src/testing/testing_test.go
parent162392773085d4cc12072200853a0424117983c0 (diff)
downloadgo-bb1ca7ae81ea8ca49a2773ace8ccff8fbc7f4dfd.tar.xz
cmd/go, testing: add TB.ArtifactDir and -artifacts flag
Add TB.ArtifactDir, which returns a directory for a test to store output files in. Add a -artifacts testflag which enables persistent storage of artifacts in the output directory (-outputdir, or the current directory by default). Fixes #71287 Change-Id: I5f6515a6cd6c103f88588f4c033d5ea11ffd0c3c Reviewed-on: https://go-review.googlesource.com/c/go/+/696399 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Alan Donovan <adonovan@google.com>
Diffstat (limited to 'src/testing/testing_test.go')
-rw-r--r--src/testing/testing_test.go106
1 files changed, 105 insertions, 1 deletions
diff --git a/src/testing/testing_test.go b/src/testing/testing_test.go
index cc89e4144e..167f4a0b45 100644
--- a/src/testing/testing_test.go
+++ b/src/testing/testing_test.go
@@ -469,7 +469,7 @@ func TestTesting(t *testing.T) {
// runTest runs a helper test with -test.v, ignoring its exit status.
// runTest both logs and returns the test output.
-func runTest(t *testing.T, test string) []byte {
+func runTest(t *testing.T, test string, args ...string) []byte {
t.Helper()
testenv.MustHaveExec(t)
@@ -477,6 +477,7 @@ func runTest(t *testing.T, test string) []byte {
cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+test+"$", "-test.bench="+test, "-test.v", "-test.parallel=2", "-test.benchtime=2x")
cmd = testenv.CleanCmdEnv(cmd)
cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1")
+ cmd.Args = append(cmd.Args, args...)
out, err := cmd.CombinedOutput()
t.Logf("%v: %v\n%s", cmd, err, out)
@@ -1055,6 +1056,105 @@ func TestAttrInvalid(t *testing.T) {
}
}
+const artifactContent = "It belongs in a museum.\n"
+
+func TestArtifactDirExample(t *testing.T) {
+ os.WriteFile(filepath.Join(t.ArtifactDir(), "artifact"), []byte(artifactContent), 0o666)
+}
+
+func TestArtifactDirDefault(t *testing.T) {
+ tempDir := t.TempDir()
+ t.Chdir(tempDir)
+ out := runTest(t, "TestArtifactDirExample", "-test.artifacts")
+ checkArtifactDir(t, out, "TestArtifactDirExample", tempDir)
+}
+
+func TestArtifactDirSpecified(t *testing.T) {
+ tempDir := t.TempDir()
+ out := runTest(t, "TestArtifactDirExample", "-test.artifacts", "-test.outputdir="+tempDir)
+ checkArtifactDir(t, out, "TestArtifactDirExample", tempDir)
+}
+
+func TestArtifactDirNoArtifacts(t *testing.T) {
+ t.Chdir(t.TempDir())
+ out := string(runTest(t, "TestArtifactDirExample"))
+ if strings.Contains(out, "=== ARTIFACTS") {
+ t.Errorf("expected output with no === ARTIFACTS, got\n%q", out)
+ }
+ ents, err := os.ReadDir(".")
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, e := range ents {
+ t.Errorf("unexpected file in current directory after test: %v", e.Name())
+ }
+}
+
+func TestArtifactDirSubtestExample(t *testing.T) {
+ t.Run("Subtest", func(t *testing.T) {
+ os.WriteFile(filepath.Join(t.ArtifactDir(), "artifact"), []byte(artifactContent), 0o666)
+ })
+}
+
+func TestArtifactDirInSubtest(t *testing.T) {
+ tempDir := t.TempDir()
+ out := runTest(t, "TestArtifactDirSubtestExample/Subtest", "-test.artifacts", "-test.outputdir="+tempDir)
+ checkArtifactDir(t, out, "TestArtifactDirSubtestExample/Subtest", tempDir)
+}
+
+func TestArtifactDirLongTestNameExample(t *testing.T) {
+ name := strings.Repeat("x", 256)
+ t.Run(name, func(t *testing.T) {
+ os.WriteFile(filepath.Join(t.ArtifactDir(), "artifact"), []byte(artifactContent), 0o666)
+ })
+}
+
+func TestArtifactDirWithLongTestName(t *testing.T) {
+ tempDir := t.TempDir()
+ out := runTest(t, "TestArtifactDirLongTestNameExample", "-test.artifacts", "-test.outputdir="+tempDir)
+ checkArtifactDir(t, out, `TestArtifactDirLongTestNameExample/\w+`, tempDir)
+}
+
+func TestArtifactDirConsistent(t *testing.T) {
+ a := t.ArtifactDir()
+ b := t.ArtifactDir()
+ if a != b {
+ t.Errorf("t.ArtifactDir is not consistent between calls: %q, %q", a, b)
+ }
+}
+
+func checkArtifactDir(t *testing.T, out []byte, testName, outputDir string) {
+ t.Helper()
+
+ re := regexp.MustCompile(`=== ARTIFACTS ` + testName + ` ([^\n]+)`)
+ match := re.FindSubmatch(out)
+ if match == nil {
+ t.Fatalf("expected output matching %q, got\n%q", re, out)
+ }
+ artifactDir := string(match[1])
+
+ // Verify that the artifact directory is contained in the expected output directory.
+ relDir, err := filepath.Rel(outputDir, artifactDir)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !filepath.IsLocal(relDir) {
+ t.Fatalf("want artifact directory contained in %q, got %q", outputDir, artifactDir)
+ }
+
+ for _, part := range strings.Split(relDir, string(os.PathSeparator)) {
+ const maxSize = 64
+ if len(part) > maxSize {
+ t.Errorf("artifact directory %q contains component >%v characters long: %q", relDir, maxSize, part)
+ }
+ }
+
+ got, err := os.ReadFile(filepath.Join(artifactDir, "artifact"))
+ if err != nil || string(got) != artifactContent {
+ t.Errorf("reading artifact in %q: got %q, %v; want %q", artifactDir, got, err, artifactContent)
+ }
+}
+
func TestBenchmarkBLoopIterationCorrect(t *testing.T) {
out := runTest(t, "BenchmarkBLoopPrint")
c := bytes.Count(out, []byte("Printing from BenchmarkBLoopPrint"))
@@ -1110,3 +1210,7 @@ func BenchmarkBNPrint(b *testing.B) {
b.Logf("Printing from BenchmarkBNPrint")
}
}
+
+func TestArtifactDir(t *testing.T) {
+ t.Log(t.ArtifactDir())
+}