diff options
| author | Damien Neil <dneil@google.com> | 2025-08-15 15:24:05 -0700 |
|---|---|---|
| committer | Damien Neil <dneil@google.com> | 2025-10-07 14:39:32 -0700 |
| commit | bb1ca7ae81ea8ca49a2773ace8ccff8fbc7f4dfd (patch) | |
| tree | 0b65e043ac16bc325d7c36e615c65715bcf06626 /src/testing/testing_test.go | |
| parent | 162392773085d4cc12072200853a0424117983c0 (diff) | |
| download | go-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.go | 106 |
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()) +} |
