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