Source file src/pkg/cmd/dist/test.go
1
2
3
4
5 package main
6
7 import (
8 "bytes"
9 "flag"
10 "fmt"
11 "io/ioutil"
12 "log"
13 "os"
14 "os/exec"
15 "path"
16 "path/filepath"
17 "reflect"
18 "regexp"
19 "runtime"
20 "strconv"
21 "strings"
22 "sync"
23 "time"
24 )
25
26 func cmdtest() {
27 gogcflags = os.Getenv("GO_GCFLAGS")
28
29 var t tester
30 var noRebuild bool
31 flag.BoolVar(&t.listMode, "list", false, "list available tests")
32 flag.BoolVar(&t.rebuild, "rebuild", false, "rebuild everything first")
33 flag.BoolVar(&noRebuild, "no-rebuild", false, "overrides -rebuild (historical dreg)")
34 flag.BoolVar(&t.keepGoing, "k", false, "keep going even when error occurred")
35 flag.BoolVar(&t.race, "race", false, "run in race builder mode (different set of tests)")
36 flag.BoolVar(&t.compileOnly, "compile-only", false, "compile tests, but don't run them. This is for some builders. Not all dist tests respect this flag, but most do.")
37 flag.StringVar(&t.banner, "banner", "##### ", "banner prefix; blank means no section banners")
38 flag.StringVar(&t.runRxStr, "run", os.Getenv("GOTESTONLY"),
39 "run only those tests matching the regular expression; empty means to run all. "+
40 "Special exception: if the string begins with '!', the match is inverted.")
41 xflagparse(-1)
42 if noRebuild {
43 t.rebuild = false
44 }
45 t.run()
46 }
47
48
49 type tester struct {
50 race bool
51 listMode bool
52 rebuild bool
53 failed bool
54 keepGoing bool
55 compileOnly bool
56 runRxStr string
57 runRx *regexp.Regexp
58 runRxWant bool
59 runNames []string
60 banner string
61 lastHeading string
62
63 cgoEnabled bool
64 partial bool
65 haveTime bool
66
67 tests []distTest
68 timeoutScale int
69
70 worklist []*work
71 }
72
73 type work struct {
74 dt *distTest
75 cmd *exec.Cmd
76 start chan bool
77 out []byte
78 err error
79 end chan bool
80 }
81
82
83
84 type distTest struct {
85 name string
86 heading string
87 fn func(*distTest) error
88 }
89
90 func (t *tester) run() {
91 timelog("start", "dist test")
92
93 var exeSuffix string
94 if goos == "windows" {
95 exeSuffix = ".exe"
96 }
97 if _, err := os.Stat(filepath.Join(gobin, "go"+exeSuffix)); err == nil {
98 os.Setenv("PATH", fmt.Sprintf("%s%c%s", gobin, os.PathListSeparator, os.Getenv("PATH")))
99 }
100
101 slurp, err := exec.Command("go", "env", "CGO_ENABLED").Output()
102 if err != nil {
103 log.Fatalf("Error running go env CGO_ENABLED: %v", err)
104 }
105 t.cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(slurp)))
106 if flag.NArg() > 0 && t.runRxStr != "" {
107 log.Fatalf("the -run regular expression flag is mutually exclusive with test name arguments")
108 }
109
110 t.runNames = flag.Args()
111
112 if t.hasBash() {
113 if _, err := exec.LookPath("time"); err == nil {
114 t.haveTime = true
115 }
116 }
117
118 if t.rebuild {
119 t.out("Building packages and commands.")
120
121 goInstall("go", append([]string{"-a", "-i"}, toolchain...)...)
122 }
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140 if !t.listMode && os.Getenv("GO_BUILDER_NAME") == "" {
141 goInstall("go", append([]string{"-i"}, toolchain...)...)
142 goInstall("go", append([]string{"-i"}, toolchain...)...)
143 goInstall("go", "std", "cmd")
144 checkNotStale("go", "std", "cmd")
145 }
146
147 t.timeoutScale = 1
148 switch goarch {
149 case "arm":
150 t.timeoutScale = 2
151 case "mips", "mipsle", "mips64", "mips64le":
152 t.timeoutScale = 4
153 }
154 if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
155 t.timeoutScale, err = strconv.Atoi(s)
156 if err != nil {
157 log.Fatalf("failed to parse $GO_TEST_TIMEOUT_SCALE = %q as integer: %v", s, err)
158 }
159 }
160
161 if t.runRxStr != "" {
162 if t.runRxStr[0] == '!' {
163 t.runRxWant = false
164 t.runRxStr = t.runRxStr[1:]
165 } else {
166 t.runRxWant = true
167 }
168 t.runRx = regexp.MustCompile(t.runRxStr)
169 }
170
171 t.registerTests()
172 if t.listMode {
173 for _, tt := range t.tests {
174 fmt.Println(tt.name)
175 }
176 return
177 }
178
179
180
181
182
183
184
185 os.Setenv("GOROOT_FINAL_OLD", os.Getenv("GOROOT_FINAL"))
186 os.Unsetenv("GOROOT_FINAL")
187
188 for _, name := range t.runNames {
189 if !t.isRegisteredTestName(name) {
190 log.Fatalf("unknown test %q", name)
191 }
192 }
193
194
195 if strings.HasPrefix(os.Getenv("GO_BUILDER_NAME"), "linux-") {
196 t.makeGOROOTUnwritable()
197 }
198
199 for _, dt := range t.tests {
200 if !t.shouldRunTest(dt.name) {
201 t.partial = true
202 continue
203 }
204 dt := dt
205 if err := dt.fn(&dt); err != nil {
206 t.runPending(&dt)
207 t.failed = true
208 if t.keepGoing {
209 log.Printf("Failed: %v", err)
210 } else {
211 log.Fatalf("Failed: %v", err)
212 }
213 }
214 }
215 t.runPending(nil)
216 timelog("end", "dist test")
217 if t.failed {
218 fmt.Println("\nFAILED")
219 os.Exit(1)
220 } else if incomplete[goos+"/"+goarch] {
221 fmt.Println("\nFAILED (incomplete port)")
222 os.Exit(1)
223 } else if t.partial {
224 fmt.Println("\nALL TESTS PASSED (some were excluded)")
225 } else {
226 fmt.Println("\nALL TESTS PASSED")
227 }
228 }
229
230 func (t *tester) shouldRunTest(name string) bool {
231 if t.runRx != nil {
232 return t.runRx.MatchString(name) == t.runRxWant
233 }
234 if len(t.runNames) == 0 {
235 return true
236 }
237 for _, runName := range t.runNames {
238 if runName == name {
239 return true
240 }
241 }
242 return false
243 }
244
245
246
247
248
249
250
251
252 func short() string {
253 if v := os.Getenv("GO_TEST_SHORT"); v != "" {
254 short, err := strconv.ParseBool(v)
255 if err != nil {
256 log.Fatalf("invalid GO_TEST_SHORT %q: %v", v, err)
257 }
258 if !short {
259 return "-short=false"
260 }
261 }
262 return "-short"
263 }
264
265
266
267
268 func (t *tester) goTest() []string {
269 return []string{
270 "go", "test", short(), "-count=1", t.tags(), t.runFlag(""),
271 }
272 }
273
274 func (t *tester) tags() string {
275 if t.iOS() {
276 return "-tags=lldb"
277 }
278 return "-tags="
279 }
280
281
282
283 func (t *tester) timeoutDuration(sec int) time.Duration {
284 return time.Duration(sec) * time.Second * time.Duration(t.timeoutScale)
285 }
286
287
288
289
290 func (t *tester) timeout(sec int) string {
291 return "-timeout=" + t.timeoutDuration(sec).String()
292 }
293
294
295
296
297
298
299
300 var (
301 ranGoTest bool
302 stdMatches []string
303
304 ranGoBench bool
305 benchMatches []string
306 )
307
308 func (t *tester) registerStdTest(pkg string) {
309 testName := "go_test:" + pkg
310 if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant {
311 stdMatches = append(stdMatches, pkg)
312 }
313 t.tests = append(t.tests, distTest{
314 name: testName,
315 heading: "Testing packages.",
316 fn: func(dt *distTest) error {
317 if ranGoTest {
318 return nil
319 }
320 t.runPending(dt)
321 timelog("start", dt.name)
322 defer timelog("end", dt.name)
323 ranGoTest = true
324
325 timeoutSec := 180
326 for _, pkg := range stdMatches {
327 if pkg == "cmd/go" {
328 timeoutSec *= 3
329 break
330 }
331 }
332
333
334 if t.shouldUsePrecompiledStdTest() {
335 return t.runPrecompiledStdTest(t.timeoutDuration(timeoutSec))
336 }
337 args := []string{
338 "test",
339 short(),
340 t.tags(),
341 t.timeout(timeoutSec),
342 "-gcflags=all=" + gogcflags,
343 }
344 if t.race {
345 args = append(args, "-race")
346 }
347 if t.compileOnly {
348 args = append(args, "-run=^$")
349 }
350 args = append(args, stdMatches...)
351 cmd := exec.Command("go", args...)
352 cmd.Stdout = os.Stdout
353 cmd.Stderr = os.Stderr
354 return cmd.Run()
355 },
356 })
357 }
358
359 func (t *tester) registerRaceBenchTest(pkg string) {
360 testName := "go_test_bench:" + pkg
361 if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant {
362 benchMatches = append(benchMatches, pkg)
363 }
364 t.tests = append(t.tests, distTest{
365 name: testName,
366 heading: "Running benchmarks briefly.",
367 fn: func(dt *distTest) error {
368 if ranGoBench {
369 return nil
370 }
371 t.runPending(dt)
372 timelog("start", dt.name)
373 defer timelog("end", dt.name)
374 ranGoBench = true
375 args := []string{
376 "test",
377 short(),
378 "-race",
379 t.timeout(1200),
380 "-run=^$",
381 "-benchtime=.1s",
382 "-cpu=4",
383 }
384 if !t.compileOnly {
385 args = append(args, "-bench=.*")
386 }
387 args = append(args, benchMatches...)
388 cmd := exec.Command("go", args...)
389 cmd.Stdout = os.Stdout
390 cmd.Stderr = os.Stderr
391 return cmd.Run()
392 },
393 })
394 }
395
396
397
398 var stdOutErrAreTerminals func() bool
399
400 func (t *tester) registerTests() {
401
402
403
404 if len(t.runNames) > 0 {
405 for _, name := range t.runNames {
406 if strings.HasPrefix(name, "go_test:") {
407 t.registerStdTest(strings.TrimPrefix(name, "go_test:"))
408 }
409 if strings.HasPrefix(name, "go_test_bench:") {
410 t.registerRaceBenchTest(strings.TrimPrefix(name, "go_test_bench:"))
411 }
412 }
413 } else {
414
415 const format = "{{if (or .TestGoFiles .XTestGoFiles)}}{{.ImportPath}}{{end}}"
416 cmd := exec.Command("go", "list", "-f", format)
417 if t.race {
418 cmd.Args = append(cmd.Args, "-tags=race")
419 }
420 cmd.Args = append(cmd.Args, "std")
421 if !t.race {
422 cmd.Args = append(cmd.Args, "cmd")
423 }
424 cmd.Stderr = new(bytes.Buffer)
425 all, err := cmd.Output()
426 if err != nil {
427 log.Fatalf("Error running go list std cmd: %v:\n%s", err, cmd.Stderr)
428 }
429 pkgs := strings.Fields(string(all))
430 for _, pkg := range pkgs {
431 t.registerStdTest(pkg)
432 }
433 if t.race {
434 for _, pkg := range pkgs {
435 if t.packageHasBenchmarks(pkg) {
436 t.registerRaceBenchTest(pkg)
437 }
438 }
439 }
440 }
441
442
443 if !t.compileOnly {
444 t.tests = append(t.tests, distTest{
445 name: "osusergo",
446 heading: "os/user with tag osusergo",
447 fn: func(dt *distTest) error {
448 t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-tags=osusergo", "os/user")
449 return nil
450 },
451 })
452 }
453
454 if t.race {
455 return
456 }
457
458
459 if !t.compileOnly && goos != "js" {
460 testName := "runtime:cpu124"
461 t.tests = append(t.tests, distTest{
462 name: testName,
463 heading: "GOMAXPROCS=2 runtime -cpu=1,2,4 -quick",
464 fn: func(dt *distTest) error {
465 cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(300), "runtime", "-cpu=1,2,4", "-quick")
466
467
468 cmd.Env = append(os.Environ(), "GOMAXPROCS=2")
469 return nil
470 },
471 })
472 }
473
474
475
476 if goos == "linux" {
477 t.tests = append(t.tests, distTest{
478 name: "cmd_go_test_terminal",
479 heading: "cmd/go terminal test",
480 fn: func(dt *distTest) error {
481 t.runPending(dt)
482 timelog("start", dt.name)
483 defer timelog("end", dt.name)
484 if !stdOutErrAreTerminals() {
485 fmt.Println("skipping terminal test; stdout/stderr not terminals")
486 return nil
487 }
488 cmd := exec.Command("go", "test")
489 cmd.Dir = filepath.Join(os.Getenv("GOROOT"), "src/cmd/go/testdata/testterminal18153")
490 cmd.Stdout = os.Stdout
491 cmd.Stderr = os.Stderr
492 return cmd.Run()
493 },
494 })
495 }
496
497
498
499
500
501
502 if os.Getenv("GO_BUILDER_NAME") != "" && goos != "android" && !t.iOS() && goos != "plan9" && goos != "js" {
503 t.tests = append(t.tests, distTest{
504 name: "moved_goroot",
505 heading: "moved GOROOT",
506 fn: func(dt *distTest) error {
507 t.runPending(dt)
508 timelog("start", dt.name)
509 defer timelog("end", dt.name)
510 moved := goroot + "-moved"
511 if err := os.Rename(goroot, moved); err != nil {
512 if goos == "windows" {
513
514
515
516
517
518
519
520 log.Printf("skipping test on Windows")
521 return nil
522 }
523 return err
524 }
525
526
527 cmd := exec.Command(filepath.Join(moved, "bin", "go"), "test", "fmt")
528 cmd.Stdout = os.Stdout
529 cmd.Stderr = os.Stderr
530
531 for _, e := range os.Environ() {
532 if !strings.HasPrefix(e, "GOROOT=") && !strings.HasPrefix(e, "GOCACHE=") {
533 cmd.Env = append(cmd.Env, e)
534 }
535 }
536 err := cmd.Run()
537
538 if rerr := os.Rename(moved, goroot); rerr != nil {
539 log.Fatalf("failed to restore GOROOT: %v", rerr)
540 }
541 return err
542 },
543 })
544 }
545
546
547
548
549
550 for _, pkg := range cgoPackages {
551 if !t.internalLink() {
552 break
553 }
554
555
556 if goarch == "arm" {
557 break
558 }
559
560 pkg := pkg
561 var run string
562 if pkg == "net" {
563 run = "TestTCPStress"
564 }
565 t.tests = append(t.tests, distTest{
566 name: "nolibgcc:" + pkg,
567 heading: "Testing without libgcc.",
568 fn: func(dt *distTest) error {
569
570
571 t.addCmd(dt, "src", t.goTest(), "-ldflags=-linkmode=internal -libgcc=none", "-run=^Test[^CS]", pkg, t.runFlag(run))
572 return nil
573 },
574 })
575 }
576
577
578 if goos == "linux" && (goarch == "amd64" || goarch == "arm64") {
579 t.tests = append(t.tests, distTest{
580 name: "pie_internal",
581 heading: "internal linking of -buildmode=pie",
582 fn: func(dt *distTest) error {
583 t.addCmd(dt, "src", t.goTest(), "reflect", "-buildmode=pie", "-ldflags=-linkmode=internal", t.timeout(60))
584 return nil
585 },
586 })
587
588 if t.cgoEnabled {
589 t.tests = append(t.tests, distTest{
590 name: "pie_internal_cgo",
591 heading: "internal linking of -buildmode=pie",
592 fn: func(dt *distTest) error {
593 t.addCmd(dt, "src", t.goTest(), "os/user", "-buildmode=pie", "-ldflags=-linkmode=internal", t.timeout(60))
594 return nil
595 },
596 })
597 }
598 }
599
600
601 if goos != "js" {
602 t.tests = append(t.tests, distTest{
603 name: "sync_cpu",
604 heading: "sync -cpu=10",
605 fn: func(dt *distTest) error {
606 t.addCmd(dt, "src", t.goTest(), "sync", t.timeout(120), "-cpu=10", t.runFlag(""))
607 return nil
608 },
609 })
610 }
611
612 if t.raceDetectorSupported() {
613 t.tests = append(t.tests, distTest{
614 name: "race",
615 heading: "Testing race detector",
616 fn: t.raceTest,
617 })
618 }
619
620 if t.cgoEnabled && !t.iOS() {
621
622 t.registerHostTest("cgo_stdio", "../misc/cgo/stdio", "misc/cgo/stdio", ".")
623 t.registerHostTest("cgo_life", "../misc/cgo/life", "misc/cgo/life", ".")
624 fortran := os.Getenv("FC")
625 if fortran == "" {
626 fortran, _ = exec.LookPath("gfortran")
627 }
628 if t.hasBash() && goos != "android" && fortran != "" {
629 t.tests = append(t.tests, distTest{
630 name: "cgo_fortran",
631 heading: "../misc/cgo/fortran",
632 fn: func(dt *distTest) error {
633 t.addCmd(dt, "misc/cgo/fortran", "./test.bash", fortran)
634 return nil
635 },
636 })
637 }
638 if t.hasSwig() && goos != "android" {
639 t.tests = append(t.tests, distTest{
640 name: "swig_stdio",
641 heading: "../misc/swig/stdio",
642 fn: func(dt *distTest) error {
643 t.addCmd(dt, "misc/swig/stdio", t.goTest())
644 return nil
645 },
646 })
647 if t.hasCxx() {
648 t.tests = append(t.tests, distTest{
649 name: "swig_callback",
650 heading: "../misc/swig/callback",
651 fn: func(dt *distTest) error {
652 t.addCmd(dt, "misc/swig/callback", t.goTest())
653 return nil
654 },
655 })
656 }
657 }
658 }
659 if t.cgoEnabled {
660 t.tests = append(t.tests, distTest{
661 name: "cgo_test",
662 heading: "../misc/cgo/test",
663 fn: t.cgoTest,
664 })
665 }
666
667 if t.hasBash() && t.cgoEnabled && goos != "android" && goos != "darwin" {
668 t.registerTest("testgodefs", "../misc/cgo/testgodefs", "./test.bash")
669 }
670
671
672
673
674
675 if t.cgoEnabled && gogcflags == "" {
676 t.registerTest("testso", "../misc/cgo/testso", t.goTest(), t.timeout(600), ".")
677 t.registerTest("testsovar", "../misc/cgo/testsovar", t.goTest(), t.timeout(600), ".")
678 if t.supportedBuildmode("c-archive") {
679 t.registerHostTest("testcarchive", "../misc/cgo/testcarchive", "misc/cgo/testcarchive", ".")
680 }
681 if t.supportedBuildmode("c-shared") {
682 t.registerHostTest("testcshared", "../misc/cgo/testcshared", "misc/cgo/testcshared", ".")
683 }
684 if t.supportedBuildmode("shared") {
685 t.registerTest("testshared", "../misc/cgo/testshared", t.goTest(), t.timeout(600), ".")
686 }
687 if t.supportedBuildmode("plugin") {
688 t.registerTest("testplugin", "../misc/cgo/testplugin", t.goTest(), t.timeout(600), ".")
689 }
690 if gohostos == "linux" && goarch == "amd64" {
691 t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go")
692 }
693 if mSanSupported(goos, goarch) {
694 t.registerHostTest("testsanitizers/msan", "../misc/cgo/testsanitizers", "misc/cgo/testsanitizers", ".")
695 }
696 if t.hasBash() && goos != "android" && !t.iOS() && gohostos != "windows" {
697 t.registerHostTest("cgo_errors", "../misc/cgo/errors", "misc/cgo/errors", ".")
698 }
699 if gohostos == "linux" && t.extLink() {
700 t.registerTest("testsigfwd", "../misc/cgo/testsigfwd", "go", "run", "main.go")
701 }
702 }
703
704
705
706 if t.hasBash() && goos != "nacl" && goos != "js" && goos != "android" && !t.iOS() && os.Getenv("GO_BUILDER_NAME") != "" {
707 t.registerTest("doc_progs", "../doc/progs", "time", "go", "run", "run.go")
708 t.registerTest("wiki", "../doc/articles/wiki", "./test.bash")
709 t.registerTest("codewalk", "../doc/codewalk", "time", "./run")
710 }
711
712 if goos != "android" && !t.iOS() {
713
714
715
716 t.registerTest("bench_go1", "../test/bench/go1", t.goTest(), "-c", "-o="+os.DevNull)
717 }
718 if goos != "android" && !t.iOS() {
719
720
721
722 nShards := 1
723 if os.Getenv("GO_BUILDER_NAME") != "" {
724 nShards = 10
725 }
726 if n, err := strconv.Atoi(os.Getenv("GO_TEST_SHARDS")); err == nil {
727 nShards = n
728 }
729 for shard := 0; shard < nShards; shard++ {
730 shard := shard
731 t.tests = append(t.tests, distTest{
732 name: fmt.Sprintf("test:%d_%d", shard, nShards),
733 heading: "../test",
734 fn: func(dt *distTest) error { return t.testDirTest(dt, shard, nShards) },
735 })
736 }
737 }
738 if goos != "nacl" && goos != "android" && !t.iOS() && goos != "js" {
739 t.tests = append(t.tests, distTest{
740 name: "api",
741 heading: "API check",
742 fn: func(dt *distTest) error {
743 if t.compileOnly {
744 t.addCmd(dt, "src", "go", "build", filepath.Join(goroot, "src/cmd/api/run.go"))
745 return nil
746 }
747 t.addCmd(dt, "src", "go", "run", filepath.Join(goroot, "src/cmd/api/run.go"))
748 return nil
749 },
750 })
751 }
752
753
754
755 if os.Getenv("GO_BUILDER_NAME") != "" && goos != "android" && !t.iOS() {
756 t.registerHostTest("reboot", "../misc/reboot", "misc/reboot", ".")
757 }
758 }
759
760
761
762 func (t *tester) isRegisteredTestName(testName string) bool {
763 for _, tt := range t.tests {
764 if tt.name == testName {
765 return true
766 }
767 }
768 return false
769 }
770
771 func (t *tester) registerTest1(seq bool, name, dirBanner string, cmdline ...interface{}) {
772 bin, args := flattenCmdline(cmdline)
773 if bin == "time" && !t.haveTime {
774 bin, args = args[0], args[1:]
775 }
776 if t.isRegisteredTestName(name) {
777 panic("duplicate registered test name " + name)
778 }
779 t.tests = append(t.tests, distTest{
780 name: name,
781 heading: dirBanner,
782 fn: func(dt *distTest) error {
783 if seq {
784 t.runPending(dt)
785 timelog("start", name)
786 defer timelog("end", name)
787 return t.dirCmd(filepath.Join(goroot, "src", dirBanner), bin, args).Run()
788 }
789 t.addCmd(dt, filepath.Join(goroot, "src", dirBanner), bin, args)
790 return nil
791 },
792 })
793 }
794
795 func (t *tester) registerTest(name, dirBanner string, cmdline ...interface{}) {
796 t.registerTest1(false, name, dirBanner, cmdline...)
797 }
798
799 func (t *tester) registerSeqTest(name, dirBanner string, cmdline ...interface{}) {
800 t.registerTest1(true, name, dirBanner, cmdline...)
801 }
802
803 func (t *tester) bgDirCmd(dir, bin string, args ...string) *exec.Cmd {
804 cmd := exec.Command(bin, args...)
805 if filepath.IsAbs(dir) {
806 cmd.Dir = dir
807 } else {
808 cmd.Dir = filepath.Join(goroot, dir)
809 }
810 return cmd
811 }
812
813 func (t *tester) dirCmd(dir string, cmdline ...interface{}) *exec.Cmd {
814 bin, args := flattenCmdline(cmdline)
815 cmd := t.bgDirCmd(dir, bin, args...)
816 cmd.Stdout = os.Stdout
817 cmd.Stderr = os.Stderr
818 if vflag > 1 {
819 errprintf("%s\n", strings.Join(cmd.Args, " "))
820 }
821 return cmd
822 }
823
824
825
826 func flattenCmdline(cmdline []interface{}) (bin string, args []string) {
827 var list []string
828 for _, x := range cmdline {
829 switch x := x.(type) {
830 case string:
831 list = append(list, x)
832 case []string:
833 list = append(list, x...)
834 default:
835 panic("invalid addCmd argument type: " + reflect.TypeOf(x).String())
836 }
837 }
838
839
840
841 drop := make([]bool, len(list))
842 have := map[string]int{}
843 for i := 1; i < len(list); i++ {
844 j := strings.Index(list[i], "=")
845 if j < 0 {
846 continue
847 }
848 flag := list[i][:j]
849 switch flag {
850 case "-run", "-tags":
851 if have[flag] != 0 {
852 drop[have[flag]] = true
853 }
854 have[flag] = i
855 }
856 }
857 out := list[:0]
858 for i, x := range list {
859 if !drop[i] {
860 out = append(out, x)
861 }
862 }
863 list = out
864
865 return list[0], list[1:]
866 }
867
868 func (t *tester) addCmd(dt *distTest, dir string, cmdline ...interface{}) *exec.Cmd {
869 bin, args := flattenCmdline(cmdline)
870 w := &work{
871 dt: dt,
872 cmd: t.bgDirCmd(dir, bin, args...),
873 }
874 t.worklist = append(t.worklist, w)
875 return w.cmd
876 }
877
878 func (t *tester) iOS() bool {
879 return goos == "darwin" && (goarch == "arm" || goarch == "arm64")
880 }
881
882 func (t *tester) out(v string) {
883 if t.banner == "" {
884 return
885 }
886 fmt.Println("\n" + t.banner + v)
887 }
888
889 func (t *tester) extLink() bool {
890 pair := gohostos + "-" + goarch
891 switch pair {
892 case "aix-ppc64",
893 "android-arm",
894 "darwin-386", "darwin-amd64", "darwin-arm", "darwin-arm64",
895 "dragonfly-amd64",
896 "freebsd-386", "freebsd-amd64", "freebsd-arm",
897 "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le", "linux-mips", "linux-mipsle", "linux-s390x",
898 "netbsd-386", "netbsd-amd64",
899 "openbsd-386", "openbsd-amd64",
900 "windows-386", "windows-amd64":
901 return true
902 }
903 return false
904 }
905
906 func (t *tester) internalLink() bool {
907 if gohostos == "dragonfly" {
908
909 return false
910 }
911 if gohostarch == "ppc64le" {
912
913
914 return false
915 }
916 if goos == "android" {
917 return false
918 }
919 if goos == "darwin" && (goarch == "arm" || goarch == "arm64") {
920 return false
921 }
922
923
924
925 if goarch == "mips64" || goarch == "mips64le" || goarch == "mips" || goarch == "mipsle" {
926 return false
927 }
928 if goos == "aix" {
929
930 return false
931 }
932 return true
933 }
934
935 func (t *tester) supportedBuildmode(mode string) bool {
936 pair := goos + "-" + goarch
937 switch mode {
938 case "c-archive":
939 if !t.extLink() {
940 return false
941 }
942 switch pair {
943 case "aix-ppc64",
944 "darwin-386", "darwin-amd64", "darwin-arm", "darwin-arm64",
945 "linux-amd64", "linux-386", "linux-ppc64le", "linux-s390x",
946 "freebsd-amd64",
947 "windows-amd64", "windows-386":
948 return true
949 }
950 return false
951 case "c-shared":
952 switch pair {
953 case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x",
954 "darwin-amd64", "darwin-386",
955 "freebsd-amd64",
956 "android-arm", "android-arm64", "android-386",
957 "windows-amd64", "windows-386":
958 return true
959 }
960 return false
961 case "shared":
962 switch pair {
963 case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x":
964 return true
965 }
966 return false
967 case "plugin":
968
969
970 switch pair {
971 case "linux-386", "linux-amd64", "linux-arm", "linux-s390x", "linux-ppc64le":
972 return true
973 case "darwin-amd64":
974 return true
975 }
976 return false
977 case "pie":
978 switch pair {
979 case "aix/ppc64",
980 "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x",
981 "android-amd64", "android-arm", "android-arm64", "android-386":
982 return true
983 case "darwin-amd64":
984 return true
985 }
986 return false
987
988 default:
989 log.Fatalf("internal error: unknown buildmode %s", mode)
990 return false
991 }
992 }
993
994 func (t *tester) registerHostTest(name, heading, dir, pkg string) {
995 t.tests = append(t.tests, distTest{
996 name: name,
997 heading: heading,
998 fn: func(dt *distTest) error {
999 t.runPending(dt)
1000 timelog("start", name)
1001 defer timelog("end", name)
1002 return t.runHostTest(dir, pkg)
1003 },
1004 })
1005 }
1006
1007 func (t *tester) runHostTest(dir, pkg string) error {
1008 defer os.Remove(filepath.Join(goroot, dir, "test.test"))
1009 cmd := t.dirCmd(dir, t.goTest(), "-c", "-o", "test.test", pkg)
1010 cmd.Env = append(os.Environ(), "GOARCH="+gohostarch, "GOOS="+gohostos)
1011 if err := cmd.Run(); err != nil {
1012 return err
1013 }
1014 return t.dirCmd(dir, "./test.test", "-test.short").Run()
1015 }
1016
1017 func (t *tester) cgoTest(dt *distTest) error {
1018 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
1019 cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=auto")
1020
1021 if t.internalLink() {
1022 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=internal")
1023 cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=internal")
1024 }
1025
1026 pair := gohostos + "-" + goarch
1027 switch pair {
1028 case "darwin-386", "darwin-amd64",
1029 "openbsd-386", "openbsd-amd64",
1030 "windows-386", "windows-amd64":
1031
1032 if !t.extLink() {
1033 break
1034 }
1035 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
1036 cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=external")
1037
1038 cmd = t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s")
1039
1040 case "aix-ppc64",
1041 "android-arm",
1042 "dragonfly-amd64",
1043 "freebsd-386", "freebsd-amd64", "freebsd-arm",
1044 "linux-386", "linux-amd64", "linux-arm", "linux-ppc64le", "linux-s390x",
1045 "netbsd-386", "netbsd-amd64", "linux-arm64":
1046
1047 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
1048 cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=external")
1049
1050 cmd.Env = append(cmd.Env, "CGO_CFLAGS=-g0")
1051
1052 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=auto")
1053 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=external")
1054
1055 switch pair {
1056 case "aix-ppc64", "netbsd-386", "netbsd-amd64":
1057
1058 case "freebsd-arm":
1059
1060
1061
1062
1063
1064 default:
1065 cmd := t.dirCmd("misc/cgo/test",
1066 compilerEnvLookup(defaultcc, goos, goarch), "-xc", "-o", "/dev/null", "-static", "-")
1067 cmd.Stdin = strings.NewReader("int main() {}")
1068 if err := cmd.Run(); err != nil {
1069 fmt.Println("No support for static linking found (lacks libc.a?), skip cgo static linking test.")
1070 } else {
1071 if goos != "android" {
1072 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
1073 }
1074 t.addCmd(dt, "misc/cgo/nocgo", t.goTest())
1075 t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-ldflags", `-linkmode=external`)
1076 if goos != "android" {
1077 t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
1078 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
1079
1080
1081
1082 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static")
1083 cmd.Env = append(os.Environ(), "CGO_LDFLAGS=-static -pthread")
1084 }
1085 }
1086
1087 if t.supportedBuildmode("pie") {
1088 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie")
1089 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-buildmode=pie")
1090 t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-buildmode=pie")
1091 }
1092 }
1093 }
1094
1095 return nil
1096 }
1097
1098
1099
1100
1101
1102
1103
1104 func (t *tester) runPending(nextTest *distTest) {
1105 checkNotStale("go", "std")
1106 worklist := t.worklist
1107 t.worklist = nil
1108 for _, w := range worklist {
1109 w.start = make(chan bool)
1110 w.end = make(chan bool)
1111 go func(w *work) {
1112 if !<-w.start {
1113 timelog("skip", w.dt.name)
1114 w.out = []byte(fmt.Sprintf("skipped due to earlier error\n"))
1115 } else {
1116 timelog("start", w.dt.name)
1117 w.out, w.err = w.cmd.CombinedOutput()
1118 if w.err != nil {
1119 if isUnsupportedVMASize(w) {
1120 timelog("skip", w.dt.name)
1121 w.out = []byte(fmt.Sprintf("skipped due to unsupported VMA\n"))
1122 w.err = nil
1123 }
1124 }
1125 }
1126 timelog("end", w.dt.name)
1127 w.end <- true
1128 }(w)
1129 }
1130
1131 started := 0
1132 ended := 0
1133 var last *distTest
1134 for ended < len(worklist) {
1135 for started < len(worklist) && started-ended < maxbg {
1136 w := worklist[started]
1137 started++
1138 w.start <- !t.failed || t.keepGoing
1139 }
1140 w := worklist[ended]
1141 dt := w.dt
1142 if dt.heading != "" && t.lastHeading != dt.heading {
1143 t.lastHeading = dt.heading
1144 t.out(dt.heading)
1145 }
1146 if dt != last {
1147
1148 last = w.dt
1149 if vflag > 0 {
1150 fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
1151 }
1152 }
1153 if vflag > 1 {
1154 errprintf("%s\n", strings.Join(w.cmd.Args, " "))
1155 }
1156 ended++
1157 <-w.end
1158 os.Stdout.Write(w.out)
1159 if w.err != nil {
1160 log.Printf("Failed: %v", w.err)
1161 t.failed = true
1162 }
1163 checkNotStale("go", "std")
1164 }
1165 if t.failed && !t.keepGoing {
1166 log.Fatal("FAILED")
1167 }
1168
1169 if dt := nextTest; dt != nil {
1170 if dt.heading != "" && t.lastHeading != dt.heading {
1171 t.lastHeading = dt.heading
1172 t.out(dt.heading)
1173 }
1174 if vflag > 0 {
1175 fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
1176 }
1177 }
1178 }
1179
1180 func (t *tester) hasBash() bool {
1181 switch gohostos {
1182 case "windows", "plan9":
1183 return false
1184 }
1185 return true
1186 }
1187
1188 func (t *tester) hasCxx() bool {
1189 cxx, _ := exec.LookPath(compilerEnvLookup(defaultcxx, goos, goarch))
1190 return cxx != ""
1191 }
1192
1193 func (t *tester) hasSwig() bool {
1194 swig, err := exec.LookPath("swig")
1195 if err != nil {
1196 return false
1197 }
1198
1199
1200
1201
1202 output, err := exec.Command(swig, "-go", "-swiglib").Output()
1203 if err != nil {
1204 return false
1205 }
1206 swigDir := strings.TrimSpace(string(output))
1207
1208 _, err = os.Stat(filepath.Join(swigDir, "go"))
1209 if err != nil {
1210 return false
1211 }
1212
1213
1214
1215 out, err := exec.Command(swig, "-version").CombinedOutput()
1216 if err != nil {
1217 return false
1218 }
1219
1220 re := regexp.MustCompile(`[vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)?`)
1221 matches := re.FindSubmatch(out)
1222 if matches == nil {
1223
1224 return true
1225 }
1226
1227 major, err := strconv.Atoi(string(matches[1]))
1228 if err != nil {
1229
1230 return true
1231 }
1232 if major < 3 {
1233 return false
1234 }
1235 if major > 3 {
1236
1237 return true
1238 }
1239
1240
1241 if len(matches[2]) > 0 {
1242 minor, err := strconv.Atoi(string(matches[2][1:]))
1243 if err != nil {
1244 return true
1245 }
1246 if minor > 0 {
1247
1248 return true
1249 }
1250 }
1251
1252
1253 if len(matches[3]) > 0 {
1254 patch, err := strconv.Atoi(string(matches[3][1:]))
1255 if err != nil {
1256 return true
1257 }
1258 if patch < 6 {
1259
1260 return false
1261 }
1262 }
1263
1264 return true
1265 }
1266
1267 func (t *tester) raceDetectorSupported() bool {
1268 if gohostos != goos {
1269 return false
1270 }
1271 if !t.cgoEnabled {
1272 return false
1273 }
1274 if !raceDetectorSupported(goos, goarch) {
1275 return false
1276 }
1277
1278
1279 if isAlpineLinux() {
1280 return false
1281 }
1282
1283
1284 if goos == "netbsd" {
1285 return false
1286 }
1287 return true
1288 }
1289
1290 func isAlpineLinux() bool {
1291 if runtime.GOOS != "linux" {
1292 return false
1293 }
1294 fi, err := os.Lstat("/etc/alpine-release")
1295 return err == nil && fi.Mode().IsRegular()
1296 }
1297
1298 func (t *tester) runFlag(rx string) string {
1299 if t.compileOnly {
1300 return "-run=^$"
1301 }
1302 return "-run=" + rx
1303 }
1304
1305 func (t *tester) raceTest(dt *distTest) error {
1306 t.addCmd(dt, "src", t.goTest(), "-race", "-i", "runtime/race", "flag", "os", "os/exec")
1307 t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("Output"), "runtime/race")
1308 t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace|TestTypeRace|TestFdRace|TestFdReadRace|TestFileCloseRace"), "flag", "net", "os", "os/exec", "encoding/gob")
1309
1310
1311
1312
1313
1314 if t.cgoEnabled {
1315
1316
1317
1318
1319
1320
1321 }
1322 if t.extLink() {
1323
1324 t.addCmd(dt, "src", t.goTest(), "-race", "-ldflags=-linkmode=external", t.runFlag("TestParse|TestEcho|TestStdinCloseRace"), "flag", "os/exec")
1325 }
1326 return nil
1327 }
1328
1329 var runtest struct {
1330 sync.Once
1331 exe string
1332 err error
1333 }
1334
1335 func (t *tester) testDirTest(dt *distTest, shard, shards int) error {
1336 runtest.Do(func() {
1337 const exe = "runtest.exe"
1338 cmd := t.dirCmd("test", "go", "build", "-o", exe, "run.go")
1339 cmd.Env = append(os.Environ(), "GOOS="+gohostos, "GOARCH="+gohostarch)
1340 runtest.exe = filepath.Join(cmd.Dir, exe)
1341 if err := cmd.Run(); err != nil {
1342 runtest.err = err
1343 return
1344 }
1345 xatexit(func() {
1346 os.Remove(runtest.exe)
1347 })
1348 })
1349 if runtest.err != nil {
1350 return runtest.err
1351 }
1352 if t.compileOnly {
1353 return nil
1354 }
1355 t.addCmd(dt, "test", runtest.exe,
1356 fmt.Sprintf("--shard=%d", shard),
1357 fmt.Sprintf("--shards=%d", shards),
1358 )
1359 return nil
1360 }
1361
1362
1363 var cgoPackages = []string{
1364 "crypto/x509",
1365 "net",
1366 "os/user",
1367 }
1368
1369 var funcBenchmark = []byte("\nfunc Benchmark")
1370
1371
1372
1373
1374
1375
1376
1377
1378 func (t *tester) packageHasBenchmarks(pkg string) bool {
1379 pkgDir := filepath.Join(goroot, "src", pkg)
1380 d, err := os.Open(pkgDir)
1381 if err != nil {
1382 return true
1383 }
1384 defer d.Close()
1385 names, err := d.Readdirnames(-1)
1386 if err != nil {
1387 return true
1388 }
1389 for _, name := range names {
1390 if !strings.HasSuffix(name, "_test.go") {
1391 continue
1392 }
1393 slurp, err := ioutil.ReadFile(filepath.Join(pkgDir, name))
1394 if err != nil {
1395 return true
1396 }
1397 if bytes.Contains(slurp, funcBenchmark) {
1398 return true
1399 }
1400 }
1401 return false
1402 }
1403
1404
1405
1406 func (t *tester) makeGOROOTUnwritable() {
1407 if os.Getenv("GO_BUILDER_NAME") == "" {
1408 panic("not a builder")
1409 }
1410 if os.Getenv("GOROOT") == "" {
1411 panic("GOROOT not set")
1412 }
1413 err := filepath.Walk(os.Getenv("GOROOT"), func(name string, fi os.FileInfo, err error) error {
1414 if err != nil {
1415 return err
1416 }
1417 if !fi.Mode().IsRegular() && !fi.IsDir() {
1418 return nil
1419 }
1420 mode := fi.Mode()
1421 newMode := mode & ^os.FileMode(0222)
1422 if newMode != mode {
1423 if err := os.Chmod(name, newMode); err != nil {
1424 return err
1425 }
1426 }
1427 return nil
1428 })
1429 if err != nil {
1430 log.Fatalf("making builder's files read-only: %v", err)
1431 }
1432 }
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444 func (t *tester) shouldUsePrecompiledStdTest() bool {
1445 bin := t.prebuiltGoPackageTestBinary()
1446 if bin == "" {
1447 return false
1448 }
1449 _, err := os.Stat(bin)
1450 return err == nil
1451 }
1452
1453
1454
1455
1456
1457 func (t *tester) prebuiltGoPackageTestBinary() string {
1458 if len(stdMatches) != 1 || t.race || t.compileOnly || os.Getenv("GO_BUILDER_NAME") == "" {
1459 return ""
1460 }
1461 pkg := stdMatches[0]
1462 return filepath.Join(os.Getenv("GOROOT"), "src", pkg, path.Base(pkg)+".test")
1463 }
1464
1465
1466
1467 func (t *tester) runPrecompiledStdTest(timeout time.Duration) error {
1468 bin := t.prebuiltGoPackageTestBinary()
1469 fmt.Fprintf(os.Stderr, "# %s: using pre-built %s...\n", stdMatches[0], bin)
1470 cmd := exec.Command(bin, "-test.short", "-test.timeout="+timeout.String())
1471 cmd.Dir = filepath.Dir(bin)
1472 cmd.Stdout = os.Stdout
1473 cmd.Stderr = os.Stderr
1474 if err := cmd.Start(); err != nil {
1475 return err
1476 }
1477
1478
1479 const backupKillFactor = 1.05
1480 timer := time.AfterFunc(time.Duration(float64(timeout)*backupKillFactor), func() {
1481 fmt.Fprintf(os.Stderr, "# %s: timeout running %s; killing...\n", stdMatches[0], bin)
1482 cmd.Process.Kill()
1483 })
1484 defer timer.Stop()
1485 return cmd.Wait()
1486 }
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496 func raceDetectorSupported(goos, goarch string) bool {
1497 switch goos {
1498 case "linux":
1499 return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64"
1500 case "darwin", "freebsd", "netbsd", "windows":
1501 return goarch == "amd64"
1502 default:
1503 return false
1504 }
1505 }
1506
1507
1508
1509 func mSanSupported(goos, goarch string) bool {
1510 switch goos {
1511 case "linux":
1512 return goarch == "amd64" || goarch == "arm64"
1513 default:
1514 return false
1515 }
1516 }
1517
1518
1519
1520
1521 func isUnsupportedVMASize(w *work) bool {
1522 unsupportedVMA := []byte("unsupported VMA range")
1523 return w.dt.name == "race" && bytes.Contains(w.out, unsupportedVMA)
1524 }
1525
View as plain text