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