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