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, bools, buildtag, directive, errorsas,
82 ifaceassert, nilfunc, printf, stdversion, stringintconv, and tests.
83 You can see the documentation for these and other vet tests via
84 "go doc cmd/vet". To disable the running of go vet, use the -vet=off flag.
85 To run all 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 Save a copy of the test binary to the named file.
166 The test still runs (unless -c 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
660 "-atomic",
661 "-bools",
662 "-buildtag",
663
664
665
666
667 "-directive",
668 "-errorsas",
669
670
671
672 "-ifaceassert",
673
674
675 "-nilfunc",
676 "-printf",
677
678
679 "-slog",
680
681 "-stdversion",
682 "-stringintconv",
683
684
685 "-tests",
686
687
688
689
690
691
692 }
693
694 func runTest(ctx context.Context, cmd *base.Command, args []string) {
695 moduleLoader := modload.NewLoader()
696 pkgArgs, testArgs = testFlags(args)
697 moduleLoader.InitWorkfile()
698
699 if cfg.DebugTrace != "" {
700 var close func() error
701 var err error
702 ctx, close, err = trace.Start(ctx, cfg.DebugTrace)
703 if err != nil {
704 base.Fatalf("failed to start trace: %v", err)
705 }
706 defer func() {
707 if err := close(); err != nil {
708 base.Fatalf("failed to stop trace: %v", err)
709 }
710 }()
711 }
712
713 ctx, span := trace.StartSpan(ctx, fmt.Sprint("Running ", cmd.Name(), " command"))
714 defer span.Done()
715
716 work.FindExecCmd()
717
718 work.BuildInit(moduleLoader)
719 work.VetFlags = testVet.flags
720 work.VetExplicit = testVet.explicit
721 work.VetTool = base.Tool("vet")
722
723 pkgOpts := load.PackageOpts{ModResolveTests: true}
724 pkgs = load.PackagesAndErrors(moduleLoader, ctx, pkgOpts, pkgArgs)
725
726
727 if len(pkgs) == 0 {
728 base.Fatalf("no packages to test")
729 }
730
731 if testFuzz != "" {
732 if !platform.FuzzSupported(cfg.Goos, cfg.Goarch) {
733 base.Fatalf("-fuzz flag is not supported on %s/%s", cfg.Goos, cfg.Goarch)
734 }
735 if len(pkgs) != 1 {
736 base.Fatalf("cannot use -fuzz flag with multiple packages")
737 }
738 if testCoverProfile != "" {
739 base.Fatalf("cannot use -coverprofile flag with -fuzz flag")
740 }
741 if profileFlag := testProfile(); profileFlag != "" {
742 base.Fatalf("cannot use %s flag with -fuzz flag", profileFlag)
743 }
744
745
746
747
748
749
750 mainMods := moduleLoader.MainModules
751 if m := pkgs[0].Module; m != nil && m.Path != "" {
752 if !mainMods.Contains(m.Path) {
753 base.Fatalf("cannot use -fuzz flag on package outside the main module")
754 }
755 } else if pkgs[0].Standard && moduleLoader.Enabled() {
756
757
758
759
760
761
762
763
764
765
766 if strings.HasPrefix(pkgs[0].ImportPath, "cmd/") {
767 if !mainMods.Contains("cmd") || !mainMods.InGorootSrc(module.Version{Path: "cmd"}) {
768 base.Fatalf("cannot use -fuzz flag on package outside the main module")
769 }
770 } else {
771 if !mainMods.Contains("std") || !mainMods.InGorootSrc(module.Version{Path: "std"}) {
772 base.Fatalf("cannot use -fuzz flag on package outside the main module")
773 }
774 }
775 }
776 }
777 if testProfile() != "" && len(pkgs) != 1 {
778 base.Fatalf("cannot use %s flag with multiple packages", testProfile())
779 }
780
781 if testO != "" {
782 if strings.HasSuffix(testO, "/") || strings.HasSuffix(testO, string(os.PathSeparator)) {
783 testODir = true
784 } else if fi, err := os.Stat(testO); err == nil && fi.IsDir() {
785 testODir = true
786 }
787 }
788
789 if len(pkgs) > 1 && (testC || testO != "") && !base.IsNull(testO) {
790 if testO != "" && !testODir {
791 base.Fatalf("with multiple packages, -o must refer to a directory or %s", os.DevNull)
792 }
793
794 pkgsForBinary := map[string][]*load.Package{}
795
796 for _, p := range pkgs {
797 testBinary := testBinaryName(p)
798 pkgsForBinary[testBinary] = append(pkgsForBinary[testBinary], p)
799 }
800
801 for testBinary, pkgs := range pkgsForBinary {
802 if len(pkgs) > 1 {
803 var buf strings.Builder
804 for _, pkg := range pkgs {
805 buf.WriteString(pkg.ImportPath)
806 buf.WriteString("\n")
807 }
808
809 base.Errorf("cannot write test binary %s for multiple packages:\n%s", testBinary, buf.String())
810 }
811 }
812
813 base.ExitIfErrors()
814 }
815
816 initCoverProfile()
817 defer closeCoverProfile()
818
819
820
821
822
823
824
825 if testTimeout > 0 && testFuzz == "" && testBench == "" {
826
827
828
829
830
831
832
833
834
835
836 if wd := testTimeout / 10; wd < 5*time.Second {
837 testWaitDelay = 5 * time.Second
838 } else {
839 testWaitDelay = wd
840 }
841
842
843
844
845
846
847
848
849
850 if testWaitDelay < 1*time.Minute {
851 testKillTimeout = testTimeout + 1*time.Minute
852 } else {
853 testKillTimeout = testTimeout + testWaitDelay
854 }
855 }
856
857
858
859
860 if dir, _, _ := cache.DefaultDir(); dir != "off" {
861 if data, _ := lockedfile.Read(filepath.Join(dir, "testexpire.txt")); len(data) > 0 && data[len(data)-1] == '\n' {
862 if t, err := strconv.ParseInt(string(data[:len(data)-1]), 10, 64); err == nil {
863 testCacheExpire = time.Unix(0, t)
864 }
865 }
866 }
867
868 b := work.NewBuilder("", moduleLoader.VendorDirOrEmpty)
869 defer func() {
870 if err := b.Close(); err != nil {
871 base.Fatal(err)
872 }
873 }()
874
875 var builds, runs, prints []*work.Action
876 var writeCoverMetaAct *work.Action
877
878 if cfg.BuildCoverPkg != nil {
879 match := make([]func(*modload.Loader, *load.Package) bool, len(cfg.BuildCoverPkg))
880 for i := range cfg.BuildCoverPkg {
881 match[i] = load.MatchPackage(cfg.BuildCoverPkg[i], base.Cwd())
882 }
883
884
885
886 plist := load.TestPackageList(moduleLoader, ctx, pkgOpts, pkgs)
887 testCoverPkgs = load.SelectCoverPackages(moduleLoader, plist, match, "test")
888 if len(testCoverPkgs) > 0 {
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
924
925
926
927
928
929
930
931
932
933
934 writeCoverMetaAct = &work.Action{
935 Mode: "write coverage meta-data file",
936 Actor: work.ActorFunc(work.WriteCoverMetaFilesFile),
937 Objdir: b.NewObjdir(),
938 }
939 for _, p := range testCoverPkgs {
940 p.Internal.Cover.GenMeta = true
941 }
942 }
943 }
944
945
946
947 if testFuzz != "" {
948
949
950
951 var skipInstrumentation = map[string]bool{
952 "context": true,
953 "internal/fuzz": true,
954 "internal/godebug": true,
955 "internal/runtime/maps": true,
956 "internal/sync": true,
957 "reflect": true,
958 "runtime": true,
959 "sync": true,
960 "sync/atomic": true,
961 "syscall": true,
962 "testing": true,
963 "time": true,
964 }
965 for _, p := range load.TestPackageList(moduleLoader, ctx, pkgOpts, pkgs) {
966 if !skipInstrumentation[p.ImportPath] {
967 p.Internal.FuzzInstrument = true
968 }
969 }
970 }
971
972
973 allImports := make(map[*load.Package]bool)
974 for _, p := range pkgs {
975 if p.Error != nil && p.Error.IsImportCycle {
976 continue
977 }
978 for _, p1 := range p.Internal.Imports {
979 allImports[p1] = true
980 }
981 }
982
983 if cfg.BuildCover {
984 for _, p := range pkgs {
985
986
987
988
989
990
991
992
993
994 if cfg.BuildCoverMode == "atomic" && p.ImportPath != "sync/atomic" {
995 load.EnsureImport(moduleLoader, p, "sync/atomic")
996 }
997
998
999
1000
1001
1002
1003
1004
1005 if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 && cfg.BuildCoverPkg == nil {
1006 p.Internal.Cover.GenMeta = true
1007 }
1008
1009
1010
1011
1012 if cfg.BuildCover {
1013 if p.Internal.Cover.GenMeta {
1014 p.Internal.Cover.Mode = cfg.BuildCoverMode
1015 }
1016 }
1017 }
1018 }
1019
1020
1021 for _, p := range pkgs {
1022 reportErr := func(perr *load.Package, err error) {
1023 str := err.Error()
1024 if p.ImportPath != "" {
1025 load.DefaultPrinter().Errorf(perr, "# %s\n%s", p.ImportPath, str)
1026 } else {
1027 load.DefaultPrinter().Errorf(perr, "%s", str)
1028 }
1029 }
1030 reportSetupFailed := func(perr *load.Package, err error) {
1031 var stdout io.Writer = os.Stdout
1032 if testJSON {
1033 json := test2json.NewConverter(stdout, p.ImportPath, test2json.Timestamp)
1034 defer func() {
1035 json.Exited(err)
1036 json.Close()
1037 }()
1038 if gotestjsonbuildtext.Value() == "1" {
1039
1040
1041 gotestjsonbuildtext.IncNonDefault()
1042 } else {
1043 json.SetFailedBuild(perr.Desc())
1044 }
1045 stdout = json
1046 }
1047 fmt.Fprintf(stdout, "FAIL\t%s [setup failed]\n", p.ImportPath)
1048 base.SetExitStatus(1)
1049 }
1050
1051 var firstErrPkg *load.Package
1052 load.PackageErrors([]*load.Package{p}, func(p *load.Package) {
1053 reportErr(p, p.Error)
1054 if firstErrPkg == nil {
1055 firstErrPkg = p
1056 }
1057 })
1058 if firstErrPkg != nil {
1059 reportSetupFailed(firstErrPkg, firstErrPkg.Error)
1060 continue
1061 }
1062 buildTest, runTest, printTest, perr, err := builderTest(moduleLoader, b, ctx, pkgOpts, p, allImports[p], writeCoverMetaAct)
1063 if err != nil {
1064 reportErr(perr, err)
1065 reportSetupFailed(perr, err)
1066 continue
1067 }
1068 builds = append(builds, buildTest)
1069 runs = append(runs, runTest)
1070 prints = append(prints, printTest)
1071 }
1072
1073
1074
1075
1076
1077
1078 var prevBarrier *work.Action
1079 ch := make(chan struct{})
1080 close(ch)
1081 for _, a := range runs {
1082 if r, ok := a.Actor.(*runTestActor); ok {
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093 barrier := &work.Action{
1094 Mode: "test barrier",
1095 Deps: slices.Clip(a.Deps),
1096 }
1097 if prevBarrier != nil {
1098 barrier.Deps = append(barrier.Deps, prevBarrier)
1099 }
1100 a.Deps = []*work.Action{barrier}
1101 prevBarrier = barrier
1102
1103 r.prev = ch
1104 ch = make(chan struct{})
1105 r.next = ch
1106 }
1107 }
1108
1109
1110 root := &work.Action{Mode: "go test", Actor: work.ActorFunc(printExitStatus), Deps: prints}
1111
1112
1113
1114 for i, a := range prints {
1115 if i > 0 {
1116 a.Deps = append(a.Deps, prints[i-1])
1117 }
1118 }
1119
1120
1121 if !testC && (testBench != "") {
1122
1123
1124 for i, run := range runs {
1125 if i == 0 {
1126 run.Deps = append(run.Deps, builds...)
1127 } else {
1128 run.Deps = append(run.Deps, prints[i-1])
1129 }
1130 }
1131 }
1132
1133 b.Do(ctx, root)
1134 }
1135
1136 var windowsBadWords = []string{
1137 "install",
1138 "patch",
1139 "setup",
1140 "update",
1141 }
1142
1143 func builderTest(ld *modload.Loader, 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) {
1144 if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
1145 build := b.CompileAction(work.ModeBuild, work.ModeBuild, p)
1146 run := &work.Action{
1147 Mode: "test run",
1148 Actor: new(runTestActor),
1149 Deps: []*work.Action{build},
1150 Objdir: b.NewObjdir(),
1151 Package: p,
1152 IgnoreFail: true,
1153 }
1154 if writeCoverMetaAct != nil && build.Actor != nil {
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168 run.Deps = append(run.Deps, writeCoverMetaAct)
1169 writeCoverMetaAct.Deps = append(writeCoverMetaAct.Deps, build)
1170 }
1171 addTestVet(ld, b, p, run, nil)
1172 print := &work.Action{
1173 Mode: "test print",
1174 Actor: work.ActorFunc(builderPrintTest),
1175 Deps: []*work.Action{run},
1176 Package: p,
1177 IgnoreFail: true,
1178 }
1179 return build, run, print, nil, nil
1180 }
1181
1182
1183
1184
1185
1186 var cover *load.TestCover
1187 if cfg.BuildCover {
1188 cover = &load.TestCover{
1189 Mode: cfg.BuildCoverMode,
1190 Local: cfg.BuildCoverPkg == nil,
1191 Pkgs: testCoverPkgs,
1192 Paths: cfg.BuildCoverPkg,
1193 }
1194 }
1195 pmain, ptest, pxtest, perr := load.TestPackagesFor(ld, ctx, pkgOpts, p, cover)
1196 if perr != nil {
1197 return nil, nil, nil, perr, perr.Error
1198 }
1199
1200
1201
1202
1203
1204 if imported && ptest != p {
1205 buildTest := b.CompileAction(work.ModeBuild, work.ModeBuild, ptest)
1206 buildP := b.CompileAction(work.ModeBuild, work.ModeBuild, p)
1207 buildTest.Deps = append(buildTest.Deps, buildP)
1208 }
1209
1210 testBinary := testBinaryName(p)
1211
1212
1213
1214 testDir := b.CompileAction(work.ModeBuild, work.ModeBuild, pmain).Objdir
1215 if err := b.BackgroundShell().Mkdir(testDir); err != nil {
1216 return nil, nil, nil, nil, err
1217 }
1218
1219 pmain.Dir = testDir
1220 pmain.Internal.OmitDebug = !testC && !testNeedBinary()
1221 if pmain.ImportPath == "runtime.test" {
1222
1223
1224 pmain.Internal.OmitDebug = false
1225 }
1226
1227 if !cfg.BuildN {
1228
1229
1230 if err := os.WriteFile(testDir+"_testmain.go", *pmain.Internal.TestmainGo, 0666); err != nil {
1231 return nil, nil, nil, nil, err
1232 }
1233 }
1234
1235 a := b.LinkAction(ld, work.ModeBuild, work.ModeBuild, pmain)
1236 a.Target = testDir + testBinary + cfg.ExeSuffix
1237 if cfg.Goos == "windows" {
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260 for _, bad := range windowsBadWords {
1261 if strings.Contains(testBinary, bad) {
1262 a.Target = testDir + "test.test" + cfg.ExeSuffix
1263 break
1264 }
1265 }
1266 }
1267 buildAction = a
1268 var installAction, cleanAction *work.Action
1269 if testC || testNeedBinary() {
1270
1271 target := filepath.Join(base.Cwd(), testBinary+cfg.ExeSuffix)
1272 isNull := false
1273
1274 if testO != "" {
1275 target = testO
1276
1277 if testODir {
1278 if filepath.IsAbs(target) {
1279 target = filepath.Join(target, testBinary+cfg.ExeSuffix)
1280 } else {
1281 target = filepath.Join(base.Cwd(), target, testBinary+cfg.ExeSuffix)
1282 }
1283 } else {
1284 if base.IsNull(target) {
1285 isNull = true
1286 } else if !filepath.IsAbs(target) {
1287 target = filepath.Join(base.Cwd(), target)
1288 }
1289 }
1290 }
1291
1292 if isNull {
1293 runAction = buildAction
1294 } else {
1295 pmain.Target = target
1296 installAction = &work.Action{
1297 Mode: "test build",
1298 Actor: work.ActorFunc(work.BuildInstallFunc),
1299 Deps: []*work.Action{buildAction},
1300 Package: pmain,
1301 Target: target,
1302 }
1303 runAction = installAction
1304 }
1305 }
1306
1307 var vetRunAction *work.Action
1308 if testC {
1309 printAction = &work.Action{Mode: "test print (nop)", Package: p, Deps: []*work.Action{runAction}}
1310 vetRunAction = printAction
1311 } else {
1312
1313 rta := &runTestActor{
1314 writeCoverMetaAct: writeCoverMetaAct,
1315 }
1316 runAction = &work.Action{
1317 Mode: "test run",
1318 Actor: rta,
1319 Deps: []*work.Action{buildAction},
1320 Package: p,
1321 IgnoreFail: true,
1322 TryCache: rta.c.tryCache,
1323 }
1324 if writeCoverMetaAct != nil {
1325
1326
1327
1328
1329
1330 runAction.Deps = append(runAction.Deps, writeCoverMetaAct)
1331 if !p.IsTestOnly() {
1332
1333
1334
1335
1336
1337 compileAction := b.CompileAction(work.ModeBuild, work.ModeBuild, p)
1338 writeCoverMetaAct.Deps = append(writeCoverMetaAct.Deps, compileAction)
1339 }
1340 }
1341 runAction.Objdir = testDir
1342 vetRunAction = runAction
1343 cleanAction = &work.Action{
1344 Mode: "test clean",
1345 Actor: work.ActorFunc(builderCleanTest),
1346 Deps: []*work.Action{runAction},
1347 Package: p,
1348 IgnoreFail: true,
1349 Objdir: testDir,
1350 }
1351 printAction = &work.Action{
1352 Mode: "test print",
1353 Actor: work.ActorFunc(builderPrintTest),
1354 Deps: []*work.Action{cleanAction},
1355 Package: p,
1356 IgnoreFail: true,
1357 }
1358 }
1359
1360 if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
1361 addTestVet(ld, b, ptest, vetRunAction, installAction)
1362 }
1363 if pxtest != nil {
1364 addTestVet(ld, b, pxtest, vetRunAction, installAction)
1365 }
1366
1367 if installAction != nil {
1368 if runAction != installAction {
1369 installAction.Deps = append(installAction.Deps, runAction)
1370 }
1371 if cleanAction != nil {
1372 cleanAction.Deps = append(cleanAction.Deps, installAction)
1373 }
1374 }
1375
1376 return buildAction, runAction, printAction, nil, nil
1377 }
1378
1379 func addTestVet(ld *modload.Loader, b *work.Builder, p *load.Package, runAction, installAction *work.Action) {
1380 if testVet.off {
1381 return
1382 }
1383
1384 vet := b.VetAction(ld, work.ModeBuild, work.ModeBuild, false, p)
1385 runAction.Deps = append(runAction.Deps, vet)
1386
1387
1388
1389
1390 if installAction != nil {
1391 installAction.Deps = append(installAction.Deps, vet)
1392 }
1393 }
1394
1395 var noTestsToRun = []byte("\ntesting: warning: no tests to run\n")
1396 var noFuzzTestsToFuzz = []byte("\ntesting: warning: no fuzz tests to fuzz\n")
1397 var tooManyFuzzTestsToFuzz = []byte("\ntesting: warning: -fuzz matches more than one fuzz test, won't fuzz\n")
1398
1399
1400 type runTestActor struct {
1401 c runCache
1402
1403
1404
1405
1406
1407 writeCoverMetaAct *work.Action
1408
1409
1410 prev <-chan struct{}
1411 next chan<- struct{}
1412 }
1413
1414
1415 type runCache struct {
1416 disableCache bool
1417
1418 buf *bytes.Buffer
1419 id1 cache.ActionID
1420 id2 cache.ActionID
1421 covMeta cache.ActionID
1422 }
1423
1424 func coverProfTempFile(a *work.Action) string {
1425 if a.Objdir == "" {
1426 panic("internal error: objdir not set in coverProfTempFile")
1427 }
1428 return a.Objdir + "_cover_.out"
1429 }
1430
1431
1432
1433
1434
1435
1436 var stdoutMu sync.Mutex
1437
1438 type lockedStdout struct{}
1439
1440 func (lockedStdout) Write(b []byte) (int, error) {
1441 stdoutMu.Lock()
1442 defer stdoutMu.Unlock()
1443 return os.Stdout.Write(b)
1444 }
1445
1446 func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action) error {
1447 sh := b.Shell(a)
1448 barrierAction := a.Deps[0]
1449 buildAction := barrierAction.Deps[0]
1450
1451
1452 select {
1453 case <-r.prev:
1454
1455 if testShouldFailFast.Load() {
1456 close(r.next)
1457 return nil
1458 }
1459 case <-base.Interrupted:
1460
1461
1462
1463 base.SetExitStatus(1)
1464 return nil
1465 }
1466
1467
1468
1469
1470 streamOutput := len(pkgArgs) == 0 || testBench != "" || testFuzz != ""
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486 streamAndCacheOutput := testShowPass() && (len(pkgs) == 1 || cfg.BuildP == 1) || testJSON
1487
1488 var stdout io.Writer = os.Stdout
1489 var err error
1490 var json *test2json.Converter
1491 if testJSON {
1492 json = test2json.NewConverter(lockedStdout{}, a.Package.ImportPath, test2json.Timestamp)
1493 defer func() {
1494 json.Exited(err)
1495 json.Close()
1496 }()
1497 stdout = json
1498 }
1499
1500 var buf bytes.Buffer
1501 if streamOutput {
1502
1503 } else if streamAndCacheOutput {
1504
1505
1506 stdout = io.MultiWriter(stdout, &buf)
1507 } else {
1508 stdout = &buf
1509 }
1510
1511
1512 close(r.next)
1513
1514 if a.Failed != nil {
1515
1516 if json != nil && a.Failed.Package != nil {
1517 if gotestjsonbuildtext.Value() == "1" {
1518 gotestjsonbuildtext.IncNonDefault()
1519 } else {
1520 json.SetFailedBuild(a.Failed.Package.Desc())
1521 }
1522 }
1523 a.Failed = nil
1524 fmt.Fprintf(stdout, "FAIL\t%s [build failed]\n", a.Package.ImportPath)
1525
1526 err = errors.New("build failed")
1527 base.SetExitStatus(1)
1528 if stdout == &buf {
1529 a.TestOutput = &buf
1530 }
1531 return nil
1532 }
1533
1534 if p := a.Package; len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
1535 reportNoTestFiles := true
1536 if cfg.BuildCover && p.Internal.Cover.GenMeta {
1537 if err := sh.Mkdir(a.Objdir); err != nil {
1538 return err
1539 }
1540 mf, err := work.BuildActionCoverMetaFile(a)
1541 if err != nil {
1542 return err
1543 } else if mf != "" {
1544 reportNoTestFiles = false
1545
1546 if err := work.WriteCoveragePercent(b, a, mf, stdout); err != nil {
1547 return err
1548 }
1549
1550
1551
1552 if coverMerge.f != nil {
1553 cp := coverProfTempFile(a)
1554 if err := work.WriteCoverageProfile(b, a, mf, cp, stdout); err != nil {
1555 return err
1556 }
1557 mergeCoverProfile(cp)
1558 }
1559 }
1560 }
1561 if reportNoTestFiles {
1562 fmt.Fprintf(stdout, "? \t%s\t[no test files]\n", p.ImportPath)
1563 }
1564 if stdout == &buf {
1565 a.TestOutput = &buf
1566 }
1567 return nil
1568 }
1569
1570 if r.c.buf == nil {
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580 r.c.tryCacheWithID(b, a, buildAction.BuildContentID())
1581 }
1582 if r.c.buf != nil {
1583 if stdout != &buf {
1584 stdout.Write(r.c.buf.Bytes())
1585 r.c.buf.Reset()
1586 }
1587 a.TestOutput = r.c.buf
1588 return nil
1589 }
1590
1591 execCmd := work.FindExecCmd()
1592 testlogArg := []string{}
1593 if !r.c.disableCache && len(execCmd) == 0 {
1594 testlogArg = []string{"-test.testlogfile=" + a.Objdir + "testlog.txt"}
1595 }
1596 panicArg := "-test.paniconexit0"
1597 fuzzArg := []string{}
1598 if testFuzz != "" {
1599 fuzzCacheDir := filepath.Join(cache.Default().FuzzDir(), a.Package.ImportPath)
1600 fuzzArg = []string{"-test.fuzzcachedir=" + fuzzCacheDir}
1601 }
1602 coverdirArg := []string{}
1603 addToEnv := ""
1604 if cfg.BuildCover {
1605 gcd := filepath.Join(a.Objdir, "gocoverdir")
1606 if err := sh.Mkdir(gcd); err != nil {
1607
1608
1609
1610
1611
1612 base.Fatalf("failed to create temporary dir: %v", err)
1613 }
1614 coverdirArg = append(coverdirArg, "-test.gocoverdir="+gcd)
1615 if r.writeCoverMetaAct != nil {
1616
1617
1618
1619 src := r.writeCoverMetaAct.Objdir + coverage.MetaFilesFileName
1620 dst := filepath.Join(gcd, coverage.MetaFilesFileName)
1621 if err := sh.CopyFile(dst, src, 0666, false); err != nil {
1622 return err
1623 }
1624 }
1625
1626
1627
1628
1629 addToEnv = "GOCOVERDIR=" + gcd
1630 }
1631 args := str.StringList(execCmd, buildAction.BuiltTarget(), testlogArg, panicArg, fuzzArg, coverdirArg, testArgs)
1632
1633 if testCoverProfile != "" {
1634
1635 for i, arg := range args {
1636 if strings.HasPrefix(arg, "-test.coverprofile=") {
1637 args[i] = "-test.coverprofile=" + coverProfTempFile(a)
1638 }
1639 }
1640 }
1641
1642 if cfg.BuildN || cfg.BuildX {
1643 sh.ShowCmd("", "%s", strings.Join(args, " "))
1644 if cfg.BuildN {
1645 return nil
1646 }
1647 }
1648
1649
1650
1651 ctx, cancel := context.WithTimeout(ctx, testKillTimeout)
1652 defer cancel()
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665 var (
1666 cmd *exec.Cmd
1667 t0 time.Time
1668 cancelKilled = false
1669 cancelSignaled = false
1670 )
1671 for {
1672 cmd = exec.CommandContext(ctx, args[0], args[1:]...)
1673 cmd.Dir = a.Package.Dir
1674
1675 env := slices.Clip(cfg.OrigEnv)
1676 env = base.AppendPATH(env)
1677 env = base.AppendPWD(env, cmd.Dir)
1678 cmd.Env = env
1679 if addToEnv != "" {
1680 cmd.Env = append(cmd.Env, addToEnv)
1681 }
1682
1683 cmd.Stdout = stdout
1684 cmd.Stderr = stdout
1685
1686 cmd.Cancel = func() error {
1687 if base.SignalTrace == nil {
1688 err := cmd.Process.Kill()
1689 if err == nil {
1690 cancelKilled = true
1691 }
1692 return err
1693 }
1694
1695
1696
1697 err := cmd.Process.Signal(base.SignalTrace)
1698 if err == nil {
1699 cancelSignaled = true
1700 }
1701 return err
1702 }
1703 cmd.WaitDelay = testWaitDelay
1704
1705 base.StartSigHandlers()
1706 t0 = time.Now()
1707 err = cmd.Run()
1708
1709 if !base.IsETXTBSY(err) {
1710
1711
1712 break
1713 }
1714 }
1715
1716 out := buf.Bytes()
1717 a.TestOutput = &buf
1718 t := fmt.Sprintf("%.3fs", time.Since(t0).Seconds())
1719
1720 mergeCoverProfile(coverProfTempFile(a))
1721
1722 if err == nil {
1723 norun := ""
1724 if !testShowPass() && !testJSON {
1725 buf.Reset()
1726 }
1727 if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) {
1728 norun = " [no tests to run]"
1729 }
1730 if bytes.HasPrefix(out, noFuzzTestsToFuzz[1:]) || bytes.Contains(out, noFuzzTestsToFuzz) {
1731 norun = " [no fuzz tests to fuzz]"
1732 }
1733 if bytes.HasPrefix(out, tooManyFuzzTestsToFuzz[1:]) || bytes.Contains(out, tooManyFuzzTestsToFuzz) {
1734 norun = "[-fuzz matches more than one fuzz test, won't fuzz]"
1735 }
1736 if len(out) > 0 && !bytes.HasSuffix(out, []byte("\n")) {
1737
1738
1739 cmd.Stdout.Write([]byte("\n"))
1740 }
1741 fmt.Fprintf(cmd.Stdout, "ok \t%s\t%s%s%s\n", a.Package.ImportPath, t, coveragePercentage(out), norun)
1742 r.c.saveOutput(a)
1743 } else {
1744 if testFailFast {
1745 testShouldFailFast.Store(true)
1746 }
1747
1748 base.SetExitStatus(1)
1749 if cancelSignaled {
1750 fmt.Fprintf(cmd.Stdout, "*** Test killed with %v: ran too long (%v).\n", base.SignalTrace, testKillTimeout)
1751 } else if cancelKilled {
1752 fmt.Fprintf(cmd.Stdout, "*** Test killed: ran too long (%v).\n", testKillTimeout)
1753 } else if errors.Is(err, exec.ErrWaitDelay) {
1754 fmt.Fprintf(cmd.Stdout, "*** Test I/O incomplete %v after exiting.\n", cmd.WaitDelay)
1755 }
1756 if ee, ok := errors.AsType[*exec.ExitError](err); !ok || !ee.Exited() || len(out) == 0 {
1757
1758
1759 fmt.Fprintf(cmd.Stdout, "%s\n", err)
1760 } else if !bytes.HasSuffix(out, []byte("\n")) {
1761
1762
1763 cmd.Stdout.Write([]byte("\n"))
1764 }
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774 prefix := ""
1775 if testJSON || testV.json {
1776 prefix = "\x16"
1777 }
1778 fmt.Fprintf(cmd.Stdout, "%sFAIL\t%s\t%s\n", prefix, a.Package.ImportPath, t)
1779 }
1780
1781 if cmd.Stdout != &buf {
1782 buf.Reset()
1783 }
1784 return nil
1785 }
1786
1787
1788
1789
1790 func (c *runCache) tryCache(b *work.Builder, a *work.Action, linkAction *work.Action) bool {
1791 return c.tryCacheWithID(b, a, linkAction.BuildActionID())
1792 }
1793
1794 func (c *runCache) tryCacheWithID(b *work.Builder, a *work.Action, id string) bool {
1795 if len(pkgArgs) == 0 {
1796
1797
1798 if cache.DebugTest {
1799 fmt.Fprintf(os.Stderr, "testcache: caching disabled in local directory mode\n")
1800 }
1801 c.disableCache = true
1802 return false
1803 }
1804
1805 if a.Package.Root == "" {
1806
1807 if cache.DebugTest {
1808 fmt.Fprintf(os.Stderr, "testcache: caching disabled for package outside of module root, GOPATH, or GOROOT: %s\n", a.Package.ImportPath)
1809 }
1810 c.disableCache = true
1811 return false
1812 }
1813
1814
1815
1816
1817
1818
1819 if len(testCoverPkgs) != 0 {
1820 searchDeps := a.Deps
1821 for _, dep := range a.Deps {
1822 if dep.Mode == "test barrier" {
1823 searchDeps = dep.Deps
1824 break
1825 }
1826 }
1827 for _, dep := range searchDeps {
1828 if dep.Mode == "write coverage meta-data file" {
1829 h := cache.NewHash("covermeta")
1830 for _, metaDep := range dep.Deps {
1831 if aid := metaDep.BuildActionID(); aid != "" {
1832 fmt.Fprintf(h, "dep %s\n", aid)
1833 }
1834 }
1835 c.covMeta = h.Sum()
1836 break
1837 }
1838 }
1839 }
1840
1841 var cacheArgs []string
1842 for _, arg := range testArgs {
1843 i := strings.Index(arg, "=")
1844 if i < 0 || !strings.HasPrefix(arg, "-test.") {
1845 if cache.DebugTest {
1846 fmt.Fprintf(os.Stderr, "testcache: caching disabled for test argument: %s\n", arg)
1847 }
1848 c.disableCache = true
1849 return false
1850 }
1851 switch arg[:i] {
1852 case "-test.benchtime",
1853 "-test.cpu",
1854 "-test.list",
1855 "-test.parallel",
1856 "-test.run",
1857 "-test.short",
1858 "-test.skip",
1859 "-test.timeout",
1860 "-test.failfast",
1861 "-test.v",
1862 "-test.fullpath":
1863
1864
1865
1866 cacheArgs = append(cacheArgs, arg)
1867 case "-test.coverprofile",
1868 "-test.outputdir":
1869
1870
1871
1872 default:
1873
1874 if cache.DebugTest {
1875 fmt.Fprintf(os.Stderr, "testcache: caching disabled for test argument: %s\n", arg)
1876 }
1877 c.disableCache = true
1878 return false
1879 }
1880 }
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907 h := cache.NewHash("testResult")
1908 fmt.Fprintf(h, "test binary %s args %q execcmd %q", id, cacheArgs, work.ExecCmd)
1909 testID := h.Sum()
1910 if c.id1 == (cache.ActionID{}) {
1911 c.id1 = testID
1912 } else {
1913 c.id2 = testID
1914 }
1915 if cache.DebugTest {
1916 fmt.Fprintf(os.Stderr, "testcache: %s: test ID %x => %x\n", a.Package.ImportPath, id, testID)
1917 }
1918
1919
1920
1921 data, entry, err := cache.GetBytes(cache.Default(), testID)
1922 if !bytes.HasPrefix(data, testlogMagic) || data[len(data)-1] != '\n' {
1923 if cache.DebugTest {
1924 if err != nil {
1925 fmt.Fprintf(os.Stderr, "testcache: %s: input list not found: %v\n", a.Package.ImportPath, err)
1926 } else {
1927 fmt.Fprintf(os.Stderr, "testcache: %s: input list malformed\n", a.Package.ImportPath)
1928 }
1929 }
1930 return false
1931 }
1932 testInputsID, err := computeTestInputsID(a, data)
1933 if err != nil {
1934 return false
1935 }
1936 if cache.DebugTest {
1937 fmt.Fprintf(os.Stderr, "testcache: %s: test ID %x => input ID %x => %x\n", a.Package.ImportPath, testID, testInputsID, testAndInputKey(testID, testInputsID))
1938 }
1939
1940
1941
1942 data, entry, err = cache.GetBytes(cache.Default(), testAndInputKey(testID, testInputsID))
1943
1944
1945 if testCoverProfile != "" {
1946
1947 cpData, _, err := cache.GetFile(cache.Default(), coverProfileAndInputKey(testID, testInputsID, c.covMeta))
1948 if err != nil {
1949 if cache.DebugTest {
1950 fmt.Fprintf(os.Stderr, "testcache: %s: cached cover profile missing: %v\n", a.Package.ImportPath, err)
1951 }
1952 return false
1953 }
1954 mergeCoverProfile(cpData)
1955 } else if c.covMeta != (cache.ActionID{}) {
1956
1957
1958
1959
1960 _, _, err := cache.GetFile(cache.Default(), coverProfileAndInputKey(testID, testInputsID, c.covMeta))
1961 if err != nil {
1962 if cache.DebugTest {
1963 fmt.Fprintf(os.Stderr, "testcache: %s: coverage metadata changed, re-running test: %v\n", a.Package.ImportPath, err)
1964 }
1965 return false
1966 }
1967 }
1968
1969 if len(data) == 0 || data[len(data)-1] != '\n' {
1970 if cache.DebugTest {
1971 if err != nil {
1972 fmt.Fprintf(os.Stderr, "testcache: %s: test output not found: %v\n", a.Package.ImportPath, err)
1973 } else {
1974 fmt.Fprintf(os.Stderr, "testcache: %s: test output malformed\n", a.Package.ImportPath)
1975 }
1976 }
1977 return false
1978 }
1979 if entry.Time.Before(testCacheExpire) {
1980 if cache.DebugTest {
1981 fmt.Fprintf(os.Stderr, "testcache: %s: test output expired due to go clean -testcache\n", a.Package.ImportPath)
1982 }
1983 return false
1984 }
1985 i := bytes.LastIndexByte(data[:len(data)-1], '\n') + 1
1986 if !bytes.HasPrefix(data[i:], []byte("ok \t")) {
1987 if cache.DebugTest {
1988 fmt.Fprintf(os.Stderr, "testcache: %s: test output malformed\n", a.Package.ImportPath)
1989 }
1990 return false
1991 }
1992 j := bytes.IndexByte(data[i+len("ok \t"):], '\t')
1993 if j < 0 {
1994 if cache.DebugTest {
1995 fmt.Fprintf(os.Stderr, "testcache: %s: test output malformed\n", a.Package.ImportPath)
1996 }
1997 return false
1998 }
1999 j += i + len("ok \t") + 1
2000
2001
2002 c.buf = new(bytes.Buffer)
2003 c.buf.Write(data[:j])
2004 c.buf.WriteString("(cached)")
2005 for j < len(data) && ('0' <= data[j] && data[j] <= '9' || data[j] == '.' || data[j] == 's') {
2006 j++
2007 }
2008 c.buf.Write(data[j:])
2009 return true
2010 }
2011
2012 var errBadTestInputs = errors.New("error parsing test inputs")
2013 var testlogMagic = []byte("# test log\n")
2014
2015
2016
2017
2018 func computeTestInputsID(a *work.Action, testlog []byte) (cache.ActionID, error) {
2019 testlog = bytes.TrimPrefix(testlog, testlogMagic)
2020 h := cache.NewHash("testInputs")
2021
2022 fmt.Fprintf(h, "env GODEBUG %x\n", hashGetenv("GODEBUG"))
2023 pwd := a.Package.Dir
2024 for _, line := range bytes.Split(testlog, []byte("\n")) {
2025 if len(line) == 0 {
2026 continue
2027 }
2028 s := string(line)
2029 op, name, found := strings.Cut(s, " ")
2030 if !found {
2031 if cache.DebugTest {
2032 fmt.Fprintf(os.Stderr, "testcache: %s: input list malformed (%q)\n", a.Package.ImportPath, line)
2033 }
2034 return cache.ActionID{}, errBadTestInputs
2035 }
2036 switch op {
2037 default:
2038 if cache.DebugTest {
2039 fmt.Fprintf(os.Stderr, "testcache: %s: input list malformed (%q)\n", a.Package.ImportPath, line)
2040 }
2041 return cache.ActionID{}, errBadTestInputs
2042 case "getenv":
2043 fmt.Fprintf(h, "env %s %x\n", name, hashGetenv(name))
2044 case "chdir":
2045 pwd = name
2046 fmt.Fprintf(h, "chdir %s %x\n", name, hashStat(name))
2047 case "stat":
2048 if !filepath.IsAbs(name) {
2049 name = filepath.Join(pwd, name)
2050 }
2051 if a.Package.Root == "" || search.InDir(name, a.Package.Root) == "" {
2052
2053 break
2054 }
2055 fmt.Fprintf(h, "stat %s %x\n", name, hashStat(name))
2056 case "open":
2057 if !filepath.IsAbs(name) {
2058 name = filepath.Join(pwd, name)
2059 }
2060 if a.Package.Root == "" || search.InDir(name, a.Package.Root) == "" {
2061
2062 break
2063 }
2064 fh, err := hashOpen(name)
2065 if err != nil {
2066 if cache.DebugTest {
2067 fmt.Fprintf(os.Stderr, "testcache: %s: input file %s: %s\n", a.Package.ImportPath, name, err)
2068 }
2069 return cache.ActionID{}, err
2070 }
2071 fmt.Fprintf(h, "open %s %x\n", name, fh)
2072 }
2073 }
2074 sum := h.Sum()
2075 return sum, nil
2076 }
2077
2078 func hashGetenv(name string) cache.ActionID {
2079 h := cache.NewHash("getenv")
2080 v, ok := os.LookupEnv(name)
2081 if !ok {
2082 h.Write([]byte{0})
2083 } else {
2084 h.Write([]byte{1})
2085 h.Write([]byte(v))
2086 }
2087 return h.Sum()
2088 }
2089
2090 const modTimeCutoff = 2 * time.Second
2091
2092 var errFileTooNew = errors.New("file used as input is too new")
2093
2094 func hashOpen(name string) (cache.ActionID, error) {
2095 h := cache.NewHash("open")
2096 info, err := os.Stat(name)
2097 if err != nil {
2098 fmt.Fprintf(h, "err %v\n", err)
2099 return h.Sum(), nil
2100 }
2101 hashWriteStat(h, info)
2102 if info.IsDir() {
2103 files, err := os.ReadDir(name)
2104 if err != nil {
2105 fmt.Fprintf(h, "err %v\n", err)
2106 }
2107 for _, f := range files {
2108 fmt.Fprintf(h, "file %s ", f.Name())
2109 finfo, err := f.Info()
2110 if err != nil {
2111 fmt.Fprintf(h, "err %v\n", err)
2112 } else {
2113 hashWriteStat(h, finfo)
2114 }
2115 }
2116 } else if info.Mode().IsRegular() {
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126 if time.Since(info.ModTime()) < modTimeCutoff {
2127 return cache.ActionID{}, errFileTooNew
2128 }
2129 }
2130 return h.Sum(), nil
2131 }
2132
2133 func hashStat(name string) cache.ActionID {
2134 h := cache.NewHash("stat")
2135 if info, err := os.Stat(name); err != nil {
2136 fmt.Fprintf(h, "err %v\n", err)
2137 } else {
2138 hashWriteStat(h, info)
2139 }
2140 if info, err := os.Lstat(name); err != nil {
2141 fmt.Fprintf(h, "err %v\n", err)
2142 } else {
2143 hashWriteStat(h, info)
2144 }
2145 return h.Sum()
2146 }
2147
2148 func hashWriteStat(h io.Writer, info fs.FileInfo) {
2149 fmt.Fprintf(h, "stat %d %x %v %v\n", info.Size(), uint64(info.Mode()), info.ModTime(), info.IsDir())
2150 }
2151
2152
2153 func testAndInputKey(testID, testInputsID cache.ActionID) cache.ActionID {
2154 return cache.Subkey(testID, fmt.Sprintf("inputs:%x", testInputsID))
2155 }
2156
2157
2158
2159
2160 func coverProfileAndInputKey(testID, testInputsID, covMetaID cache.ActionID) cache.ActionID {
2161 key := testAndInputKey(testID, testInputsID)
2162 if covMetaID != (cache.ActionID{}) {
2163 key = cache.Subkey(key, fmt.Sprintf("coverdeps:%x", covMetaID))
2164 }
2165 return cache.Subkey(key, "coverprofile")
2166 }
2167
2168 func (c *runCache) saveOutput(a *work.Action) {
2169 if c.id1 == (cache.ActionID{}) && c.id2 == (cache.ActionID{}) {
2170 return
2171 }
2172
2173
2174 testlog, err := os.ReadFile(a.Objdir + "testlog.txt")
2175 if err != nil || !bytes.HasPrefix(testlog, testlogMagic) || testlog[len(testlog)-1] != '\n' {
2176 if cache.DebugTest {
2177 if err != nil {
2178 fmt.Fprintf(os.Stderr, "testcache: %s: reading testlog: %v\n", a.Package.ImportPath, err)
2179 } else {
2180 fmt.Fprintf(os.Stderr, "testcache: %s: reading testlog: malformed\n", a.Package.ImportPath)
2181 }
2182 }
2183 return
2184 }
2185 testInputsID, err := computeTestInputsID(a, testlog)
2186 if err != nil {
2187 return
2188 }
2189 var coverProfile []byte
2190 if testCoverProfile != "" {
2191 coverProfile, err = os.ReadFile(coverProfTempFile(a))
2192 if err != nil {
2193 if cache.DebugTest {
2194 fmt.Fprintf(os.Stderr, "testcache: %s: reading cover profile: %v\n", a.Package.ImportPath, err)
2195 }
2196 return
2197 }
2198 }
2199 if c.id1 != (cache.ActionID{}) {
2200 if cache.DebugTest {
2201 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))
2202 }
2203 cache.PutNoVerify(cache.Default(), c.id1, bytes.NewReader(testlog))
2204 cache.PutNoVerify(cache.Default(), testAndInputKey(c.id1, testInputsID), bytes.NewReader(a.TestOutput.Bytes()))
2205 if coverProfile != nil {
2206 cache.PutNoVerify(cache.Default(), coverProfileAndInputKey(c.id1, testInputsID, c.covMeta), bytes.NewReader(coverProfile))
2207 } else if c.covMeta != (cache.ActionID{}) {
2208
2209
2210 cache.PutNoVerify(cache.Default(), coverProfileAndInputKey(c.id1, testInputsID, c.covMeta), bytes.NewReader(nil))
2211 }
2212 }
2213 if c.id2 != (cache.ActionID{}) {
2214 if cache.DebugTest {
2215 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))
2216 }
2217 cache.PutNoVerify(cache.Default(), c.id2, bytes.NewReader(testlog))
2218 cache.PutNoVerify(cache.Default(), testAndInputKey(c.id2, testInputsID), bytes.NewReader(a.TestOutput.Bytes()))
2219 if coverProfile != nil {
2220 cache.PutNoVerify(cache.Default(), coverProfileAndInputKey(c.id2, testInputsID, c.covMeta), bytes.NewReader(coverProfile))
2221 } else if c.covMeta != (cache.ActionID{}) {
2222
2223 cache.PutNoVerify(cache.Default(), coverProfileAndInputKey(c.id2, testInputsID, c.covMeta), bytes.NewReader(nil))
2224 }
2225 }
2226 }
2227
2228
2229
2230 func coveragePercentage(out []byte) string {
2231 if !cfg.BuildCover {
2232 return ""
2233 }
2234
2235
2236
2237 re := regexp.MustCompile(`coverage: (.*)\n`)
2238 matches := re.FindSubmatch(out)
2239 if matches == nil {
2240
2241
2242 return ""
2243 }
2244 return fmt.Sprintf("\tcoverage: %s", matches[1])
2245 }
2246
2247
2248 func builderCleanTest(b *work.Builder, ctx context.Context, a *work.Action) error {
2249 if cfg.BuildWork {
2250 return nil
2251 }
2252 b.Shell(a).RemoveAll(a.Objdir)
2253 return nil
2254 }
2255
2256
2257 func builderPrintTest(b *work.Builder, ctx context.Context, a *work.Action) error {
2258 run := a.Deps[0]
2259 if run.Mode == "test clean" {
2260 run = run.Deps[0]
2261 }
2262 if run.Mode != "test run" {
2263 base.Fatalf("internal error: cannot find test run to print")
2264 }
2265 if run.TestOutput != nil {
2266 os.Stdout.Write(run.TestOutput.Bytes())
2267 run.TestOutput = nil
2268 }
2269 return nil
2270 }
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287 func printExitStatus(b *work.Builder, ctx context.Context, a *work.Action) error {
2288 if !testJSON && testFuzz == "" && len(pkgArgs) != 0 {
2289 if base.GetExitStatus() != 0 {
2290 fmt.Println("FAIL")
2291 return nil
2292 }
2293 }
2294 return nil
2295 }
2296
2297
2298
2299
2300
2301
2302 func testBinaryName(p *load.Package) string {
2303 var elem string
2304 if p.ImportPath == "command-line-arguments" {
2305 elem = p.Name
2306 } else {
2307 elem = p.DefaultExecName()
2308 }
2309
2310 return elem + ".test"
2311 }
2312
View as plain text