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 --alloc_space, --alloc_objects, and --show_bytes
190 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 for _, p := range pkgs {
996 reportErr := func(perr *load.Package, err error) {
997 str := err.Error()
998 if p.ImportPath != "" {
999 load.DefaultPrinter().Errorf(perr, "# %s\n%s", p.ImportPath, str)
1000 } else {
1001 load.DefaultPrinter().Errorf(perr, "%s", str)
1002 }
1003 }
1004 reportSetupFailed := func(perr *load.Package, err error) {
1005 var stdout io.Writer = os.Stdout
1006 if testJSON {
1007 json := test2json.NewConverter(stdout, p.ImportPath, test2json.Timestamp)
1008 defer func() {
1009 json.Exited(err)
1010 json.Close()
1011 }()
1012 if gotestjsonbuildtext.Value() == "1" {
1013
1014
1015 gotestjsonbuildtext.IncNonDefault()
1016 } else {
1017 json.SetFailedBuild(perr.Desc())
1018 }
1019 stdout = json
1020 }
1021 fmt.Fprintf(stdout, "FAIL\t%s [setup failed]\n", p.ImportPath)
1022 base.SetExitStatus(1)
1023 }
1024
1025 var firstErrPkg *load.Package
1026 load.PackageErrors([]*load.Package{p}, func(p *load.Package) {
1027 reportErr(p, p.Error)
1028 if firstErrPkg == nil {
1029 firstErrPkg = p
1030 }
1031 })
1032 if firstErrPkg != nil {
1033 reportSetupFailed(firstErrPkg, firstErrPkg.Error)
1034 continue
1035 }
1036 buildTest, runTest, printTest, perr, err := builderTest(b, ctx, pkgOpts, p, allImports[p], writeCoverMetaAct)
1037 if err != nil {
1038 reportErr(perr, err)
1039 reportSetupFailed(perr, err)
1040 continue
1041 }
1042 builds = append(builds, buildTest)
1043 runs = append(runs, runTest)
1044 prints = append(prints, printTest)
1045 }
1046
1047
1048 ch := make(chan struct{})
1049 close(ch)
1050 for _, a := range runs {
1051 if r, ok := a.Actor.(*runTestActor); ok {
1052 r.prev = ch
1053 ch = make(chan struct{})
1054 r.next = ch
1055 }
1056 }
1057
1058
1059 root := &work.Action{Mode: "go test", Actor: work.ActorFunc(printExitStatus), Deps: prints}
1060
1061
1062
1063 for i, a := range prints {
1064 if i > 0 {
1065 a.Deps = append(a.Deps, prints[i-1])
1066 }
1067 }
1068
1069
1070 if !testC && (testBench != "") {
1071
1072
1073 for i, run := range runs {
1074 if i == 0 {
1075 run.Deps = append(run.Deps, builds...)
1076 } else {
1077 run.Deps = append(run.Deps, prints[i-1])
1078 }
1079 }
1080 }
1081
1082 b.Do(ctx, root)
1083 }
1084
1085 var windowsBadWords = []string{
1086 "install",
1087 "patch",
1088 "setup",
1089 "update",
1090 }
1091
1092 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) {
1093 if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
1094 if cfg.BuildCover {
1095 if p.Internal.Cover.GenMeta {
1096 p.Internal.Cover.Mode = cfg.BuildCoverMode
1097 }
1098 }
1099 build := b.CompileAction(work.ModeBuild, work.ModeBuild, p)
1100 run := &work.Action{
1101 Mode: "test run",
1102 Actor: new(runTestActor),
1103 Deps: []*work.Action{build},
1104 Objdir: b.NewObjdir(),
1105 Package: p,
1106 IgnoreFail: true,
1107 }
1108 if writeCoverMetaAct != nil && build.Actor != nil {
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122 run.Deps = append(run.Deps, writeCoverMetaAct)
1123 writeCoverMetaAct.Deps = append(writeCoverMetaAct.Deps, build)
1124 }
1125 addTestVet(b, p, run, nil)
1126 print := &work.Action{
1127 Mode: "test print",
1128 Actor: work.ActorFunc(builderPrintTest),
1129 Deps: []*work.Action{run},
1130 Package: p,
1131 IgnoreFail: true,
1132 }
1133 return build, run, print, nil, nil
1134 }
1135
1136
1137
1138
1139
1140 var cover *load.TestCover
1141 if cfg.BuildCover {
1142 cover = &load.TestCover{
1143 Mode: cfg.BuildCoverMode,
1144 Local: cfg.BuildCoverPkg == nil,
1145 Pkgs: testCoverPkgs,
1146 Paths: cfg.BuildCoverPkg,
1147 }
1148 }
1149 pmain, ptest, pxtest, perr := load.TestPackagesFor(ctx, pkgOpts, p, cover)
1150 if perr != nil {
1151 return nil, nil, nil, perr, perr.Error
1152 }
1153
1154
1155
1156
1157
1158 if imported && ptest != p {
1159 buildTest := b.CompileAction(work.ModeBuild, work.ModeBuild, ptest)
1160 buildP := b.CompileAction(work.ModeBuild, work.ModeBuild, p)
1161 buildTest.Deps = append(buildTest.Deps, buildP)
1162 }
1163
1164 testBinary := testBinaryName(p)
1165
1166 testDir := b.NewObjdir()
1167 if err := b.BackgroundShell().Mkdir(testDir); err != nil {
1168 return nil, nil, nil, nil, err
1169 }
1170
1171 pmain.Dir = testDir
1172 pmain.Internal.OmitDebug = !testC && !testNeedBinary()
1173 if pmain.ImportPath == "runtime.test" {
1174
1175
1176 pmain.Internal.OmitDebug = false
1177 }
1178
1179 if !cfg.BuildN {
1180
1181
1182 if err := os.WriteFile(testDir+"_testmain.go", *pmain.Internal.TestmainGo, 0666); err != nil {
1183 return nil, nil, nil, nil, err
1184 }
1185 }
1186
1187
1188
1189 b.CompileAction(work.ModeBuild, work.ModeBuild, pmain).Objdir = testDir
1190
1191 a := b.LinkAction(work.ModeBuild, work.ModeBuild, pmain)
1192 a.Target = testDir + testBinary + cfg.ExeSuffix
1193 if cfg.Goos == "windows" {
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216 for _, bad := range windowsBadWords {
1217 if strings.Contains(testBinary, bad) {
1218 a.Target = testDir + "test.test" + cfg.ExeSuffix
1219 break
1220 }
1221 }
1222 }
1223 buildAction = a
1224 var installAction, cleanAction *work.Action
1225 if testC || testNeedBinary() {
1226
1227 target := filepath.Join(base.Cwd(), testBinary+cfg.ExeSuffix)
1228 isNull := false
1229
1230 if testO != "" {
1231 target = testO
1232
1233 if testODir {
1234 if filepath.IsAbs(target) {
1235 target = filepath.Join(target, testBinary+cfg.ExeSuffix)
1236 } else {
1237 target = filepath.Join(base.Cwd(), target, testBinary+cfg.ExeSuffix)
1238 }
1239 } else {
1240 if base.IsNull(target) {
1241 isNull = true
1242 } else if !filepath.IsAbs(target) {
1243 target = filepath.Join(base.Cwd(), target)
1244 }
1245 }
1246 }
1247
1248 if isNull {
1249 runAction = buildAction
1250 } else {
1251 pmain.Target = target
1252 installAction = &work.Action{
1253 Mode: "test build",
1254 Actor: work.ActorFunc(work.BuildInstallFunc),
1255 Deps: []*work.Action{buildAction},
1256 Package: pmain,
1257 Target: target,
1258 }
1259 runAction = installAction
1260 }
1261 }
1262
1263 var vetRunAction *work.Action
1264 if testC {
1265 printAction = &work.Action{Mode: "test print (nop)", Package: p, Deps: []*work.Action{runAction}}
1266 vetRunAction = printAction
1267 } else {
1268
1269 rta := &runTestActor{
1270 writeCoverMetaAct: writeCoverMetaAct,
1271 }
1272 runAction = &work.Action{
1273 Mode: "test run",
1274 Actor: rta,
1275 Deps: []*work.Action{buildAction},
1276 Package: p,
1277 IgnoreFail: true,
1278 TryCache: rta.c.tryCache,
1279 }
1280 if writeCoverMetaAct != nil {
1281
1282
1283
1284
1285
1286 runAction.Deps = append(runAction.Deps, writeCoverMetaAct)
1287 if !p.IsTestOnly() {
1288
1289
1290
1291
1292
1293 compileAction := b.CompileAction(work.ModeBuild, work.ModeBuild, p)
1294 writeCoverMetaAct.Deps = append(writeCoverMetaAct.Deps, compileAction)
1295 }
1296 }
1297 runAction.Objdir = testDir
1298 vetRunAction = runAction
1299 cleanAction = &work.Action{
1300 Mode: "test clean",
1301 Actor: work.ActorFunc(builderCleanTest),
1302 Deps: []*work.Action{runAction},
1303 Package: p,
1304 IgnoreFail: true,
1305 Objdir: testDir,
1306 }
1307 printAction = &work.Action{
1308 Mode: "test print",
1309 Actor: work.ActorFunc(builderPrintTest),
1310 Deps: []*work.Action{cleanAction},
1311 Package: p,
1312 IgnoreFail: true,
1313 }
1314 }
1315
1316 if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
1317 addTestVet(b, ptest, vetRunAction, installAction)
1318 }
1319 if pxtest != nil {
1320 addTestVet(b, pxtest, vetRunAction, installAction)
1321 }
1322
1323 if installAction != nil {
1324 if runAction != installAction {
1325 installAction.Deps = append(installAction.Deps, runAction)
1326 }
1327 if cleanAction != nil {
1328 cleanAction.Deps = append(cleanAction.Deps, installAction)
1329 }
1330 }
1331
1332 return buildAction, runAction, printAction, nil, nil
1333 }
1334
1335 func addTestVet(b *work.Builder, p *load.Package, runAction, installAction *work.Action) {
1336 if testVet.off {
1337 return
1338 }
1339
1340 vet := b.VetAction(work.ModeBuild, work.ModeBuild, p)
1341 runAction.Deps = append(runAction.Deps, vet)
1342
1343
1344
1345
1346 if installAction != nil {
1347 installAction.Deps = append(installAction.Deps, vet)
1348 }
1349 }
1350
1351 var noTestsToRun = []byte("\ntesting: warning: no tests to run\n")
1352 var noFuzzTestsToFuzz = []byte("\ntesting: warning: no fuzz tests to fuzz\n")
1353 var tooManyFuzzTestsToFuzz = []byte("\ntesting: warning: -fuzz matches more than one fuzz test, won't fuzz\n")
1354
1355
1356 type runTestActor struct {
1357 c runCache
1358
1359
1360
1361
1362
1363 writeCoverMetaAct *work.Action
1364
1365
1366 prev <-chan struct{}
1367 next chan<- struct{}
1368 }
1369
1370
1371 type runCache struct {
1372 disableCache bool
1373
1374 buf *bytes.Buffer
1375 id1 cache.ActionID
1376 id2 cache.ActionID
1377 }
1378
1379 func coverProfTempFile(a *work.Action) string {
1380 if a.Objdir == "" {
1381 panic("internal error: objdir not set in coverProfTempFile")
1382 }
1383 return a.Objdir + "_cover_.out"
1384 }
1385
1386
1387
1388
1389
1390
1391 var stdoutMu sync.Mutex
1392
1393 type lockedStdout struct{}
1394
1395 func (lockedStdout) Write(b []byte) (int, error) {
1396 stdoutMu.Lock()
1397 defer stdoutMu.Unlock()
1398 return os.Stdout.Write(b)
1399 }
1400
1401 func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action) error {
1402 sh := b.Shell(a)
1403
1404
1405 select {
1406 case <-r.prev:
1407
1408 if testShouldFailFast.Load() {
1409 close(r.next)
1410 return nil
1411 }
1412 case <-base.Interrupted:
1413
1414
1415
1416 base.SetExitStatus(1)
1417 return nil
1418 }
1419
1420
1421
1422
1423 streamOutput := len(pkgArgs) == 0 || testBench != "" || testFuzz != ""
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439 streamAndCacheOutput := testShowPass() && (len(pkgs) == 1 || cfg.BuildP == 1) || testJSON
1440
1441 var stdout io.Writer = os.Stdout
1442 var err error
1443 var json *test2json.Converter
1444 if testJSON {
1445 json = test2json.NewConverter(lockedStdout{}, a.Package.ImportPath, test2json.Timestamp)
1446 defer func() {
1447 json.Exited(err)
1448 json.Close()
1449 }()
1450 stdout = json
1451 }
1452
1453 var buf bytes.Buffer
1454 if streamOutput {
1455
1456 } else if streamAndCacheOutput {
1457
1458
1459 stdout = io.MultiWriter(stdout, &buf)
1460 } else {
1461 stdout = &buf
1462 }
1463
1464
1465 close(r.next)
1466
1467 if a.Failed != nil {
1468
1469 if json != nil && a.Failed.Package != nil {
1470 if gotestjsonbuildtext.Value() == "1" {
1471 gotestjsonbuildtext.IncNonDefault()
1472 } else {
1473 json.SetFailedBuild(a.Failed.Package.Desc())
1474 }
1475 }
1476 a.Failed = nil
1477 fmt.Fprintf(stdout, "FAIL\t%s [build failed]\n", a.Package.ImportPath)
1478
1479 err = errors.New("build failed")
1480 base.SetExitStatus(1)
1481 if stdout == &buf {
1482 a.TestOutput = &buf
1483 }
1484 return nil
1485 }
1486
1487 if p := a.Package; len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
1488 reportNoTestFiles := true
1489 if cfg.BuildCover && p.Internal.Cover.GenMeta {
1490 if err := sh.Mkdir(a.Objdir); err != nil {
1491 return err
1492 }
1493 mf, err := work.BuildActionCoverMetaFile(a)
1494 if err != nil {
1495 return err
1496 } else if mf != "" {
1497 reportNoTestFiles = false
1498
1499 if err := work.WriteCoveragePercent(b, a, mf, stdout); err != nil {
1500 return err
1501 }
1502
1503
1504
1505 if coverMerge.f != nil {
1506 cp := coverProfTempFile(a)
1507 if err := work.WriteCoverageProfile(b, a, mf, cp, stdout); err != nil {
1508 return err
1509 }
1510 mergeCoverProfile(cp)
1511 }
1512 }
1513 }
1514 if reportNoTestFiles {
1515 fmt.Fprintf(stdout, "? \t%s\t[no test files]\n", p.ImportPath)
1516 }
1517 if stdout == &buf {
1518 a.TestOutput = &buf
1519 }
1520 return nil
1521 }
1522
1523 if r.c.buf == nil {
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533 r.c.tryCacheWithID(b, a, a.Deps[0].BuildContentID())
1534 }
1535 if r.c.buf != nil {
1536 if stdout != &buf {
1537 stdout.Write(r.c.buf.Bytes())
1538 r.c.buf.Reset()
1539 }
1540 a.TestOutput = r.c.buf
1541 return nil
1542 }
1543
1544 execCmd := work.FindExecCmd()
1545 testlogArg := []string{}
1546 if !r.c.disableCache && len(execCmd) == 0 {
1547 testlogArg = []string{"-test.testlogfile=" + a.Objdir + "testlog.txt"}
1548 }
1549 panicArg := "-test.paniconexit0"
1550 fuzzArg := []string{}
1551 if testFuzz != "" {
1552 fuzzCacheDir := filepath.Join(cache.Default().FuzzDir(), a.Package.ImportPath)
1553 fuzzArg = []string{"-test.fuzzcachedir=" + fuzzCacheDir}
1554 }
1555 coverdirArg := []string{}
1556 addToEnv := ""
1557 if cfg.BuildCover {
1558 gcd := filepath.Join(a.Objdir, "gocoverdir")
1559 if err := sh.Mkdir(gcd); err != nil {
1560
1561
1562
1563
1564
1565 base.Fatalf("failed to create temporary dir: %v", err)
1566 }
1567 coverdirArg = append(coverdirArg, "-test.gocoverdir="+gcd)
1568 if r.writeCoverMetaAct != nil {
1569
1570
1571
1572 src := r.writeCoverMetaAct.Objdir + coverage.MetaFilesFileName
1573 dst := filepath.Join(gcd, coverage.MetaFilesFileName)
1574 if err := sh.CopyFile(dst, src, 0666, false); err != nil {
1575 return err
1576 }
1577 }
1578
1579
1580
1581
1582 addToEnv = "GOCOVERDIR=" + gcd
1583 }
1584 args := str.StringList(execCmd, a.Deps[0].BuiltTarget(), testlogArg, panicArg, fuzzArg, coverdirArg, testArgs)
1585
1586 if testCoverProfile != "" {
1587
1588 for i, arg := range args {
1589 if strings.HasPrefix(arg, "-test.coverprofile=") {
1590 args[i] = "-test.coverprofile=" + coverProfTempFile(a)
1591 }
1592 }
1593 }
1594
1595 if cfg.BuildN || cfg.BuildX {
1596 sh.ShowCmd("", "%s", strings.Join(args, " "))
1597 if cfg.BuildN {
1598 return nil
1599 }
1600 }
1601
1602
1603
1604 ctx, cancel := context.WithTimeout(ctx, testKillTimeout)
1605 defer cancel()
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618 var (
1619 cmd *exec.Cmd
1620 t0 time.Time
1621 cancelKilled = false
1622 cancelSignaled = false
1623 )
1624 for {
1625 cmd = exec.CommandContext(ctx, args[0], args[1:]...)
1626 cmd.Dir = a.Package.Dir
1627
1628 env := slices.Clip(cfg.OrigEnv)
1629 env = base.AppendPATH(env)
1630 env = base.AppendPWD(env, cmd.Dir)
1631 cmd.Env = env
1632 if addToEnv != "" {
1633 cmd.Env = append(cmd.Env, addToEnv)
1634 }
1635
1636 cmd.Stdout = stdout
1637 cmd.Stderr = stdout
1638
1639 cmd.Cancel = func() error {
1640 if base.SignalTrace == nil {
1641 err := cmd.Process.Kill()
1642 if err == nil {
1643 cancelKilled = true
1644 }
1645 return err
1646 }
1647
1648
1649
1650 err := cmd.Process.Signal(base.SignalTrace)
1651 if err == nil {
1652 cancelSignaled = true
1653 }
1654 return err
1655 }
1656 cmd.WaitDelay = testWaitDelay
1657
1658 base.StartSigHandlers()
1659 t0 = time.Now()
1660 err = cmd.Run()
1661
1662 if !base.IsETXTBSY(err) {
1663
1664
1665 break
1666 }
1667 }
1668
1669 out := buf.Bytes()
1670 a.TestOutput = &buf
1671 t := fmt.Sprintf("%.3fs", time.Since(t0).Seconds())
1672
1673 mergeCoverProfile(coverProfTempFile(a))
1674
1675 if err == nil {
1676 norun := ""
1677 if !testShowPass() && !testJSON {
1678 buf.Reset()
1679 }
1680 if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) {
1681 norun = " [no tests to run]"
1682 }
1683 if bytes.HasPrefix(out, noFuzzTestsToFuzz[1:]) || bytes.Contains(out, noFuzzTestsToFuzz) {
1684 norun = " [no fuzz tests to fuzz]"
1685 }
1686 if bytes.HasPrefix(out, tooManyFuzzTestsToFuzz[1:]) || bytes.Contains(out, tooManyFuzzTestsToFuzz) {
1687 norun = "[-fuzz matches more than one fuzz test, won't fuzz]"
1688 }
1689 if len(out) > 0 && !bytes.HasSuffix(out, []byte("\n")) {
1690
1691
1692 cmd.Stdout.Write([]byte("\n"))
1693 }
1694 fmt.Fprintf(cmd.Stdout, "ok \t%s\t%s%s%s\n", a.Package.ImportPath, t, coveragePercentage(out), norun)
1695 r.c.saveOutput(a)
1696 } else {
1697 if testFailFast {
1698 testShouldFailFast.Store(true)
1699 }
1700
1701 base.SetExitStatus(1)
1702 if cancelSignaled {
1703 fmt.Fprintf(cmd.Stdout, "*** Test killed with %v: ran too long (%v).\n", base.SignalTrace, testKillTimeout)
1704 } else if cancelKilled {
1705 fmt.Fprintf(cmd.Stdout, "*** Test killed: ran too long (%v).\n", testKillTimeout)
1706 } else if errors.Is(err, exec.ErrWaitDelay) {
1707 fmt.Fprintf(cmd.Stdout, "*** Test I/O incomplete %v after exiting.\n", cmd.WaitDelay)
1708 }
1709 var ee *exec.ExitError
1710 if len(out) == 0 || !errors.As(err, &ee) || !ee.Exited() {
1711
1712
1713 fmt.Fprintf(cmd.Stdout, "%s\n", err)
1714 } else if !bytes.HasSuffix(out, []byte("\n")) {
1715
1716
1717 cmd.Stdout.Write([]byte("\n"))
1718 }
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728 prefix := ""
1729 if testJSON || testV.json {
1730 prefix = "\x16"
1731 }
1732 fmt.Fprintf(cmd.Stdout, "%sFAIL\t%s\t%s\n", prefix, a.Package.ImportPath, t)
1733 }
1734
1735 if cmd.Stdout != &buf {
1736 buf.Reset()
1737 }
1738 return nil
1739 }
1740
1741
1742
1743
1744 func (c *runCache) tryCache(b *work.Builder, a *work.Action) bool {
1745 return c.tryCacheWithID(b, a, a.Deps[0].BuildActionID())
1746 }
1747
1748 func (c *runCache) tryCacheWithID(b *work.Builder, a *work.Action, id string) bool {
1749 if len(pkgArgs) == 0 {
1750
1751
1752 if cache.DebugTest {
1753 fmt.Fprintf(os.Stderr, "testcache: caching disabled in local directory mode\n")
1754 }
1755 c.disableCache = true
1756 return false
1757 }
1758
1759 if a.Package.Root == "" {
1760
1761 if cache.DebugTest {
1762 fmt.Fprintf(os.Stderr, "testcache: caching disabled for package outside of module root, GOPATH, or GOROOT: %s\n", a.Package.ImportPath)
1763 }
1764 c.disableCache = true
1765 return false
1766 }
1767
1768 var cacheArgs []string
1769 for _, arg := range testArgs {
1770 i := strings.Index(arg, "=")
1771 if i < 0 || !strings.HasPrefix(arg, "-test.") {
1772 if cache.DebugTest {
1773 fmt.Fprintf(os.Stderr, "testcache: caching disabled for test argument: %s\n", arg)
1774 }
1775 c.disableCache = true
1776 return false
1777 }
1778 switch arg[:i] {
1779 case "-test.benchtime",
1780 "-test.cpu",
1781 "-test.list",
1782 "-test.parallel",
1783 "-test.run",
1784 "-test.short",
1785 "-test.skip",
1786 "-test.timeout",
1787 "-test.failfast",
1788 "-test.v",
1789 "-test.fullpath":
1790
1791
1792
1793 cacheArgs = append(cacheArgs, arg)
1794 case "-test.coverprofile",
1795 "-test.outputdir":
1796
1797
1798
1799 default:
1800
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 }
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834 h := cache.NewHash("testResult")
1835 fmt.Fprintf(h, "test binary %s args %q execcmd %q", id, cacheArgs, work.ExecCmd)
1836 testID := h.Sum()
1837 if c.id1 == (cache.ActionID{}) {
1838 c.id1 = testID
1839 } else {
1840 c.id2 = testID
1841 }
1842 if cache.DebugTest {
1843 fmt.Fprintf(os.Stderr, "testcache: %s: test ID %x => %x\n", a.Package.ImportPath, id, testID)
1844 }
1845
1846
1847
1848 data, entry, err := cache.GetBytes(cache.Default(), testID)
1849 if !bytes.HasPrefix(data, testlogMagic) || data[len(data)-1] != '\n' {
1850 if cache.DebugTest {
1851 if err != nil {
1852 fmt.Fprintf(os.Stderr, "testcache: %s: input list not found: %v\n", a.Package.ImportPath, err)
1853 } else {
1854 fmt.Fprintf(os.Stderr, "testcache: %s: input list malformed\n", a.Package.ImportPath)
1855 }
1856 }
1857 return false
1858 }
1859 testInputsID, err := computeTestInputsID(a, data)
1860 if err != nil {
1861 return false
1862 }
1863 if cache.DebugTest {
1864 fmt.Fprintf(os.Stderr, "testcache: %s: test ID %x => input ID %x => %x\n", a.Package.ImportPath, testID, testInputsID, testAndInputKey(testID, testInputsID))
1865 }
1866
1867
1868
1869 data, entry, err = cache.GetBytes(cache.Default(), testAndInputKey(testID, testInputsID))
1870
1871
1872 if testCoverProfile != "" {
1873
1874 cpData, _, err := cache.GetFile(cache.Default(), coverProfileAndInputKey(testID, testInputsID))
1875 if err != nil {
1876 if cache.DebugTest {
1877 fmt.Fprintf(os.Stderr, "testcache: %s: cached cover profile missing: %v\n", a.Package.ImportPath, err)
1878 }
1879 return false
1880 }
1881 mergeCoverProfile(cpData)
1882 }
1883
1884 if len(data) == 0 || data[len(data)-1] != '\n' {
1885 if cache.DebugTest {
1886 if err != nil {
1887 fmt.Fprintf(os.Stderr, "testcache: %s: test output not found: %v\n", a.Package.ImportPath, err)
1888 } else {
1889 fmt.Fprintf(os.Stderr, "testcache: %s: test output malformed\n", a.Package.ImportPath)
1890 }
1891 }
1892 return false
1893 }
1894 if entry.Time.Before(testCacheExpire) {
1895 if cache.DebugTest {
1896 fmt.Fprintf(os.Stderr, "testcache: %s: test output expired due to go clean -testcache\n", a.Package.ImportPath)
1897 }
1898 return false
1899 }
1900 i := bytes.LastIndexByte(data[:len(data)-1], '\n') + 1
1901 if !bytes.HasPrefix(data[i:], []byte("ok \t")) {
1902 if cache.DebugTest {
1903 fmt.Fprintf(os.Stderr, "testcache: %s: test output malformed\n", a.Package.ImportPath)
1904 }
1905 return false
1906 }
1907 j := bytes.IndexByte(data[i+len("ok \t"):], '\t')
1908 if j < 0 {
1909 if cache.DebugTest {
1910 fmt.Fprintf(os.Stderr, "testcache: %s: test output malformed\n", a.Package.ImportPath)
1911 }
1912 return false
1913 }
1914 j += i + len("ok \t") + 1
1915
1916
1917 c.buf = new(bytes.Buffer)
1918 c.buf.Write(data[:j])
1919 c.buf.WriteString("(cached)")
1920 for j < len(data) && ('0' <= data[j] && data[j] <= '9' || data[j] == '.' || data[j] == 's') {
1921 j++
1922 }
1923 c.buf.Write(data[j:])
1924 return true
1925 }
1926
1927 var errBadTestInputs = errors.New("error parsing test inputs")
1928 var testlogMagic = []byte("# test log\n")
1929
1930
1931
1932
1933 func computeTestInputsID(a *work.Action, testlog []byte) (cache.ActionID, error) {
1934 testlog = bytes.TrimPrefix(testlog, testlogMagic)
1935 h := cache.NewHash("testInputs")
1936
1937 fmt.Fprintf(h, "env GODEBUG %x\n", hashGetenv("GODEBUG"))
1938 pwd := a.Package.Dir
1939 for _, line := range bytes.Split(testlog, []byte("\n")) {
1940 if len(line) == 0 {
1941 continue
1942 }
1943 s := string(line)
1944 op, name, found := strings.Cut(s, " ")
1945 if !found {
1946 if cache.DebugTest {
1947 fmt.Fprintf(os.Stderr, "testcache: %s: input list malformed (%q)\n", a.Package.ImportPath, line)
1948 }
1949 return cache.ActionID{}, errBadTestInputs
1950 }
1951 switch op {
1952 default:
1953 if cache.DebugTest {
1954 fmt.Fprintf(os.Stderr, "testcache: %s: input list malformed (%q)\n", a.Package.ImportPath, line)
1955 }
1956 return cache.ActionID{}, errBadTestInputs
1957 case "getenv":
1958 fmt.Fprintf(h, "env %s %x\n", name, hashGetenv(name))
1959 case "chdir":
1960 pwd = name
1961 fmt.Fprintf(h, "chdir %s %x\n", name, hashStat(name))
1962 case "stat":
1963 if !filepath.IsAbs(name) {
1964 name = filepath.Join(pwd, name)
1965 }
1966 if a.Package.Root == "" || search.InDir(name, a.Package.Root) == "" {
1967
1968 break
1969 }
1970 fmt.Fprintf(h, "stat %s %x\n", name, hashStat(name))
1971 case "open":
1972 if !filepath.IsAbs(name) {
1973 name = filepath.Join(pwd, name)
1974 }
1975 if a.Package.Root == "" || search.InDir(name, a.Package.Root) == "" {
1976
1977 break
1978 }
1979 fh, err := hashOpen(name)
1980 if err != nil {
1981 if cache.DebugTest {
1982 fmt.Fprintf(os.Stderr, "testcache: %s: input file %s: %s\n", a.Package.ImportPath, name, err)
1983 }
1984 return cache.ActionID{}, err
1985 }
1986 fmt.Fprintf(h, "open %s %x\n", name, fh)
1987 }
1988 }
1989 sum := h.Sum()
1990 return sum, nil
1991 }
1992
1993 func hashGetenv(name string) cache.ActionID {
1994 h := cache.NewHash("getenv")
1995 v, ok := os.LookupEnv(name)
1996 if !ok {
1997 h.Write([]byte{0})
1998 } else {
1999 h.Write([]byte{1})
2000 h.Write([]byte(v))
2001 }
2002 return h.Sum()
2003 }
2004
2005 const modTimeCutoff = 2 * time.Second
2006
2007 var errFileTooNew = errors.New("file used as input is too new")
2008
2009 func hashOpen(name string) (cache.ActionID, error) {
2010 h := cache.NewHash("open")
2011 info, err := os.Stat(name)
2012 if err != nil {
2013 fmt.Fprintf(h, "err %v\n", err)
2014 return h.Sum(), nil
2015 }
2016 hashWriteStat(h, info)
2017 if info.IsDir() {
2018 files, err := os.ReadDir(name)
2019 if err != nil {
2020 fmt.Fprintf(h, "err %v\n", err)
2021 }
2022 for _, f := range files {
2023 fmt.Fprintf(h, "file %s ", f.Name())
2024 finfo, err := f.Info()
2025 if err != nil {
2026 fmt.Fprintf(h, "err %v\n", err)
2027 } else {
2028 hashWriteStat(h, finfo)
2029 }
2030 }
2031 } else if info.Mode().IsRegular() {
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041 if time.Since(info.ModTime()) < modTimeCutoff {
2042 return cache.ActionID{}, errFileTooNew
2043 }
2044 }
2045 return h.Sum(), nil
2046 }
2047
2048 func hashStat(name string) cache.ActionID {
2049 h := cache.NewHash("stat")
2050 if info, err := os.Stat(name); err != nil {
2051 fmt.Fprintf(h, "err %v\n", err)
2052 } else {
2053 hashWriteStat(h, info)
2054 }
2055 if info, err := os.Lstat(name); err != nil {
2056 fmt.Fprintf(h, "err %v\n", err)
2057 } else {
2058 hashWriteStat(h, info)
2059 }
2060 return h.Sum()
2061 }
2062
2063 func hashWriteStat(h io.Writer, info fs.FileInfo) {
2064 fmt.Fprintf(h, "stat %d %x %v %v\n", info.Size(), uint64(info.Mode()), info.ModTime(), info.IsDir())
2065 }
2066
2067
2068 func testAndInputKey(testID, testInputsID cache.ActionID) cache.ActionID {
2069 return cache.Subkey(testID, fmt.Sprintf("inputs:%x", testInputsID))
2070 }
2071
2072
2073 func coverProfileAndInputKey(testID, testInputsID cache.ActionID) cache.ActionID {
2074 return cache.Subkey(testAndInputKey(testID, testInputsID), "coverprofile")
2075 }
2076
2077 func (c *runCache) saveOutput(a *work.Action) {
2078 if c.id1 == (cache.ActionID{}) && c.id2 == (cache.ActionID{}) {
2079 return
2080 }
2081
2082
2083 testlog, err := os.ReadFile(a.Objdir + "testlog.txt")
2084 if err != nil || !bytes.HasPrefix(testlog, testlogMagic) || testlog[len(testlog)-1] != '\n' {
2085 if cache.DebugTest {
2086 if err != nil {
2087 fmt.Fprintf(os.Stderr, "testcache: %s: reading testlog: %v\n", a.Package.ImportPath, err)
2088 } else {
2089 fmt.Fprintf(os.Stderr, "testcache: %s: reading testlog: malformed\n", a.Package.ImportPath)
2090 }
2091 }
2092 return
2093 }
2094 testInputsID, err := computeTestInputsID(a, testlog)
2095 if err != nil {
2096 return
2097 }
2098 var coverProfile []byte
2099 if testCoverProfile != "" {
2100 coverProfile, err = os.ReadFile(coverProfTempFile(a))
2101 if err != nil {
2102 if cache.DebugTest {
2103 fmt.Fprintf(os.Stderr, "testcache: %s: reading cover profile: %v\n", a.Package.ImportPath, err)
2104 }
2105 return
2106 }
2107 }
2108 if c.id1 != (cache.ActionID{}) {
2109 if cache.DebugTest {
2110 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))
2111 }
2112 cache.PutNoVerify(cache.Default(), c.id1, bytes.NewReader(testlog))
2113 cache.PutNoVerify(cache.Default(), testAndInputKey(c.id1, testInputsID), bytes.NewReader(a.TestOutput.Bytes()))
2114 if coverProfile != nil {
2115 cache.PutNoVerify(cache.Default(), coverProfileAndInputKey(c.id1, testInputsID), bytes.NewReader(coverProfile))
2116 }
2117 }
2118 if c.id2 != (cache.ActionID{}) {
2119 if cache.DebugTest {
2120 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))
2121 }
2122 cache.PutNoVerify(cache.Default(), c.id2, bytes.NewReader(testlog))
2123 cache.PutNoVerify(cache.Default(), testAndInputKey(c.id2, testInputsID), bytes.NewReader(a.TestOutput.Bytes()))
2124 if coverProfile != nil {
2125 cache.PutNoVerify(cache.Default(), coverProfileAndInputKey(c.id2, testInputsID), bytes.NewReader(coverProfile))
2126 }
2127 }
2128 }
2129
2130
2131
2132 func coveragePercentage(out []byte) string {
2133 if !cfg.BuildCover {
2134 return ""
2135 }
2136
2137
2138
2139 re := regexp.MustCompile(`coverage: (.*)\n`)
2140 matches := re.FindSubmatch(out)
2141 if matches == nil {
2142
2143
2144 return ""
2145 }
2146 return fmt.Sprintf("\tcoverage: %s", matches[1])
2147 }
2148
2149
2150 func builderCleanTest(b *work.Builder, ctx context.Context, a *work.Action) error {
2151 if cfg.BuildWork {
2152 return nil
2153 }
2154 b.Shell(a).RemoveAll(a.Objdir)
2155 return nil
2156 }
2157
2158
2159 func builderPrintTest(b *work.Builder, ctx context.Context, a *work.Action) error {
2160 run := a.Deps[0]
2161 if run.Mode == "test clean" {
2162 run = run.Deps[0]
2163 }
2164 if run.Mode != "test run" {
2165 base.Fatalf("internal error: cannot find test run to print")
2166 }
2167 if run.TestOutput != nil {
2168 os.Stdout.Write(run.TestOutput.Bytes())
2169 run.TestOutput = nil
2170 }
2171 return nil
2172 }
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189 func printExitStatus(b *work.Builder, ctx context.Context, a *work.Action) error {
2190 if !testJSON && testFuzz == "" && len(pkgArgs) != 0 {
2191 if base.GetExitStatus() != 0 {
2192 fmt.Println("FAIL")
2193 return nil
2194 }
2195 }
2196 return nil
2197 }
2198
2199
2200
2201
2202
2203
2204 func testBinaryName(p *load.Package) string {
2205 var elem string
2206 if p.ImportPath == "command-line-arguments" {
2207 elem = p.Name
2208 } else {
2209 elem = p.DefaultExecName()
2210 }
2211
2212 return elem + ".test"
2213 }
2214
View as plain text