1
2
3
4
5 package test
6
7 import (
8 "bytes"
9 "context"
10 "errors"
11 "fmt"
12 "internal/coverage"
13 "internal/platform"
14 "io"
15 "io/fs"
16 "os"
17 "os/exec"
18 "path/filepath"
19 "regexp"
20 "slices"
21 "strconv"
22 "strings"
23 "sync"
24 "sync/atomic"
25 "time"
26
27 "cmd/go/internal/base"
28 "cmd/go/internal/cache"
29 "cmd/go/internal/cfg"
30 "cmd/go/internal/load"
31 "cmd/go/internal/lockedfile"
32 "cmd/go/internal/modload"
33 "cmd/go/internal/search"
34 "cmd/go/internal/str"
35 "cmd/go/internal/trace"
36 "cmd/go/internal/work"
37 "cmd/internal/test2json"
38
39 "golang.org/x/mod/module"
40 )
41
42
43 func init() {
44 CmdTest.Run = runTest
45 }
46
47 const testUsage = "go test [build/test flags] [packages] [build/test flags & test binary flags]"
48
49 var CmdTest = &base.Command{
50 CustomFlags: true,
51 UsageLine: testUsage,
52 Short: "test packages",
53 Long: `
54 'Go test' automates testing the packages named by the import paths.
55 It prints a summary of the test results in the format:
56
57 ok archive/tar 0.011s
58 FAIL archive/zip 0.022s
59 ok compress/gzip 0.033s
60 ...
61
62 followed by detailed output for each failed package.
63
64 'Go test' recompiles each package along with any files with names matching
65 the file pattern "*_test.go".
66 These additional files can contain test functions, benchmark functions, fuzz
67 tests and example functions. See 'go help testfunc' for more.
68 Each listed package causes the execution of a separate test binary.
69 Files whose names begin with "_" (including "_test.go") or "." are ignored.
70
71 Test files that declare a package with the suffix "_test" will be compiled as a
72 separate package, and then linked and run with the main test binary.
73
74 The go tool will ignore a directory named "testdata", making it available
75 to hold ancillary data needed by the tests.
76
77 As part of building a test binary, go test runs go vet on the package
78 and its test source files to identify significant problems. If go vet
79 finds any problems, go test reports those and does not run the test
80 binary. Only a high-confidence subset of the default go vet checks are
81 used. That subset is: atomic, bool, buildtags, directive, errorsas,
82 ifaceassert, nilfunc, printf, stringintconv, and tests. You can see
83 the documentation for these and other vet tests via "go doc cmd/vet".
84 To disable the running of go vet, use the -vet=off flag. To run all
85 checks, use the -vet=all flag.
86
87 All test output and summary lines are printed to the go command's
88 standard output, even if the test printed them to its own standard
89 error. (The go command's standard error is reserved for printing
90 errors building the tests.)
91
92 The go command places $GOROOT/bin at the beginning of $PATH
93 in the test's environment, so that tests that execute
94 'go' commands use the same 'go' as the parent 'go test' command.
95
96 Go test runs in two different modes:
97
98 The first, called local directory mode, occurs when go test is
99 invoked with no package arguments (for example, 'go test' or 'go
100 test -v'). In this mode, go test compiles the package sources and
101 tests found in the current directory and then runs the resulting
102 test binary. In this mode, caching (discussed below) is disabled.
103 After the package test finishes, go test prints a summary line
104 showing the test status ('ok' or 'FAIL'), package name, and elapsed
105 time.
106
107 The second, called package list mode, occurs when go test is invoked
108 with explicit package arguments (for example 'go test math', 'go
109 test ./...', and even 'go test .'). In this mode, go test compiles
110 and tests each of the packages listed on the command line. If a
111 package test passes, go test prints only the final 'ok' summary
112 line. If a package test fails, go test prints the full test output.
113 If invoked with the -bench or -v flag, go test prints the full
114 output even for passing package tests, in order to display the
115 requested benchmark results or verbose logging. After the package
116 tests for all of the listed packages finish, and their output is
117 printed, go test prints a final 'FAIL' status if any package test
118 has failed.
119
120 In package list mode only, go test caches successful package test
121 results to avoid unnecessary repeated running of tests. When the
122 result of a test can be recovered from the cache, go test will
123 redisplay the previous output instead of running the test binary
124 again. When this happens, go test prints '(cached)' in place of the
125 elapsed time in the summary line.
126
127 The rule for a match in the cache is that the run involves the same
128 test binary and the flags on the command line come entirely from a
129 restricted set of 'cacheable' test flags, defined as -benchtime,
130 -coverprofile, -cpu, -failfast, -fullpath, -list, -outputdir, -parallel,
131 -run, -short, -skip, -timeout and -v.
132 If a run of go test has any test or non-test flags outside this set,
133 the result is not cached. To disable test caching, use any test flag
134 or argument other than the cacheable flags. The idiomatic way to disable
135 test caching explicitly is to use -count=1. Tests that open files within
136 the package's module or that consult environment variables only
137 match future runs in which the files and environment variables are
138 unchanged. A cached test result is treated as executing in no time
139 at all, so a successful package test result will be cached and
140 reused regardless of -timeout setting.
141
142 In addition to the build flags, the flags handled by 'go test' itself are:
143
144 -args
145 Pass the remainder of the command line (everything after -args)
146 to the test binary, uninterpreted and unchanged.
147 Because this flag consumes the remainder of the command line,
148 the package list (if present) must appear before this flag.
149
150 -c
151 Compile the test binary to pkg.test in the current directory but do not run it
152 (where pkg is the last element of the package's import path).
153 The file name or target directory can be changed with the -o flag.
154
155 -exec xprog
156 Run the test binary using xprog. The behavior is the same as
157 in 'go run'. See 'go help run' for details.
158
159 -json
160 Convert test output to JSON suitable for automated processing.
161 See 'go doc test2json' for the encoding details.
162 Also emits build output in JSON. See 'go help buildjson'.
163
164 -o file
165 Compile the test binary to the named file.
166 The test still runs (unless -c or -i is specified).
167 If file ends in a slash or names an existing directory,
168 the test is written to pkg.test in that directory.
169
170 The test binary also accepts flags that control execution of the test; these
171 flags are also accessible by 'go test'. See 'go help testflag' for details.
172
173 For more about build flags, see 'go help build'.
174 For more about specifying packages, see 'go help packages'.
175
176 See also: go build, go vet.
177 `,
178 }
179
180 var HelpTestflag = &base.Command{
181 UsageLine: "testflag",
182 Short: "testing flags",
183 Long: `
184 The 'go test' command takes both flags that apply to 'go test' itself
185 and flags that apply to the resulting test binary.
186
187 Several of the flags control profiling and write an execution profile
188 suitable for "go tool pprof"; run "go tool pprof -h" for more
189 information. The -sample_index=alloc_space, -sample_index=alloc_objects,
190 and -show_bytes options of pprof control how the information is presented.
191
192 The following flags are recognized by the 'go test' command and
193 control the execution of any test:
194
195 -artifacts
196 Save test artifacts in the directory specified by -outputdir.
197 See 'go doc testing.T.ArtifactDir'.
198
199 -bench regexp
200 Run only those benchmarks matching a regular expression.
201 By default, no benchmarks are run.
202 To run all benchmarks, use '-bench .' or '-bench=.'.
203 The regular expression is split by unbracketed slash (/)
204 characters into a sequence of regular expressions, and each
205 part of a benchmark's identifier must match the corresponding
206 element in the sequence, if any. Possible parents of matches
207 are run with b.N=1 to identify sub-benchmarks. For example,
208 given -bench=X/Y, top-level benchmarks matching X are run
209 with b.N=1 to find any sub-benchmarks matching Y, which are
210 then run in full.
211
212 -benchtime t
213 Run enough iterations of each benchmark to take t, specified
214 as a time.Duration (for example, -benchtime 1h30s).
215 The default is 1 second (1s).
216 The special syntax Nx means to run the benchmark N times
217 (for example, -benchtime 100x).
218
219 -count n
220 Run each test, benchmark, and fuzz seed n times (default 1).
221 If -cpu is set, run n times for each GOMAXPROCS value.
222 Examples are always run once. -count does not apply to
223 fuzz tests matched by -fuzz.
224
225 -cover
226 Enable coverage analysis.
227 Note that because coverage works by annotating the source
228 code before compilation, compilation and test failures with
229 coverage enabled may report line numbers that don't correspond
230 to the original sources.
231
232 -covermode set,count,atomic
233 Set the mode for coverage analysis for the package[s]
234 being tested. The default is "set" unless -race is enabled,
235 in which case it is "atomic".
236 The values:
237 set: bool: does this statement run?
238 count: int: how many times does this statement run?
239 atomic: int: count, but correct in multithreaded tests;
240 significantly more expensive.
241 Sets -cover.
242
243 -coverpkg pattern1,pattern2,pattern3
244 Apply coverage analysis in each test to packages whose import paths
245 match the patterns. The default is for each test to analyze only
246 the package being tested. See 'go help packages' for a description
247 of package patterns. Sets -cover.
248
249 -cpu 1,2,4
250 Specify a list of GOMAXPROCS values for which the tests, benchmarks or
251 fuzz tests should be executed. The default is the current value
252 of GOMAXPROCS. -cpu does not apply to fuzz tests matched by -fuzz.
253
254 -failfast
255 Do not start new tests after the first test failure.
256
257 -fullpath
258 Show full file names in the error messages.
259
260 -fuzz regexp
261 Run the fuzz test matching the regular expression. When specified,
262 the command line argument must match exactly one package within the
263 main module, and regexp must match exactly one fuzz test within
264 that package. Fuzzing will occur after tests, benchmarks, seed corpora
265 of other fuzz tests, and examples have completed. See the Fuzzing
266 section of the testing package documentation for details.
267
268 -fuzztime t
269 Run enough iterations of the fuzz target during fuzzing to take t,
270 specified as a time.Duration (for example, -fuzztime 1h30s).
271 The default is to run forever.
272 The special syntax Nx means to run the fuzz target N times
273 (for example, -fuzztime 1000x).
274
275 -fuzzminimizetime t
276 Run enough iterations of the fuzz target during each minimization
277 attempt to take t, as specified as a time.Duration (for example,
278 -fuzzminimizetime 30s).
279 The default is 60s.
280 The special syntax Nx means to run the fuzz target N times
281 (for example, -fuzzminimizetime 100x).
282
283 -json
284 Log verbose output and test results in JSON. This presents the
285 same information as the -v flag in a machine-readable format.
286
287 -list regexp
288 List tests, benchmarks, fuzz tests, or examples matching the regular
289 expression. No tests, benchmarks, fuzz tests, or examples will be run.
290 This will only list top-level tests. No subtest or subbenchmarks will be
291 shown.
292
293 -outputdir directory
294 Place output files from profiling and test artifacts in the
295 specified directory, by default the directory in which "go test" is running.
296
297 -parallel n
298 Allow parallel execution of test functions that call t.Parallel, and
299 fuzz targets that call t.Parallel when running the seed corpus.
300 The value of this flag is the maximum number of tests to run
301 simultaneously.
302 While fuzzing, the value of this flag is the maximum number of
303 subprocesses that may call the fuzz function simultaneously, regardless of
304 whether T.Parallel is called.
305 By default, -parallel is set to the value of GOMAXPROCS.
306 Setting -parallel to values higher than GOMAXPROCS may cause degraded
307 performance due to CPU contention, especially when fuzzing.
308 Note that -parallel only applies within a single test binary.
309 The 'go test' command may run tests for different packages
310 in parallel as well, according to the setting of the -p flag
311 (see 'go help build').
312
313 -run regexp
314 Run only those tests, examples, and fuzz tests matching the regular
315 expression. For tests, the regular expression is split by unbracketed
316 slash (/) characters into a sequence of regular expressions, and each
317 part of a test's identifier must match the corresponding element in
318 the sequence, if any. Note that possible parents of matches are
319 run too, so that -run=X/Y matches and runs and reports the result
320 of all tests matching X, even those without sub-tests matching Y,
321 because it must run them to look for those sub-tests.
322 See also -skip.
323
324 -short
325 Tell long-running tests to shorten their run time.
326 It is off by default but set during all.bash so that installing
327 the Go tree can run a sanity check but not spend time running
328 exhaustive tests.
329
330 -shuffle off,on,N
331 Randomize the execution order of tests and benchmarks.
332 It is off by default. If -shuffle is set to on, then it will seed
333 the randomizer using the system clock. If -shuffle is set to an
334 integer N, then N will be used as the seed value. In both cases,
335 the seed will be reported for reproducibility.
336
337 -skip regexp
338 Run only those tests, examples, fuzz tests, and benchmarks that
339 do not match the regular expression. Like for -run and -bench,
340 for tests and benchmarks, the regular expression is split by unbracketed
341 slash (/) characters into a sequence of regular expressions, and each
342 part of a test's identifier must match the corresponding element in
343 the sequence, if any.
344
345 -timeout d
346 If a test binary runs longer than duration d, panic.
347 If d is 0, the timeout is disabled.
348 The default is 10 minutes (10m).
349
350 -v
351 Verbose output: log all tests as they are run. Also print all
352 text from Log and Logf calls even if the test succeeds.
353
354 -vet list
355 Configure the invocation of "go vet" during "go test"
356 to use the comma-separated list of vet checks.
357 If list is empty, "go test" runs "go vet" with a curated list of
358 checks believed to be always worth addressing.
359 If list is "off", "go test" does not run "go vet" at all.
360
361 The following flags are also recognized by 'go test' and can be used to
362 profile the tests during execution:
363
364 -benchmem
365 Print memory allocation statistics for benchmarks.
366 Allocations made in C or using C.malloc are not counted.
367
368 -blockprofile block.out
369 Write a goroutine blocking profile to the specified file
370 when all tests are complete.
371 Writes test binary as -c would.
372
373 -blockprofilerate n
374 Control the detail provided in goroutine blocking profiles by
375 calling runtime.SetBlockProfileRate with n.
376 See 'go doc runtime.SetBlockProfileRate'.
377 The profiler aims to sample, on average, one blocking event every
378 n nanoseconds the program spends blocked. By default,
379 if -test.blockprofile is set without this flag, all blocking events
380 are recorded, equivalent to -test.blockprofilerate=1.
381
382 -coverprofile cover.out
383 Write a coverage profile to the file after all tests have passed.
384 Sets -cover.
385
386 -cpuprofile cpu.out
387 Write a CPU profile to the specified file before exiting.
388 Writes test binary as -c would.
389
390 -memprofile mem.out
391 Write an allocation profile to the file after all tests have passed.
392 Writes test binary as -c would.
393
394 -memprofilerate n
395 Enable more precise (and expensive) memory allocation profiles by
396 setting runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
397 To profile all memory allocations, use -test.memprofilerate=1.
398
399 -mutexprofile mutex.out
400 Write a mutex contention profile to the specified file
401 when all tests are complete.
402 Writes test binary as -c would.
403
404 -mutexprofilefraction n
405 Sample 1 in n stack traces of goroutines holding a
406 contended mutex.
407
408 -trace trace.out
409 Write an execution trace to the specified file before exiting.
410
411 Each of these flags is also recognized with an optional 'test.' prefix,
412 as in -test.v. When invoking the generated test binary (the result of
413 'go test -c') directly, however, the prefix is mandatory.
414
415 The 'go test' command rewrites or removes recognized flags,
416 as appropriate, both before and after the optional package list,
417 before invoking the test binary.
418
419 For instance, the command
420
421 go test -v -myflag testdata -cpuprofile=prof.out -x
422
423 will compile the test binary and then run it as
424
425 pkg.test -test.v -myflag testdata -test.cpuprofile=prof.out
426
427 (The -x flag is removed because it applies only to the go command's
428 execution, not to the test itself.)
429
430 The test flags that generate profiles (other than for coverage) also
431 leave the test binary in pkg.test for use when analyzing the profiles.
432
433 When 'go test' runs a test binary, it does so from within the
434 corresponding package's source code directory. Depending on the test,
435 it may be necessary to do the same when invoking a generated test
436 binary directly. Because that directory may be located within the
437 module cache, which may be read-only and is verified by checksums, the
438 test must not write to it or any other directory within the module
439 unless explicitly requested by the user (such as with the -fuzz flag,
440 which writes failures to testdata/fuzz).
441
442 The command-line package list, if present, must appear before any
443 flag not known to the go test command. Continuing the example above,
444 the package list would have to appear before -myflag, but could appear
445 on either side of -v.
446
447 When 'go test' runs in package list mode, 'go test' caches successful
448 package test results to avoid unnecessary repeated running of tests. To
449 disable test caching, use any test flag or argument other than the
450 cacheable flags. The idiomatic way to disable test caching explicitly
451 is to use -count=1.
452
453 To keep an argument for a test binary from being interpreted as a
454 known flag or a package name, use -args (see 'go help test') which
455 passes the remainder of the command line through to the test binary
456 uninterpreted and unaltered.
457
458 For instance, the command
459
460 go test -v -args -x -v
461
462 will compile the test binary and then run it as
463
464 pkg.test -test.v -x -v
465
466 Similarly,
467
468 go test -args math
469
470 will compile the test binary and then run it as
471
472 pkg.test math
473
474 In the first example, the -x and the second -v are passed through to the
475 test binary unchanged and with no effect on the go command itself.
476 In the second example, the argument math is passed through to the test
477 binary, instead of being interpreted as the package list.
478 `,
479 }
480
481 var HelpTestfunc = &base.Command{
482 UsageLine: "testfunc",
483 Short: "testing functions",
484 Long: `
485 The 'go test' command expects to find test, benchmark, and example functions
486 in the "*_test.go" files corresponding to the package under test.
487
488 A test function is one named TestXxx (where Xxx does not start with a
489 lower case letter) and should have the signature,
490
491 func TestXxx(t *testing.T) { ... }
492
493 A benchmark function is one named BenchmarkXxx and should have the signature,
494
495 func BenchmarkXxx(b *testing.B) { ... }
496
497 A fuzz test is one named FuzzXxx and should have the signature,
498
499 func FuzzXxx(f *testing.F) { ... }
500
501 An example function is similar to a test function but, instead of using
502 *testing.T to report success or failure, prints output to os.Stdout.
503 If the last comment in the function starts with "Output:" then the output
504 is compared exactly against the comment (see examples below). If the last
505 comment begins with "Unordered output:" then the output is compared to the
506 comment, however the order of the lines is ignored. An example with no such
507 comment is compiled but not executed. An example with no text after
508 "Output:" is compiled, executed, and expected to produce no output.
509
510 Godoc displays the body of ExampleXxx to demonstrate the use
511 of the function, constant, or variable Xxx. An example of a method M with
512 receiver type T or *T is named ExampleT_M. There may be multiple examples
513 for a given function, constant, or variable, distinguished by a trailing _xxx,
514 where xxx is a suffix not beginning with an upper case letter.
515
516 Here is an example of an example:
517
518 func ExamplePrintln() {
519 Println("The output of\nthis example.")
520 // Output: The output of
521 // this example.
522 }
523
524 Here is another example where the ordering of the output is ignored:
525
526 func ExamplePerm() {
527 for _, value := range Perm(4) {
528 fmt.Println(value)
529 }
530
531 // Unordered output: 4
532 // 2
533 // 1
534 // 3
535 // 0
536 }
537
538 The entire test file is presented as the example when it contains a single
539 example function, at least one other function, type, variable, or constant
540 declaration, and no tests, benchmarks, or fuzz tests.
541
542 See the documentation of the testing package for more information.
543 `,
544 }
545
546 var (
547 testArtifacts bool
548 testBench string
549 testC bool
550 testCoverPkgs []*load.Package
551 testCoverProfile string
552 testFailFast bool
553 testFuzz string
554 testJSON bool
555 testList string
556 testO string
557 testOutputDir outputdirFlag
558 testShuffle shuffleFlag
559 testTimeout time.Duration
560 testV testVFlag
561 testVet = vetFlag{flags: defaultVetFlags}
562 )
563
564 type testVFlag struct {
565 on bool
566 json bool
567 }
568
569 func (*testVFlag) IsBoolFlag() bool { return true }
570
571 func (f *testVFlag) Set(arg string) error {
572 if v, err := strconv.ParseBool(arg); err == nil {
573 f.on = v
574 f.json = false
575 return nil
576 }
577 if arg == "test2json" {
578 f.on = true
579 f.json = true
580 return nil
581 }
582 return fmt.Errorf("invalid flag -test.v=%s", arg)
583 }
584
585 func (f *testVFlag) String() string {
586 if f.json {
587 return "test2json"
588 }
589 if f.on {
590 return "true"
591 }
592 return "false"
593 }
594
595 var (
596 testArgs []string
597 pkgArgs []string
598 pkgs []*load.Package
599
600 testHelp bool
601
602 testKillTimeout = 100 * 365 * 24 * time.Hour
603 testWaitDelay time.Duration
604 testCacheExpire time.Time
605 testShouldFailFast atomic.Bool
606
607 testBlockProfile, testCPUProfile, testMemProfile, testMutexProfile, testTrace string
608
609 testODir = false
610 )
611
612
613
614 func testProfile() string {
615 switch {
616 case testBlockProfile != "":
617 return "-blockprofile"
618 case testCPUProfile != "":
619 return "-cpuprofile"
620 case testMemProfile != "":
621 return "-memprofile"
622 case testMutexProfile != "":
623 return "-mutexprofile"
624 case testTrace != "":
625 return "-trace"
626 default:
627 return ""
628 }
629 }
630
631
632 func testNeedBinary() bool {
633 switch {
634 case testBlockProfile != "":
635 return true
636 case testCPUProfile != "":
637 return true
638 case testMemProfile != "":
639 return true
640 case testMutexProfile != "":
641 return true
642 case testO != "":
643 return true
644 default:
645 return false
646 }
647 }
648
649
650 func testShowPass() bool {
651 return testV.on || testList != "" || testHelp
652 }
653
654 var defaultVetFlags = []string{
655
656
657
658
659 "-atomic",
660 "-bool",
661 "-buildtags",
662
663
664
665 "-directive",
666 "-errorsas",
667
668 "-ifaceassert",
669
670
671 "-nilfunc",
672 "-printf",
673
674
675 "-slog",
676 "-stringintconv",
677
678 "-tests",
679
680
681
682 }
683
684 func runTest(ctx context.Context, cmd *base.Command, args []string) {
685 pkgArgs, testArgs = testFlags(args)
686 modload.InitWorkfile(modload.LoaderState)
687
688 if cfg.DebugTrace != "" {
689 var close func() error
690 var err error
691 ctx, close, err = trace.Start(ctx, cfg.DebugTrace)
692 if err != nil {
693 base.Fatalf("failed to start trace: %v", err)
694 }
695 defer func() {
696 if err := close(); err != nil {
697 base.Fatalf("failed to stop trace: %v", err)
698 }
699 }()
700 }
701
702 ctx, span := trace.StartSpan(ctx, fmt.Sprint("Running ", cmd.Name(), " command"))
703 defer span.Done()
704
705 work.FindExecCmd()
706
707 work.BuildInit(modload.LoaderState)
708 work.VetFlags = testVet.flags
709 work.VetExplicit = testVet.explicit
710 work.VetTool = base.Tool("vet")
711
712 pkgOpts := load.PackageOpts{ModResolveTests: true}
713 pkgs = load.PackagesAndErrors(modload.LoaderState, ctx, pkgOpts, pkgArgs)
714
715
716 if len(pkgs) == 0 {
717 base.Fatalf("no packages to test")
718 }
719
720 if testFuzz != "" {
721 if !platform.FuzzSupported(cfg.Goos, cfg.Goarch) {
722 base.Fatalf("-fuzz flag is not supported on %s/%s", cfg.Goos, cfg.Goarch)
723 }
724 if len(pkgs) != 1 {
725 base.Fatalf("cannot use -fuzz flag with multiple packages")
726 }
727 if testCoverProfile != "" {
728 base.Fatalf("cannot use -coverprofile flag with -fuzz flag")
729 }
730 if profileFlag := testProfile(); profileFlag != "" {
731 base.Fatalf("cannot use %s flag with -fuzz flag", profileFlag)
732 }
733
734
735
736
737
738
739 mainMods := modload.LoaderState.MainModules
740 if m := pkgs[0].Module; m != nil && m.Path != "" {
741 if !mainMods.Contains(m.Path) {
742 base.Fatalf("cannot use -fuzz flag on package outside the main module")
743 }
744 } else if pkgs[0].Standard && modload.Enabled(modload.LoaderState) {
745
746
747
748
749
750
751
752
753
754
755 if strings.HasPrefix(pkgs[0].ImportPath, "cmd/") {
756 if !mainMods.Contains("cmd") || !mainMods.InGorootSrc(module.Version{Path: "cmd"}) {
757 base.Fatalf("cannot use -fuzz flag on package outside the main module")
758 }
759 } else {
760 if !mainMods.Contains("std") || !mainMods.InGorootSrc(module.Version{Path: "std"}) {
761 base.Fatalf("cannot use -fuzz flag on package outside the main module")
762 }
763 }
764 }
765 }
766 if testProfile() != "" && len(pkgs) != 1 {
767 base.Fatalf("cannot use %s flag with multiple packages", testProfile())
768 }
769
770 if testO != "" {
771 if strings.HasSuffix(testO, "/") || strings.HasSuffix(testO, string(os.PathSeparator)) {
772 testODir = true
773 } else if fi, err := os.Stat(testO); err == nil && fi.IsDir() {
774 testODir = true
775 }
776 }
777
778 if len(pkgs) > 1 && (testC || testO != "") && !base.IsNull(testO) {
779 if testO != "" && !testODir {
780 base.Fatalf("with multiple packages, -o must refer to a directory or %s", os.DevNull)
781 }
782
783 pkgsForBinary := map[string][]*load.Package{}
784
785 for _, p := range pkgs {
786 testBinary := testBinaryName(p)
787 pkgsForBinary[testBinary] = append(pkgsForBinary[testBinary], p)
788 }
789
790 for testBinary, pkgs := range pkgsForBinary {
791 if len(pkgs) > 1 {
792 var buf strings.Builder
793 for _, pkg := range pkgs {
794 buf.WriteString(pkg.ImportPath)
795 buf.WriteString("\n")
796 }
797
798 base.Errorf("cannot write test binary %s for multiple packages:\n%s", testBinary, buf.String())
799 }
800 }
801
802 base.ExitIfErrors()
803 }
804
805 initCoverProfile()
806 defer closeCoverProfile()
807
808
809
810
811
812
813
814 if testTimeout > 0 && testFuzz == "" && testBench == "" {
815
816
817
818
819
820
821
822
823
824
825 if wd := testTimeout / 10; wd < 5*time.Second {
826 testWaitDelay = 5 * time.Second
827 } else {
828 testWaitDelay = wd
829 }
830
831
832
833
834
835
836
837
838
839 if testWaitDelay < 1*time.Minute {
840 testKillTimeout = testTimeout + 1*time.Minute
841 } else {
842 testKillTimeout = testTimeout + testWaitDelay
843 }
844 }
845
846
847
848
849 if dir, _, _ := cache.DefaultDir(); dir != "off" {
850 if data, _ := lockedfile.Read(filepath.Join(dir, "testexpire.txt")); len(data) > 0 && data[len(data)-1] == '\n' {
851 if t, err := strconv.ParseInt(string(data[:len(data)-1]), 10, 64); err == nil {
852 testCacheExpire = time.Unix(0, t)
853 }
854 }
855 }
856
857 b := work.NewBuilder("")
858 defer func() {
859 if err := b.Close(); err != nil {
860 base.Fatal(err)
861 }
862 }()
863
864 var builds, runs, prints []*work.Action
865 var writeCoverMetaAct *work.Action
866
867 if cfg.BuildCoverPkg != nil {
868 match := make([]func(*load.Package) bool, len(cfg.BuildCoverPkg))
869 for i := range cfg.BuildCoverPkg {
870 match[i] = load.MatchPackage(modload.LoaderState, cfg.BuildCoverPkg[i], base.Cwd())
871 }
872
873
874
875 plist := load.TestPackageList(modload.LoaderState, ctx, pkgOpts, pkgs)
876 testCoverPkgs = load.SelectCoverPackages(modload.LoaderState, plist, match, "test")
877 if len(testCoverPkgs) > 0 {
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923 writeCoverMetaAct = &work.Action{
924 Mode: "write coverage meta-data file",
925 Actor: work.ActorFunc(work.WriteCoverMetaFilesFile),
926 Objdir: b.NewObjdir(),
927 }
928 for _, p := range testCoverPkgs {
929 p.Internal.Cover.GenMeta = true
930 }
931 }
932 }
933
934
935
936 if testFuzz != "" {
937
938
939
940 var skipInstrumentation = map[string]bool{
941 "context": true,
942 "internal/fuzz": true,
943 "internal/godebug": true,
944 "internal/runtime/maps": true,
945 "internal/sync": true,
946 "reflect": true,
947 "runtime": true,
948 "sync": true,
949 "sync/atomic": true,
950 "syscall": true,
951 "testing": true,
952 "time": true,
953 }
954 for _, p := range load.TestPackageList(modload.LoaderState, ctx, pkgOpts, pkgs) {
955 if !skipInstrumentation[p.ImportPath] {
956 p.Internal.FuzzInstrument = true
957 }
958 }
959 }
960
961
962 allImports := make(map[*load.Package]bool)
963 for _, p := range pkgs {
964 if p.Error != nil && p.Error.IsImportCycle {
965 continue
966 }
967 for _, p1 := range p.Internal.Imports {
968 allImports[p1] = true
969 }
970 }
971
972 if cfg.BuildCover {
973 for _, p := range pkgs {
974
975
976
977
978
979
980
981
982
983 if cfg.BuildCoverMode == "atomic" && p.ImportPath != "sync/atomic" {
984 load.EnsureImport(modload.LoaderState, p, "sync/atomic")
985 }
986
987
988
989
990
991
992
993
994 if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 && cfg.BuildCoverPkg == nil {
995 p.Internal.Cover.GenMeta = true
996 }
997
998
999
1000
1001 if cfg.BuildCover {
1002 if p.Internal.Cover.GenMeta {
1003 p.Internal.Cover.Mode = cfg.BuildCoverMode
1004 }
1005 }
1006 }
1007 }
1008
1009
1010 for _, p := range pkgs {
1011 reportErr := func(perr *load.Package, err error) {
1012 str := err.Error()
1013 if p.ImportPath != "" {
1014 load.DefaultPrinter().Errorf(perr, "# %s\n%s", p.ImportPath, str)
1015 } else {
1016 load.DefaultPrinter().Errorf(perr, "%s", str)
1017 }
1018 }
1019 reportSetupFailed := func(perr *load.Package, err error) {
1020 var stdout io.Writer = os.Stdout
1021 if testJSON {
1022 json := test2json.NewConverter(stdout, p.ImportPath, test2json.Timestamp)
1023 defer func() {
1024 json.Exited(err)
1025 json.Close()
1026 }()
1027 if gotestjsonbuildtext.Value() == "1" {
1028
1029
1030 gotestjsonbuildtext.IncNonDefault()
1031 } else {
1032 json.SetFailedBuild(perr.Desc())
1033 }
1034 stdout = json
1035 }
1036 fmt.Fprintf(stdout, "FAIL\t%s [setup failed]\n", p.ImportPath)
1037 base.SetExitStatus(1)
1038 }
1039
1040 var firstErrPkg *load.Package
1041 load.PackageErrors([]*load.Package{p}, func(p *load.Package) {
1042 reportErr(p, p.Error)
1043 if firstErrPkg == nil {
1044 firstErrPkg = p
1045 }
1046 })
1047 if firstErrPkg != nil {
1048 reportSetupFailed(firstErrPkg, firstErrPkg.Error)
1049 continue
1050 }
1051 buildTest, runTest, printTest, perr, err := builderTest(modload.LoaderState, b, ctx, pkgOpts, p, allImports[p], writeCoverMetaAct)
1052 if err != nil {
1053 reportErr(perr, err)
1054 reportSetupFailed(perr, err)
1055 continue
1056 }
1057 builds = append(builds, buildTest)
1058 runs = append(runs, runTest)
1059 prints = append(prints, printTest)
1060 }
1061
1062
1063
1064
1065
1066
1067 var prevBarrier *work.Action
1068 ch := make(chan struct{})
1069 close(ch)
1070 for _, a := range runs {
1071 if r, ok := a.Actor.(*runTestActor); ok {
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082 barrier := &work.Action{
1083 Mode: "test barrier",
1084 Deps: slices.Clip(a.Deps),
1085 }
1086 if prevBarrier != nil {
1087 barrier.Deps = append(barrier.Deps, prevBarrier)
1088 }
1089 a.Deps = []*work.Action{barrier}
1090 prevBarrier = barrier
1091
1092 r.prev = ch
1093 ch = make(chan struct{})
1094 r.next = ch
1095 }
1096 }
1097
1098
1099 root := &work.Action{Mode: "go test", Actor: work.ActorFunc(printExitStatus), Deps: prints}
1100
1101
1102
1103 for i, a := range prints {
1104 if i > 0 {
1105 a.Deps = append(a.Deps, prints[i-1])
1106 }
1107 }
1108
1109
1110 if !testC && (testBench != "") {
1111
1112
1113 for i, run := range runs {
1114 if i == 0 {
1115 run.Deps = append(run.Deps, builds...)
1116 } else {
1117 run.Deps = append(run.Deps, prints[i-1])
1118 }
1119 }
1120 }
1121
1122 b.Do(ctx, root)
1123 }
1124
1125 var windowsBadWords = []string{
1126 "install",
1127 "patch",
1128 "setup",
1129 "update",
1130 }
1131
1132 func builderTest(loaderstate *modload.State, b *work.Builder, ctx context.Context, pkgOpts load.PackageOpts, p *load.Package, imported bool, writeCoverMetaAct *work.Action) (buildAction, runAction, printAction *work.Action, perr *load.Package, err error) {
1133 if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
1134 build := b.CompileAction(work.ModeBuild, work.ModeBuild, p)
1135 run := &work.Action{
1136 Mode: "test run",
1137 Actor: new(runTestActor),
1138 Deps: []*work.Action{build},
1139 Objdir: b.NewObjdir(),
1140 Package: p,
1141 IgnoreFail: true,
1142 }
1143 if writeCoverMetaAct != nil && build.Actor != nil {
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157 run.Deps = append(run.Deps, writeCoverMetaAct)
1158 writeCoverMetaAct.Deps = append(writeCoverMetaAct.Deps, build)
1159 }
1160 addTestVet(loaderstate, b, p, run, nil)
1161 print := &work.Action{
1162 Mode: "test print",
1163 Actor: work.ActorFunc(builderPrintTest),
1164 Deps: []*work.Action{run},
1165 Package: p,
1166 IgnoreFail: true,
1167 }
1168 return build, run, print, nil, nil
1169 }
1170
1171
1172
1173
1174
1175 var cover *load.TestCover
1176 if cfg.BuildCover {
1177 cover = &load.TestCover{
1178 Mode: cfg.BuildCoverMode,
1179 Local: cfg.BuildCoverPkg == nil,
1180 Pkgs: testCoverPkgs,
1181 Paths: cfg.BuildCoverPkg,
1182 }
1183 }
1184 pmain, ptest, pxtest, perr := load.TestPackagesFor(loaderstate, ctx, pkgOpts, p, cover)
1185 if perr != nil {
1186 return nil, nil, nil, perr, perr.Error
1187 }
1188
1189
1190
1191
1192
1193 if imported && ptest != p {
1194 buildTest := b.CompileAction(work.ModeBuild, work.ModeBuild, ptest)
1195 buildP := b.CompileAction(work.ModeBuild, work.ModeBuild, p)
1196 buildTest.Deps = append(buildTest.Deps, buildP)
1197 }
1198
1199 testBinary := testBinaryName(p)
1200
1201
1202
1203 testDir := b.CompileAction(work.ModeBuild, work.ModeBuild, pmain).Objdir
1204 if err := b.BackgroundShell().Mkdir(testDir); err != nil {
1205 return nil, nil, nil, nil, err
1206 }
1207
1208 pmain.Dir = testDir
1209 pmain.Internal.OmitDebug = !testC && !testNeedBinary()
1210 if pmain.ImportPath == "runtime.test" {
1211
1212
1213 pmain.Internal.OmitDebug = false
1214 }
1215
1216 if !cfg.BuildN {
1217
1218
1219 if err := os.WriteFile(testDir+"_testmain.go", *pmain.Internal.TestmainGo, 0666); err != nil {
1220 return nil, nil, nil, nil, err
1221 }
1222 }
1223
1224 a := b.LinkAction(loaderstate, work.ModeBuild, work.ModeBuild, pmain)
1225 a.Target = testDir + testBinary + cfg.ExeSuffix
1226 if cfg.Goos == "windows" {
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249 for _, bad := range windowsBadWords {
1250 if strings.Contains(testBinary, bad) {
1251 a.Target = testDir + "test.test" + cfg.ExeSuffix
1252 break
1253 }
1254 }
1255 }
1256 buildAction = a
1257 var installAction, cleanAction *work.Action
1258 if testC || testNeedBinary() {
1259
1260 target := filepath.Join(base.Cwd(), testBinary+cfg.ExeSuffix)
1261 isNull := false
1262
1263 if testO != "" {
1264 target = testO
1265
1266 if testODir {
1267 if filepath.IsAbs(target) {
1268 target = filepath.Join(target, testBinary+cfg.ExeSuffix)
1269 } else {
1270 target = filepath.Join(base.Cwd(), target, testBinary+cfg.ExeSuffix)
1271 }
1272 } else {
1273 if base.IsNull(target) {
1274 isNull = true
1275 } else if !filepath.IsAbs(target) {
1276 target = filepath.Join(base.Cwd(), target)
1277 }
1278 }
1279 }
1280
1281 if isNull {
1282 runAction = buildAction
1283 } else {
1284 pmain.Target = target
1285 installAction = &work.Action{
1286 Mode: "test build",
1287 Actor: work.ActorFunc(work.BuildInstallFunc),
1288 Deps: []*work.Action{buildAction},
1289 Package: pmain,
1290 Target: target,
1291 }
1292 runAction = installAction
1293 }
1294 }
1295
1296 var vetRunAction *work.Action
1297 if testC {
1298 printAction = &work.Action{Mode: "test print (nop)", Package: p, Deps: []*work.Action{runAction}}
1299 vetRunAction = printAction
1300 } else {
1301
1302 rta := &runTestActor{
1303 writeCoverMetaAct: writeCoverMetaAct,
1304 }
1305 runAction = &work.Action{
1306 Mode: "test run",
1307 Actor: rta,
1308 Deps: []*work.Action{buildAction},
1309 Package: p,
1310 IgnoreFail: true,
1311 TryCache: rta.c.tryCache,
1312 }
1313 if writeCoverMetaAct != nil {
1314
1315
1316
1317
1318
1319 runAction.Deps = append(runAction.Deps, writeCoverMetaAct)
1320 if !p.IsTestOnly() {
1321
1322
1323
1324
1325
1326 compileAction := b.CompileAction(work.ModeBuild, work.ModeBuild, p)
1327 writeCoverMetaAct.Deps = append(writeCoverMetaAct.Deps, compileAction)
1328 }
1329 }
1330 runAction.Objdir = testDir
1331 vetRunAction = runAction
1332 cleanAction = &work.Action{
1333 Mode: "test clean",
1334 Actor: work.ActorFunc(builderCleanTest),
1335 Deps: []*work.Action{runAction},
1336 Package: p,
1337 IgnoreFail: true,
1338 Objdir: testDir,
1339 }
1340 printAction = &work.Action{
1341 Mode: "test print",
1342 Actor: work.ActorFunc(builderPrintTest),
1343 Deps: []*work.Action{cleanAction},
1344 Package: p,
1345 IgnoreFail: true,
1346 }
1347 }
1348
1349 if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
1350 addTestVet(loaderstate, b, ptest, vetRunAction, installAction)
1351 }
1352 if pxtest != nil {
1353 addTestVet(loaderstate, b, pxtest, vetRunAction, installAction)
1354 }
1355
1356 if installAction != nil {
1357 if runAction != installAction {
1358 installAction.Deps = append(installAction.Deps, runAction)
1359 }
1360 if cleanAction != nil {
1361 cleanAction.Deps = append(cleanAction.Deps, installAction)
1362 }
1363 }
1364
1365 return buildAction, runAction, printAction, nil, nil
1366 }
1367
1368 func addTestVet(loaderstate *modload.State, b *work.Builder, p *load.Package, runAction, installAction *work.Action) {
1369 if testVet.off {
1370 return
1371 }
1372
1373 vet := b.VetAction(loaderstate, work.ModeBuild, work.ModeBuild, p)
1374 runAction.Deps = append(runAction.Deps, vet)
1375
1376
1377
1378
1379 if installAction != nil {
1380 installAction.Deps = append(installAction.Deps, vet)
1381 }
1382 }
1383
1384 var noTestsToRun = []byte("\ntesting: warning: no tests to run\n")
1385 var noFuzzTestsToFuzz = []byte("\ntesting: warning: no fuzz tests to fuzz\n")
1386 var tooManyFuzzTestsToFuzz = []byte("\ntesting: warning: -fuzz matches more than one fuzz test, won't fuzz\n")
1387
1388
1389 type runTestActor struct {
1390 c runCache
1391
1392
1393
1394
1395
1396 writeCoverMetaAct *work.Action
1397
1398
1399 prev <-chan struct{}
1400 next chan<- struct{}
1401 }
1402
1403
1404 type runCache struct {
1405 disableCache bool
1406
1407 buf *bytes.Buffer
1408 id1 cache.ActionID
1409 id2 cache.ActionID
1410 }
1411
1412 func coverProfTempFile(a *work.Action) string {
1413 if a.Objdir == "" {
1414 panic("internal error: objdir not set in coverProfTempFile")
1415 }
1416 return a.Objdir + "_cover_.out"
1417 }
1418
1419
1420
1421
1422
1423
1424 var stdoutMu sync.Mutex
1425
1426 type lockedStdout struct{}
1427
1428 func (lockedStdout) Write(b []byte) (int, error) {
1429 stdoutMu.Lock()
1430 defer stdoutMu.Unlock()
1431 return os.Stdout.Write(b)
1432 }
1433
1434 func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action) error {
1435 sh := b.Shell(a)
1436 barrierAction := a.Deps[0]
1437 buildAction := barrierAction.Deps[0]
1438
1439
1440 select {
1441 case <-r.prev:
1442
1443 if testShouldFailFast.Load() {
1444 close(r.next)
1445 return nil
1446 }
1447 case <-base.Interrupted:
1448
1449
1450
1451 base.SetExitStatus(1)
1452 return nil
1453 }
1454
1455
1456
1457
1458 streamOutput := len(pkgArgs) == 0 || testBench != "" || testFuzz != ""
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474 streamAndCacheOutput := testShowPass() && (len(pkgs) == 1 || cfg.BuildP == 1) || testJSON
1475
1476 var stdout io.Writer = os.Stdout
1477 var err error
1478 var json *test2json.Converter
1479 if testJSON {
1480 json = test2json.NewConverter(lockedStdout{}, a.Package.ImportPath, test2json.Timestamp)
1481 defer func() {
1482 json.Exited(err)
1483 json.Close()
1484 }()
1485 stdout = json
1486 }
1487
1488 var buf bytes.Buffer
1489 if streamOutput {
1490
1491 } else if streamAndCacheOutput {
1492
1493
1494 stdout = io.MultiWriter(stdout, &buf)
1495 } else {
1496 stdout = &buf
1497 }
1498
1499
1500 close(r.next)
1501
1502 if a.Failed != nil {
1503
1504 if json != nil && a.Failed.Package != nil {
1505 if gotestjsonbuildtext.Value() == "1" {
1506 gotestjsonbuildtext.IncNonDefault()
1507 } else {
1508 json.SetFailedBuild(a.Failed.Package.Desc())
1509 }
1510 }
1511 a.Failed = nil
1512 fmt.Fprintf(stdout, "FAIL\t%s [build failed]\n", a.Package.ImportPath)
1513
1514 err = errors.New("build failed")
1515 base.SetExitStatus(1)
1516 if stdout == &buf {
1517 a.TestOutput = &buf
1518 }
1519 return nil
1520 }
1521
1522 if p := a.Package; len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
1523 reportNoTestFiles := true
1524 if cfg.BuildCover && p.Internal.Cover.GenMeta {
1525 if err := sh.Mkdir(a.Objdir); err != nil {
1526 return err
1527 }
1528 mf, err := work.BuildActionCoverMetaFile(a)
1529 if err != nil {
1530 return err
1531 } else if mf != "" {
1532 reportNoTestFiles = false
1533
1534 if err := work.WriteCoveragePercent(b, a, mf, stdout); err != nil {
1535 return err
1536 }
1537
1538
1539
1540 if coverMerge.f != nil {
1541 cp := coverProfTempFile(a)
1542 if err := work.WriteCoverageProfile(b, a, mf, cp, stdout); err != nil {
1543 return err
1544 }
1545 mergeCoverProfile(cp)
1546 }
1547 }
1548 }
1549 if reportNoTestFiles {
1550 fmt.Fprintf(stdout, "? \t%s\t[no test files]\n", p.ImportPath)
1551 }
1552 if stdout == &buf {
1553 a.TestOutput = &buf
1554 }
1555 return nil
1556 }
1557
1558 if r.c.buf == nil {
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568 r.c.tryCacheWithID(b, a, buildAction.BuildContentID())
1569 }
1570 if r.c.buf != nil {
1571 if stdout != &buf {
1572 stdout.Write(r.c.buf.Bytes())
1573 r.c.buf.Reset()
1574 }
1575 a.TestOutput = r.c.buf
1576 return nil
1577 }
1578
1579 execCmd := work.FindExecCmd()
1580 testlogArg := []string{}
1581 if !r.c.disableCache && len(execCmd) == 0 {
1582 testlogArg = []string{"-test.testlogfile=" + a.Objdir + "testlog.txt"}
1583 }
1584 panicArg := "-test.paniconexit0"
1585 fuzzArg := []string{}
1586 if testFuzz != "" {
1587 fuzzCacheDir := filepath.Join(cache.Default().FuzzDir(), a.Package.ImportPath)
1588 fuzzArg = []string{"-test.fuzzcachedir=" + fuzzCacheDir}
1589 }
1590 coverdirArg := []string{}
1591 addToEnv := ""
1592 if cfg.BuildCover {
1593 gcd := filepath.Join(a.Objdir, "gocoverdir")
1594 if err := sh.Mkdir(gcd); err != nil {
1595
1596
1597
1598
1599
1600 base.Fatalf("failed to create temporary dir: %v", err)
1601 }
1602 coverdirArg = append(coverdirArg, "-test.gocoverdir="+gcd)
1603 if r.writeCoverMetaAct != nil {
1604
1605
1606
1607 src := r.writeCoverMetaAct.Objdir + coverage.MetaFilesFileName
1608 dst := filepath.Join(gcd, coverage.MetaFilesFileName)
1609 if err := sh.CopyFile(dst, src, 0666, false); err != nil {
1610 return err
1611 }
1612 }
1613
1614
1615
1616
1617 addToEnv = "GOCOVERDIR=" + gcd
1618 }
1619 args := str.StringList(execCmd, buildAction.BuiltTarget(), testlogArg, panicArg, fuzzArg, coverdirArg, testArgs)
1620
1621 if testCoverProfile != "" {
1622
1623 for i, arg := range args {
1624 if strings.HasPrefix(arg, "-test.coverprofile=") {
1625 args[i] = "-test.coverprofile=" + coverProfTempFile(a)
1626 }
1627 }
1628 }
1629
1630 if cfg.BuildN || cfg.BuildX {
1631 sh.ShowCmd("", "%s", strings.Join(args, " "))
1632 if cfg.BuildN {
1633 return nil
1634 }
1635 }
1636
1637
1638
1639 ctx, cancel := context.WithTimeout(ctx, testKillTimeout)
1640 defer cancel()
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653 var (
1654 cmd *exec.Cmd
1655 t0 time.Time
1656 cancelKilled = false
1657 cancelSignaled = false
1658 )
1659 for {
1660 cmd = exec.CommandContext(ctx, args[0], args[1:]...)
1661 cmd.Dir = a.Package.Dir
1662
1663 env := slices.Clip(cfg.OrigEnv)
1664 env = base.AppendPATH(env)
1665 env = base.AppendPWD(env, cmd.Dir)
1666 cmd.Env = env
1667 if addToEnv != "" {
1668 cmd.Env = append(cmd.Env, addToEnv)
1669 }
1670
1671 cmd.Stdout = stdout
1672 cmd.Stderr = stdout
1673
1674 cmd.Cancel = func() error {
1675 if base.SignalTrace == nil {
1676 err := cmd.Process.Kill()
1677 if err == nil {
1678 cancelKilled = true
1679 }
1680 return err
1681 }
1682
1683
1684
1685 err := cmd.Process.Signal(base.SignalTrace)
1686 if err == nil {
1687 cancelSignaled = true
1688 }
1689 return err
1690 }
1691 cmd.WaitDelay = testWaitDelay
1692
1693 base.StartSigHandlers()
1694 t0 = time.Now()
1695 err = cmd.Run()
1696
1697 if !base.IsETXTBSY(err) {
1698
1699
1700 break
1701 }
1702 }
1703
1704 out := buf.Bytes()
1705 a.TestOutput = &buf
1706 t := fmt.Sprintf("%.3fs", time.Since(t0).Seconds())
1707
1708 mergeCoverProfile(coverProfTempFile(a))
1709
1710 if err == nil {
1711 norun := ""
1712 if !testShowPass() && !testJSON {
1713 buf.Reset()
1714 }
1715 if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) {
1716 norun = " [no tests to run]"
1717 }
1718 if bytes.HasPrefix(out, noFuzzTestsToFuzz[1:]) || bytes.Contains(out, noFuzzTestsToFuzz) {
1719 norun = " [no fuzz tests to fuzz]"
1720 }
1721 if bytes.HasPrefix(out, tooManyFuzzTestsToFuzz[1:]) || bytes.Contains(out, tooManyFuzzTestsToFuzz) {
1722 norun = "[-fuzz matches more than one fuzz test, won't fuzz]"
1723 }
1724 if len(out) > 0 && !bytes.HasSuffix(out, []byte("\n")) {
1725
1726
1727 cmd.Stdout.Write([]byte("\n"))
1728 }
1729 fmt.Fprintf(cmd.Stdout, "ok \t%s\t%s%s%s\n", a.Package.ImportPath, t, coveragePercentage(out), norun)
1730 r.c.saveOutput(a)
1731 } else {
1732 if testFailFast {
1733 testShouldFailFast.Store(true)
1734 }
1735
1736 base.SetExitStatus(1)
1737 if cancelSignaled {
1738 fmt.Fprintf(cmd.Stdout, "*** Test killed with %v: ran too long (%v).\n", base.SignalTrace, testKillTimeout)
1739 } else if cancelKilled {
1740 fmt.Fprintf(cmd.Stdout, "*** Test killed: ran too long (%v).\n", testKillTimeout)
1741 } else if errors.Is(err, exec.ErrWaitDelay) {
1742 fmt.Fprintf(cmd.Stdout, "*** Test I/O incomplete %v after exiting.\n", cmd.WaitDelay)
1743 }
1744 if ee, ok := errors.AsType[*exec.ExitError](err); !ok || !ee.Exited() || len(out) == 0 {
1745
1746
1747 fmt.Fprintf(cmd.Stdout, "%s\n", err)
1748 } else if !bytes.HasSuffix(out, []byte("\n")) {
1749
1750
1751 cmd.Stdout.Write([]byte("\n"))
1752 }
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762 prefix := ""
1763 if testJSON || testV.json {
1764 prefix = "\x16"
1765 }
1766 fmt.Fprintf(cmd.Stdout, "%sFAIL\t%s\t%s\n", prefix, a.Package.ImportPath, t)
1767 }
1768
1769 if cmd.Stdout != &buf {
1770 buf.Reset()
1771 }
1772 return nil
1773 }
1774
1775
1776
1777
1778 func (c *runCache) tryCache(b *work.Builder, a *work.Action, linkAction *work.Action) bool {
1779 return c.tryCacheWithID(b, a, linkAction.BuildActionID())
1780 }
1781
1782 func (c *runCache) tryCacheWithID(b *work.Builder, a *work.Action, id string) bool {
1783 if len(pkgArgs) == 0 {
1784
1785
1786 if cache.DebugTest {
1787 fmt.Fprintf(os.Stderr, "testcache: caching disabled in local directory mode\n")
1788 }
1789 c.disableCache = true
1790 return false
1791 }
1792
1793 if a.Package.Root == "" {
1794
1795 if cache.DebugTest {
1796 fmt.Fprintf(os.Stderr, "testcache: caching disabled for package outside of module root, GOPATH, or GOROOT: %s\n", a.Package.ImportPath)
1797 }
1798 c.disableCache = true
1799 return false
1800 }
1801
1802 var cacheArgs []string
1803 for _, arg := range testArgs {
1804 i := strings.Index(arg, "=")
1805 if i < 0 || !strings.HasPrefix(arg, "-test.") {
1806 if cache.DebugTest {
1807 fmt.Fprintf(os.Stderr, "testcache: caching disabled for test argument: %s\n", arg)
1808 }
1809 c.disableCache = true
1810 return false
1811 }
1812 switch arg[:i] {
1813 case "-test.benchtime",
1814 "-test.cpu",
1815 "-test.list",
1816 "-test.parallel",
1817 "-test.run",
1818 "-test.short",
1819 "-test.skip",
1820 "-test.timeout",
1821 "-test.failfast",
1822 "-test.v",
1823 "-test.fullpath":
1824
1825
1826
1827 cacheArgs = append(cacheArgs, arg)
1828 case "-test.coverprofile",
1829 "-test.outputdir":
1830
1831
1832
1833 default:
1834
1835 if cache.DebugTest {
1836 fmt.Fprintf(os.Stderr, "testcache: caching disabled for test argument: %s\n", arg)
1837 }
1838 c.disableCache = true
1839 return false
1840 }
1841 }
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868 h := cache.NewHash("testResult")
1869 fmt.Fprintf(h, "test binary %s args %q execcmd %q", id, cacheArgs, work.ExecCmd)
1870 testID := h.Sum()
1871 if c.id1 == (cache.ActionID{}) {
1872 c.id1 = testID
1873 } else {
1874 c.id2 = testID
1875 }
1876 if cache.DebugTest {
1877 fmt.Fprintf(os.Stderr, "testcache: %s: test ID %x => %x\n", a.Package.ImportPath, id, testID)
1878 }
1879
1880
1881
1882 data, entry, err := cache.GetBytes(cache.Default(), testID)
1883 if !bytes.HasPrefix(data, testlogMagic) || data[len(data)-1] != '\n' {
1884 if cache.DebugTest {
1885 if err != nil {
1886 fmt.Fprintf(os.Stderr, "testcache: %s: input list not found: %v\n", a.Package.ImportPath, err)
1887 } else {
1888 fmt.Fprintf(os.Stderr, "testcache: %s: input list malformed\n", a.Package.ImportPath)
1889 }
1890 }
1891 return false
1892 }
1893 testInputsID, err := computeTestInputsID(a, data)
1894 if err != nil {
1895 return false
1896 }
1897 if cache.DebugTest {
1898 fmt.Fprintf(os.Stderr, "testcache: %s: test ID %x => input ID %x => %x\n", a.Package.ImportPath, testID, testInputsID, testAndInputKey(testID, testInputsID))
1899 }
1900
1901
1902
1903 data, entry, err = cache.GetBytes(cache.Default(), testAndInputKey(testID, testInputsID))
1904
1905
1906 if testCoverProfile != "" {
1907
1908 cpData, _, err := cache.GetFile(cache.Default(), coverProfileAndInputKey(testID, testInputsID))
1909 if err != nil {
1910 if cache.DebugTest {
1911 fmt.Fprintf(os.Stderr, "testcache: %s: cached cover profile missing: %v\n", a.Package.ImportPath, err)
1912 }
1913 return false
1914 }
1915 mergeCoverProfile(cpData)
1916 }
1917
1918 if len(data) == 0 || data[len(data)-1] != '\n' {
1919 if cache.DebugTest {
1920 if err != nil {
1921 fmt.Fprintf(os.Stderr, "testcache: %s: test output not found: %v\n", a.Package.ImportPath, err)
1922 } else {
1923 fmt.Fprintf(os.Stderr, "testcache: %s: test output malformed\n", a.Package.ImportPath)
1924 }
1925 }
1926 return false
1927 }
1928 if entry.Time.Before(testCacheExpire) {
1929 if cache.DebugTest {
1930 fmt.Fprintf(os.Stderr, "testcache: %s: test output expired due to go clean -testcache\n", a.Package.ImportPath)
1931 }
1932 return false
1933 }
1934 i := bytes.LastIndexByte(data[:len(data)-1], '\n') + 1
1935 if !bytes.HasPrefix(data[i:], []byte("ok \t")) {
1936 if cache.DebugTest {
1937 fmt.Fprintf(os.Stderr, "testcache: %s: test output malformed\n", a.Package.ImportPath)
1938 }
1939 return false
1940 }
1941 j := bytes.IndexByte(data[i+len("ok \t"):], '\t')
1942 if j < 0 {
1943 if cache.DebugTest {
1944 fmt.Fprintf(os.Stderr, "testcache: %s: test output malformed\n", a.Package.ImportPath)
1945 }
1946 return false
1947 }
1948 j += i + len("ok \t") + 1
1949
1950
1951 c.buf = new(bytes.Buffer)
1952 c.buf.Write(data[:j])
1953 c.buf.WriteString("(cached)")
1954 for j < len(data) && ('0' <= data[j] && data[j] <= '9' || data[j] == '.' || data[j] == 's') {
1955 j++
1956 }
1957 c.buf.Write(data[j:])
1958 return true
1959 }
1960
1961 var errBadTestInputs = errors.New("error parsing test inputs")
1962 var testlogMagic = []byte("# test log\n")
1963
1964
1965
1966
1967 func computeTestInputsID(a *work.Action, testlog []byte) (cache.ActionID, error) {
1968 testlog = bytes.TrimPrefix(testlog, testlogMagic)
1969 h := cache.NewHash("testInputs")
1970
1971 fmt.Fprintf(h, "env GODEBUG %x\n", hashGetenv("GODEBUG"))
1972 pwd := a.Package.Dir
1973 for _, line := range bytes.Split(testlog, []byte("\n")) {
1974 if len(line) == 0 {
1975 continue
1976 }
1977 s := string(line)
1978 op, name, found := strings.Cut(s, " ")
1979 if !found {
1980 if cache.DebugTest {
1981 fmt.Fprintf(os.Stderr, "testcache: %s: input list malformed (%q)\n", a.Package.ImportPath, line)
1982 }
1983 return cache.ActionID{}, errBadTestInputs
1984 }
1985 switch op {
1986 default:
1987 if cache.DebugTest {
1988 fmt.Fprintf(os.Stderr, "testcache: %s: input list malformed (%q)\n", a.Package.ImportPath, line)
1989 }
1990 return cache.ActionID{}, errBadTestInputs
1991 case "getenv":
1992 fmt.Fprintf(h, "env %s %x\n", name, hashGetenv(name))
1993 case "chdir":
1994 pwd = name
1995 fmt.Fprintf(h, "chdir %s %x\n", name, hashStat(name))
1996 case "stat":
1997 if !filepath.IsAbs(name) {
1998 name = filepath.Join(pwd, name)
1999 }
2000 if a.Package.Root == "" || search.InDir(name, a.Package.Root) == "" {
2001
2002 break
2003 }
2004 fmt.Fprintf(h, "stat %s %x\n", name, hashStat(name))
2005 case "open":
2006 if !filepath.IsAbs(name) {
2007 name = filepath.Join(pwd, name)
2008 }
2009 if a.Package.Root == "" || search.InDir(name, a.Package.Root) == "" {
2010
2011 break
2012 }
2013 fh, err := hashOpen(name)
2014 if err != nil {
2015 if cache.DebugTest {
2016 fmt.Fprintf(os.Stderr, "testcache: %s: input file %s: %s\n", a.Package.ImportPath, name, err)
2017 }
2018 return cache.ActionID{}, err
2019 }
2020 fmt.Fprintf(h, "open %s %x\n", name, fh)
2021 }
2022 }
2023 sum := h.Sum()
2024 return sum, nil
2025 }
2026
2027 func hashGetenv(name string) cache.ActionID {
2028 h := cache.NewHash("getenv")
2029 v, ok := os.LookupEnv(name)
2030 if !ok {
2031 h.Write([]byte{0})
2032 } else {
2033 h.Write([]byte{1})
2034 h.Write([]byte(v))
2035 }
2036 return h.Sum()
2037 }
2038
2039 const modTimeCutoff = 2 * time.Second
2040
2041 var errFileTooNew = errors.New("file used as input is too new")
2042
2043 func hashOpen(name string) (cache.ActionID, error) {
2044 h := cache.NewHash("open")
2045 info, err := os.Stat(name)
2046 if err != nil {
2047 fmt.Fprintf(h, "err %v\n", err)
2048 return h.Sum(), nil
2049 }
2050 hashWriteStat(h, info)
2051 if info.IsDir() {
2052 files, err := os.ReadDir(name)
2053 if err != nil {
2054 fmt.Fprintf(h, "err %v\n", err)
2055 }
2056 for _, f := range files {
2057 fmt.Fprintf(h, "file %s ", f.Name())
2058 finfo, err := f.Info()
2059 if err != nil {
2060 fmt.Fprintf(h, "err %v\n", err)
2061 } else {
2062 hashWriteStat(h, finfo)
2063 }
2064 }
2065 } else if info.Mode().IsRegular() {
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075 if time.Since(info.ModTime()) < modTimeCutoff {
2076 return cache.ActionID{}, errFileTooNew
2077 }
2078 }
2079 return h.Sum(), nil
2080 }
2081
2082 func hashStat(name string) cache.ActionID {
2083 h := cache.NewHash("stat")
2084 if info, err := os.Stat(name); err != nil {
2085 fmt.Fprintf(h, "err %v\n", err)
2086 } else {
2087 hashWriteStat(h, info)
2088 }
2089 if info, err := os.Lstat(name); err != nil {
2090 fmt.Fprintf(h, "err %v\n", err)
2091 } else {
2092 hashWriteStat(h, info)
2093 }
2094 return h.Sum()
2095 }
2096
2097 func hashWriteStat(h io.Writer, info fs.FileInfo) {
2098 fmt.Fprintf(h, "stat %d %x %v %v\n", info.Size(), uint64(info.Mode()), info.ModTime(), info.IsDir())
2099 }
2100
2101
2102 func testAndInputKey(testID, testInputsID cache.ActionID) cache.ActionID {
2103 return cache.Subkey(testID, fmt.Sprintf("inputs:%x", testInputsID))
2104 }
2105
2106
2107 func coverProfileAndInputKey(testID, testInputsID cache.ActionID) cache.ActionID {
2108 return cache.Subkey(testAndInputKey(testID, testInputsID), "coverprofile")
2109 }
2110
2111 func (c *runCache) saveOutput(a *work.Action) {
2112 if c.id1 == (cache.ActionID{}) && c.id2 == (cache.ActionID{}) {
2113 return
2114 }
2115
2116
2117 testlog, err := os.ReadFile(a.Objdir + "testlog.txt")
2118 if err != nil || !bytes.HasPrefix(testlog, testlogMagic) || testlog[len(testlog)-1] != '\n' {
2119 if cache.DebugTest {
2120 if err != nil {
2121 fmt.Fprintf(os.Stderr, "testcache: %s: reading testlog: %v\n", a.Package.ImportPath, err)
2122 } else {
2123 fmt.Fprintf(os.Stderr, "testcache: %s: reading testlog: malformed\n", a.Package.ImportPath)
2124 }
2125 }
2126 return
2127 }
2128 testInputsID, err := computeTestInputsID(a, testlog)
2129 if err != nil {
2130 return
2131 }
2132 var coverProfile []byte
2133 if testCoverProfile != "" {
2134 coverProfile, err = os.ReadFile(coverProfTempFile(a))
2135 if err != nil {
2136 if cache.DebugTest {
2137 fmt.Fprintf(os.Stderr, "testcache: %s: reading cover profile: %v\n", a.Package.ImportPath, err)
2138 }
2139 return
2140 }
2141 }
2142 if c.id1 != (cache.ActionID{}) {
2143 if cache.DebugTest {
2144 fmt.Fprintf(os.Stderr, "testcache: %s: save test ID %x => input ID %x => %x\n", a.Package.ImportPath, c.id1, testInputsID, testAndInputKey(c.id1, testInputsID))
2145 }
2146 cache.PutNoVerify(cache.Default(), c.id1, bytes.NewReader(testlog))
2147 cache.PutNoVerify(cache.Default(), testAndInputKey(c.id1, testInputsID), bytes.NewReader(a.TestOutput.Bytes()))
2148 if coverProfile != nil {
2149 cache.PutNoVerify(cache.Default(), coverProfileAndInputKey(c.id1, testInputsID), bytes.NewReader(coverProfile))
2150 }
2151 }
2152 if c.id2 != (cache.ActionID{}) {
2153 if cache.DebugTest {
2154 fmt.Fprintf(os.Stderr, "testcache: %s: save test ID %x => input ID %x => %x\n", a.Package.ImportPath, c.id2, testInputsID, testAndInputKey(c.id2, testInputsID))
2155 }
2156 cache.PutNoVerify(cache.Default(), c.id2, bytes.NewReader(testlog))
2157 cache.PutNoVerify(cache.Default(), testAndInputKey(c.id2, testInputsID), bytes.NewReader(a.TestOutput.Bytes()))
2158 if coverProfile != nil {
2159 cache.PutNoVerify(cache.Default(), coverProfileAndInputKey(c.id2, testInputsID), bytes.NewReader(coverProfile))
2160 }
2161 }
2162 }
2163
2164
2165
2166 func coveragePercentage(out []byte) string {
2167 if !cfg.BuildCover {
2168 return ""
2169 }
2170
2171
2172
2173 re := regexp.MustCompile(`coverage: (.*)\n`)
2174 matches := re.FindSubmatch(out)
2175 if matches == nil {
2176
2177
2178 return ""
2179 }
2180 return fmt.Sprintf("\tcoverage: %s", matches[1])
2181 }
2182
2183
2184 func builderCleanTest(b *work.Builder, ctx context.Context, a *work.Action) error {
2185 if cfg.BuildWork {
2186 return nil
2187 }
2188 b.Shell(a).RemoveAll(a.Objdir)
2189 return nil
2190 }
2191
2192
2193 func builderPrintTest(b *work.Builder, ctx context.Context, a *work.Action) error {
2194 run := a.Deps[0]
2195 if run.Mode == "test clean" {
2196 run = run.Deps[0]
2197 }
2198 if run.Mode != "test run" {
2199 base.Fatalf("internal error: cannot find test run to print")
2200 }
2201 if run.TestOutput != nil {
2202 os.Stdout.Write(run.TestOutput.Bytes())
2203 run.TestOutput = nil
2204 }
2205 return nil
2206 }
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223 func printExitStatus(b *work.Builder, ctx context.Context, a *work.Action) error {
2224 if !testJSON && testFuzz == "" && len(pkgArgs) != 0 {
2225 if base.GetExitStatus() != 0 {
2226 fmt.Println("FAIL")
2227 return nil
2228 }
2229 }
2230 return nil
2231 }
2232
2233
2234
2235
2236
2237
2238 func testBinaryName(p *load.Package) string {
2239 var elem string
2240 if p.ImportPath == "command-line-arguments" {
2241 elem = p.Name
2242 } else {
2243 elem = p.DefaultExecName()
2244 }
2245
2246 return elem + ".test"
2247 }
2248
View as plain text