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