aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
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/cmd
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/cmd')
-rw-r--r--src/cmd/go/alldocs.go12
-rw-r--r--src/cmd/go/internal/load/test.go9
-rw-r--r--src/cmd/go/internal/test/flagdefs.go1
-rw-r--r--src/cmd/go/internal/test/test.go13
-rw-r--r--src/cmd/go/internal/test/testflag.go4
-rw-r--r--src/cmd/internal/test2json/test2json.go24
6 files changed, 41 insertions, 22 deletions
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index 19b48f0579..51f2223283 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -3244,6 +3244,10 @@
// The following flags are recognized by the 'go test' command and
// control the execution of any test:
//
+// -artifacts
+// Save test artifacts in the directory specified by -outputdir.
+// See 'go doc testing.T.ArtifactDir'.
+//
// -bench regexp
// Run only those benchmarks matching a regular expression.
// By default, no benchmarks are run.
@@ -3338,6 +3342,10 @@
// This will only list top-level tests. No subtest or subbenchmarks will be
// shown.
//
+// -outputdir directory
+// Place output files from profiling and test artifacts in the
+// specified directory, by default the directory in which "go test" is running.
+//
// -parallel n
// Allow parallel execution of test functions that call t.Parallel, and
// fuzz targets that call t.Parallel when running the seed corpus.
@@ -3449,10 +3457,6 @@
// Sample 1 in n stack traces of goroutines holding a
// contended mutex.
//
-// -outputdir directory
-// Place output files from profiling in the specified directory,
-// by default the directory in which "go test" is running.
-//
// -trace trace.out
// Write an execution trace to the specified file before exiting.
//
diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go
index f895e3a246..9849ee138a 100644
--- a/src/cmd/go/internal/load/test.go
+++ b/src/cmd/go/internal/load/test.go
@@ -649,6 +649,14 @@ func (t *testFuncs) ImportPath() string {
return pkg
}
+func (t *testFuncs) ModulePath() string {
+ m := t.Package.Module
+ if m == nil {
+ return ""
+ }
+ return m.Path
+}
+
// Covered returns a string describing which packages are being tested for coverage.
// If the covered package is the same as the tested package, it returns the empty string.
// Otherwise it is a comma-separated human-readable list of packages beginning with
@@ -836,6 +844,7 @@ func init() {
testdeps.CoverMarkProfileEmittedFunc = cfile.MarkProfileEmitted
{{end}}
+ testdeps.ModulePath = {{.ModulePath | printf "%q"}}
testdeps.ImportPath = {{.ImportPath | printf "%q"}}
}
diff --git a/src/cmd/go/internal/test/flagdefs.go b/src/cmd/go/internal/test/flagdefs.go
index 8aa0bfc2bf..b8b4bf649e 100644
--- a/src/cmd/go/internal/test/flagdefs.go
+++ b/src/cmd/go/internal/test/flagdefs.go
@@ -9,6 +9,7 @@ package test
// passFlagToTest contains the flags that should be forwarded to
// the test binary with the prefix "test.".
var passFlagToTest = map[string]bool{
+ "artifacts": true,
"bench": true,
"benchmem": true,
"benchtime": true,
diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go
index 7a2963ff29..15ffc618c6 100644
--- a/src/cmd/go/internal/test/test.go
+++ b/src/cmd/go/internal/test/test.go
@@ -192,6 +192,10 @@ and -show_bytes options of pprof control how the information is presented.
The following flags are recognized by the 'go test' command and
control the execution of any test:
+ -artifacts
+ Save test artifacts in the directory specified by -outputdir.
+ See 'go doc testing.T.ArtifactDir'.
+
-bench regexp
Run only those benchmarks matching a regular expression.
By default, no benchmarks are run.
@@ -286,6 +290,10 @@ control the execution of any test:
This will only list top-level tests. No subtest or subbenchmarks will be
shown.
+ -outputdir directory
+ Place output files from profiling and test artifacts in the
+ specified directory, by default the directory in which "go test" is running.
+
-parallel n
Allow parallel execution of test functions that call t.Parallel, and
fuzz targets that call t.Parallel when running the seed corpus.
@@ -397,10 +405,6 @@ profile the tests during execution:
Sample 1 in n stack traces of goroutines holding a
contended mutex.
- -outputdir directory
- Place output files from profiling in the specified directory,
- by default the directory in which "go test" is running.
-
-trace trace.out
Write an execution trace to the specified file before exiting.
@@ -540,6 +544,7 @@ See the documentation of the testing package for more information.
}
var (
+ testArtifacts bool // -artifacts flag
testBench string // -bench flag
testC bool // -c flag
testCoverPkgs []*load.Package // -coverpkg flag
diff --git a/src/cmd/go/internal/test/testflag.go b/src/cmd/go/internal/test/testflag.go
index 983e8f56e9..fc2b22cb56 100644
--- a/src/cmd/go/internal/test/testflag.go
+++ b/src/cmd/go/internal/test/testflag.go
@@ -44,6 +44,7 @@ func init() {
// some of them so that cmd/go knows what to do with the test output, or knows
// to build the test in a way that supports the use of the flag.
+ cf.BoolVar(&testArtifacts, "artifacts", false, "")
cf.StringVar(&testBench, "bench", "", "")
cf.Bool("benchmem", false, "")
cf.String("benchtime", "", "")
@@ -392,7 +393,8 @@ func testFlags(args []string) (packageNames, passToTest []string) {
// directory, but 'go test' defaults it to the working directory of the 'go'
// command. Set it explicitly if it is needed due to some other flag that
// requests output.
- if testProfile() != "" && !outputDirSet {
+ needOutputDir := testProfile() != "" || testArtifacts
+ if needOutputDir && !outputDirSet {
injectedFlags = append(injectedFlags, "-test.outputdir="+testOutputDir.getAbs())
}
diff --git a/src/cmd/internal/test2json/test2json.go b/src/cmd/internal/test2json/test2json.go
index d08ef389f8..f28051e177 100644
--- a/src/cmd/internal/test2json/test2json.go
+++ b/src/cmd/internal/test2json/test2json.go
@@ -38,6 +38,7 @@ type event struct {
FailedBuild string `json:",omitempty"`
Key string `json:",omitempty"`
Value string `json:",omitempty"`
+ Path string `json:",omitempty"`
}
// textBytes is a hack to get JSON to emit a []byte as a string
@@ -180,6 +181,7 @@ var (
[]byte("=== FAIL "),
[]byte("=== SKIP "),
[]byte("=== ATTR "),
+ []byte("=== ARTIFACTS "),
}
reports = [][]byte{
@@ -251,7 +253,6 @@ func (c *Converter) handleInputLine(line []byte) {
// "=== RUN "
// "=== PAUSE "
// "=== CONT "
- actionColon := false
origLine := line
ok := false
indent := 0
@@ -273,7 +274,6 @@ func (c *Converter) handleInputLine(line []byte) {
}
for _, magic := range reports {
if bytes.HasPrefix(line, magic) {
- actionColon = true
ok = true
break
}
@@ -296,16 +296,11 @@ func (c *Converter) handleInputLine(line []byte) {
return
}
- // Parse out action and test name.
- i := 0
- if actionColon {
- i = bytes.IndexByte(line, ':') + 1
- }
- if i == 0 {
- i = len(updates[0])
- }
- action := strings.ToLower(strings.TrimSuffix(strings.TrimSpace(string(line[4:i])), ":"))
- name := strings.TrimSpace(string(line[i:]))
+ // Parse out action and test name from "=== ACTION: Name".
+ action, name, _ := strings.Cut(string(line[len("=== "):]), " ")
+ action = strings.TrimSuffix(action, ":")
+ action = strings.ToLower(action)
+ name = strings.TrimSpace(name)
e := &event{Action: action}
if line[0] == '-' { // PASS or FAIL report
@@ -336,7 +331,10 @@ func (c *Converter) handleInputLine(line []byte) {
c.output.write(origLine)
return
}
- if action == "attr" {
+ switch action {
+ case "artifacts":
+ name, e.Path, _ = strings.Cut(name, " ")
+ case "attr":
var rest string
name, rest, _ = strings.Cut(name, " ")
e.Key, e.Value, _ = strings.Cut(rest, " ")