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