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