1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
25 gogcflags = os.Getenv("GO_GCFLAGS")
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 flag.BoolVar(&t.msan, "msan", false, "run in memory sanitizer builder mode")
42 flag.BoolVar(&t.asan, "asan", false, "run in address sanitizer builder mode")
44 xflagparse(-1) // any number of args
52 // tester executes cmdtest.
61 compileOnly bool // just try to compile all tests, but no need to run
64 runRxWant bool // want runRx to match (true) or not match (false)
65 runNames []string // tests to run, exclusive with runRx; empty means all
66 banner string // prefix, or "" for none
67 lastHeading string // last dir heading printed
71 haveTime bool // the 'time' binary is available
88 // A distTest is a test run by dist test.
89 // Each test has a unique name and belongs to a group (heading)
90 type distTest struct {
91 name string // unique test name; may be filtered with -run flag
92 heading string // group section; this header is printed before the test is run.
93 fn func(*distTest) error
96 func (t *tester) run() {
97 timelog("start", "dist test")
99 os.Setenv("PATH", fmt.Sprintf("%s%c%s", gorootBin, os.PathListSeparator, os.Getenv("PATH")))
101 cmd := exec.Command(gorootBinGo, "env", "CGO_ENABLED")
102 cmd.Stderr = new(bytes.Buffer)
103 slurp, err := cmd.Output()
105 fatalf("Error running go env CGO_ENABLED: %v\n%s", err, cmd.Stderr)
107 t.cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(slurp)))
108 if flag.NArg() > 0 && t.runRxStr != "" {
109 fatalf("the -run regular expression flag is mutually exclusive with test name arguments")
112 t.runNames = flag.Args()
115 if _, err := exec.LookPath("time"); err == nil {
120 // Set GOTRACEBACK to system if the user didn't set a level explicitly.
121 // Since we're running tests for Go, we want as much detail as possible
122 // if something goes wrong.
124 // Set it before running any commands just in case something goes wrong.
125 if ok := isEnvSet("GOTRACEBACK"); !ok {
126 if err := os.Setenv("GOTRACEBACK", "system"); err != nil {
128 log.Printf("Failed to set GOTRACEBACK: %v", err)
130 fatalf("Failed to set GOTRACEBACK: %v", err)
136 t.out("Building packages and commands.")
137 // Force rebuild the whole toolchain.
138 goInstall("go", append([]string{"-a"}, toolchain...)...)
142 if os.Getenv("GO_BUILDER_NAME") == "" {
143 // Complete rebuild bootstrap, even with -no-rebuild.
144 // If everything is up-to-date, this is a no-op.
145 // If everything is not up-to-date, the first checkNotStale
146 // during the test process will kill the tests, so we might
147 // as well install the world.
148 // Now that for example "go install cmd/compile" does not
149 // also install runtime (you need "go install -i cmd/compile"
150 // for that), it's easy for previous workflows like
151 // "rebuild the compiler and then run run.bash"
152 // to break if we don't automatically refresh things here.
153 // Rebuilding is a shortened bootstrap.
154 // See cmdbootstrap for a description of the overall process.
155 goInstall("go", toolchain...)
156 goInstall("go", toolchain...)
157 goInstall("go", "std", "cmd")
159 // The Go builder infrastructure should always begin running tests from a
160 // clean, non-stale state, so there is no need to rebuild the world.
161 // Instead, we can just check that it is not stale, which may be less
162 // expensive (and is also more likely to catch bugs in the builder
164 checkNotStale("go", "std", "cmd")
172 case "mips", "mipsle", "mips64", "mips64le":
175 if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
176 t.timeoutScale, err = strconv.Atoi(s)
178 fatalf("failed to parse $GO_TEST_TIMEOUT_SCALE = %q as integer: %v", s, err)
182 if t.runRxStr != "" {
183 if t.runRxStr[0] == '!' {
185 t.runRxStr = t.runRxStr[1:]
189 t.runRx = regexp.MustCompile(t.runRxStr)
194 for _, tt := range t.tests {
200 for _, name := range t.runNames {
201 if !t.isRegisteredTestName(name) {
202 fatalf("unknown test %q", name)
206 // On a few builders, make GOROOT unwritable to catch tests writing to it.
207 if strings.HasPrefix(os.Getenv("GO_BUILDER_NAME"), "linux-") {
208 if os.Getuid() == 0 {
209 // Don't bother making GOROOT unwritable:
210 // we're running as root, so permissions would have no effect.
212 xatexit(t.makeGOROOTUnwritable())
216 if err := t.maybeLogMetadata(); err != nil {
219 log.Printf("Failed logging metadata: %v", err)
221 fatalf("Failed logging metadata: %v", err)
225 for _, dt := range t.tests {
226 if !t.shouldRunTest(dt.name) {
230 dt := dt // dt used in background after this iteration
231 if err := dt.fn(&dt); err != nil {
232 t.runPending(&dt) // in case that hasn't been done yet
235 log.Printf("Failed: %v", err)
237 fatalf("Failed: %v", err)
242 timelog("end", "dist test")
245 fmt.Println("\nFAILED")
247 } else if incomplete[goos+"/"+goarch] {
248 // The test succeeded, but consider it as failed so we don't
249 // forget to remove the port from the incomplete map once the
251 fmt.Println("\nFAILED (incomplete port)")
253 } else if t.partial {
254 fmt.Println("\nALL TESTS PASSED (some were excluded)")
256 fmt.Println("\nALL TESTS PASSED")
260 func (t *tester) shouldRunTest(name string) bool {
262 return t.runRx.MatchString(name) == t.runRxWant
264 if len(t.runNames) == 0 {
267 for _, runName := range t.runNames {
275 func (t *tester) maybeLogMetadata() error {
277 // We need to run a subprocess to log metadata. Don't do that
278 // on compile-only runs.
281 t.out("Test execution environment.")
282 // Helper binary to print system metadata (CPU model, etc). This is a
283 // separate binary from dist so it need not build with the bootstrap
286 // TODO(prattmic): If we split dist bootstrap and dist test then this
287 // could be simplified to directly use internal/sysinfo here.
288 return t.dirCmd(filepath.Join(goroot, "src/cmd/internal/metadata"), "go", []string{"run", "main.go"}).Run()
291 // short returns a -short flag value to use with 'go test'
292 // or a test binary for tests intended to run in short mode.
293 // It returns "true", unless the environment variable
294 // GO_TEST_SHORT is set to a non-empty, false-ish string.
296 // This environment variable is meant to be an internal
297 // detail between the Go build system and cmd/dist for
298 // the purpose of longtest builders, and is not intended
299 // for use by users. See golang.org/issue/12508.
300 func short() string {
301 if v := os.Getenv("GO_TEST_SHORT"); v != "" {
302 short, err := strconv.ParseBool(v)
304 fatalf("invalid GO_TEST_SHORT %q: %v", v, err)
313 // goTest returns the beginning of the go test command line.
314 // Callers should use goTest and then pass flags overriding these
315 // defaults as later arguments in the command line.
316 func (t *tester) goTest() []string {
318 "go", "test", "-short=" + short(), "-count=1", t.tags(), t.runFlag(""),
322 func (t *tester) tags() string {
326 return "-tags=lldb,noopt"
336 // timeoutDuration converts the provided number of seconds into a
337 // time.Duration, scaled by the t.timeoutScale factor.
338 func (t *tester) timeoutDuration(sec int) time.Duration {
339 return time.Duration(sec) * time.Second * time.Duration(t.timeoutScale)
342 // timeout returns the "-timeout=" string argument to "go test" given
343 // the number of seconds of timeout. It scales it by the
344 // t.timeoutScale factor.
345 func (t *tester) timeout(sec int) string {
346 return "-timeout=" + t.timeoutDuration(sec).String()
349 // ranGoTest and stdMatches are state closed over by the stdlib
350 // testing func in registerStdTest below. The tests are run
351 // sequentially, so there's no need for locks.
353 // ranGoBench and benchMatches are the same, but are only used
360 benchMatches []string
363 func (t *tester) registerStdTest(pkg string) {
364 heading := "Testing packages."
365 testPrefix := "go_test:"
368 testName := testPrefix + pkg
369 if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant {
370 stdMatches = append(stdMatches, pkg)
373 t.tests = append(t.tests, distTest{
376 fn: func(dt *distTest) error {
381 timelog("start", dt.name)
382 defer timelog("end", dt.name)
386 for _, pkg := range stdMatches {
396 t.timeout(timeoutSec),
399 args = append(args, "-gcflags=all="+gcflags)
402 args = append(args, "-race")
405 args = append(args, "-msan")
408 args = append(args, "-asan")
411 args = append(args, "-run=^$")
413 args = append(args, stdMatches...)
414 cmd := exec.Command(gorootBinGo, args...)
415 cmd.Stdout = os.Stdout
416 cmd.Stderr = os.Stderr
422 func (t *tester) registerRaceBenchTest(pkg string) {
423 testName := "go_test_bench:" + pkg
424 if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant {
425 benchMatches = append(benchMatches, pkg)
427 t.tests = append(t.tests, distTest{
429 heading: "Running benchmarks briefly.",
430 fn: func(dt *distTest) error {
435 timelog("start", dt.name)
436 defer timelog("end", dt.name)
442 t.timeout(1200), // longer timeout for race with benchmarks
443 "-run=^$", // nothing. only benchmarks.
448 args = append(args, "-bench=.*")
450 args = append(args, benchMatches...)
451 cmd := exec.Command(gorootBinGo, args...)
452 cmd.Stdout = os.Stdout
453 cmd.Stderr = os.Stderr
459 // stdOutErrAreTerminals is defined in test_linux.go, to report
460 // whether stdout & stderr are terminals.
461 var stdOutErrAreTerminals func() bool
463 func (t *tester) registerTests() {
464 // Fast path to avoid the ~1 second of `go list std cmd` when
465 // the caller lists specific tests to run. (as the continuous
466 // build coordinator does).
467 if len(t.runNames) > 0 {
468 for _, name := range t.runNames {
469 if strings.HasPrefix(name, "go_test:") {
470 t.registerStdTest(strings.TrimPrefix(name, "go_test:"))
472 if strings.HasPrefix(name, "go_test_bench:") {
473 t.registerRaceBenchTest(strings.TrimPrefix(name, "go_test_bench:"))
477 // Use a format string to only list packages and commands that have tests.
478 const format = "{{if (or .TestGoFiles .XTestGoFiles)}}{{.ImportPath}}{{end}}"
479 cmd := exec.Command(gorootBinGo, "list", "-f", format)
481 cmd.Args = append(cmd.Args, "-tags=race")
483 cmd.Args = append(cmd.Args, "std", "cmd")
484 cmd.Stderr = new(bytes.Buffer)
485 all, err := cmd.Output()
487 fatalf("Error running go list std cmd: %v:\n%s", err, cmd.Stderr)
489 pkgs := strings.Fields(string(all))
490 for _, pkg := range pkgs {
491 t.registerStdTest(pkg)
494 for _, pkg := range pkgs {
495 if t.packageHasBenchmarks(pkg) {
496 t.registerRaceBenchTest(pkg)
502 // Test the os/user package in the pure-Go mode too.
504 t.tests = append(t.tests, distTest{
506 heading: "os/user with tag osusergo",
507 fn: func(dt *distTest) error {
508 t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-tags=osusergo", "os/user")
514 // Test ios/amd64 for the iOS simulator.
515 if goos == "darwin" && goarch == "amd64" && t.cgoEnabled {
516 t.tests = append(t.tests, distTest{
518 heading: "GOOS=ios on darwin/amd64",
519 fn: func(dt *distTest) error {
520 cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-run=SystemRoots", "crypto/x509")
521 setEnv(cmd, "GOOS", "ios")
522 setEnv(cmd, "CGO_ENABLED", "1")
532 // Runtime CPU tests.
533 if !t.compileOnly && goos != "js" { // js can't handle -cpu != 1
534 testName := "runtime:cpu124"
535 t.tests = append(t.tests, distTest{
537 heading: "GOMAXPROCS=2 runtime -cpu=1,2,4 -quick",
538 fn: func(dt *distTest) error {
539 cmd := t.addCmd(dt, "src", t.goTest(), "-short=true", t.timeout(300), "runtime", "-cpu=1,2,4", "-quick")
540 // We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
541 // creation of first goroutines and first garbage collections in the parallel setting.
542 setEnv(cmd, "GOMAXPROCS", "2")
548 // morestack tests. We only run these on in long-test mode
549 // (with GO_TEST_SHORT=false) because the runtime test is
550 // already quite long and mayMoreStackMove makes it about
552 if !t.compileOnly && short() == "false" {
553 // hooks is the set of maymorestack hooks to test with.
554 hooks := []string{"mayMoreStackPreempt", "mayMoreStackMove"}
555 // pkgs is the set of test packages to run.
556 pkgs := []string{"runtime", "reflect", "sync"}
557 // hookPkgs is the set of package patterns to apply
558 // the maymorestack hook to.
559 hookPkgs := []string{"runtime/...", "reflect", "sync"}
560 // unhookPkgs is the set of package patterns to
561 // exclude from hookPkgs.
562 unhookPkgs := []string{"runtime/testdata/..."}
563 for _, hook := range hooks {
564 // Construct the build flags to use the
565 // maymorestack hook in the compiler and
566 // assembler. We pass this via the GOFLAGS
567 // environment variable so that it applies to
568 // both the test itself and to binaries built
570 goFlagsList := []string{}
571 for _, flag := range []string{"-gcflags", "-asmflags"} {
572 for _, hookPkg := range hookPkgs {
573 goFlagsList = append(goFlagsList, flag+"="+hookPkg+"=-d=maymorestack=runtime."+hook)
575 for _, unhookPkg := range unhookPkgs {
576 goFlagsList = append(goFlagsList, flag+"="+unhookPkg+"=")
579 goFlags := strings.Join(goFlagsList, " ")
581 for _, pkg := range pkgs {
583 testName := hook + ":" + pkg
584 t.tests = append(t.tests, distTest{
586 heading: "maymorestack=" + hook,
587 fn: func(dt *distTest) error {
588 cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(600), pkg, "-short")
589 setEnv(cmd, "GOFLAGS", goFlags)
597 // This test needs its stdout/stderr to be terminals, so we don't run it from cmd/go's tests.
600 t.tests = append(t.tests, distTest{
601 name: "cmd_go_test_terminal",
602 heading: "cmd/go terminal test",
603 fn: func(dt *distTest) error {
605 timelog("start", dt.name)
606 defer timelog("end", dt.name)
607 if !stdOutErrAreTerminals() {
608 fmt.Println("skipping terminal test; stdout/stderr not terminals")
611 cmd := exec.Command(gorootBinGo, "test")
612 setDir(cmd, filepath.Join(os.Getenv("GOROOT"), "src/cmd/go/testdata/testterminal18153"))
613 cmd.Stdout = os.Stdout
614 cmd.Stderr = os.Stderr
620 // On the builders only, test that a moved GOROOT still works.
621 // Fails on iOS because CC_FOR_TARGET refers to clangwrap.sh
622 // in the unmoved GOROOT.
623 // Fails on Android and js/wasm with an exec format error.
624 // Fails on plan9 with "cannot find GOROOT" (issue #21016).
625 if os.Getenv("GO_BUILDER_NAME") != "" && goos != "android" && !t.iOS() && goos != "plan9" && goos != "js" {
626 t.tests = append(t.tests, distTest{
627 name: "moved_goroot",
628 heading: "moved GOROOT",
629 fn: func(dt *distTest) error {
631 timelog("start", dt.name)
632 defer timelog("end", dt.name)
633 moved := goroot + "-moved"
634 if err := os.Rename(goroot, moved); err != nil {
635 if goos == "windows" {
636 // Fails on Windows (with "Access is denied") if a process
637 // or binary is in this directory. For instance, using all.bat
638 // when run from c:\workdir\go\src fails here
639 // if GO_BUILDER_NAME is set. Our builders invoke tests
640 // a different way which happens to work when sharding
641 // tests, but we should be tolerant of the non-sharded
643 log.Printf("skipping test on Windows")
649 // Run `go test fmt` in the moved GOROOT, without explicitly setting
650 // GOROOT in the environment. The 'go' command should find itself.
651 cmd := exec.Command(filepath.Join(moved, "bin", "go"), "test", "fmt")
652 cmd.Stdout = os.Stdout
653 cmd.Stderr = os.Stderr
654 unsetEnv(cmd, "GOROOT")
655 unsetEnv(cmd, "GOCACHE") // TODO(bcmills): ...why‽
658 if rerr := os.Rename(moved, goroot); rerr != nil {
659 fatalf("failed to restore GOROOT: %v", rerr)
666 // Test that internal linking of standard packages does not
667 // require libgcc. This ensures that we can install a Go
668 // release on a system that does not have a C compiler
669 // installed and still build Go programs (that don't use cgo).
670 for _, pkg := range cgoPackages {
671 if !t.internalLink() {
675 // ARM libgcc may be Thumb, which internal linking does not support.
683 run = "TestTCPStress"
685 t.tests = append(t.tests, distTest{
686 name: "nolibgcc:" + pkg,
687 heading: "Testing without libgcc.",
688 fn: func(dt *distTest) error {
689 // What matters is that the tests build and start up.
690 // Skip expensive tests, especially x509 TestSystemRoots.
691 t.addCmd(dt, "src", t.goTest(), "-ldflags=-linkmode=internal -libgcc=none", "-run=^Test[^CS]", pkg, t.runFlag(run))
697 // Stub out following test on alpine until 54354 resolved.
698 builderName := os.Getenv("GO_BUILDER_NAME")
699 disablePIE := strings.HasSuffix(builderName, "-alpine")
701 // Test internal linking of PIE binaries where it is supported.
702 if t.internalLinkPIE() && !disablePIE {
703 t.tests = append(t.tests, distTest{
704 name: "pie_internal",
705 heading: "internal linking of -buildmode=pie",
706 fn: func(dt *distTest) error {
707 cmd := t.addCmd(dt, "src", t.goTest(), "reflect", "-buildmode=pie", "-ldflags=-linkmode=internal", t.timeout(60))
708 setEnv(cmd, "CGO_ENABLED", "0")
712 // Also test a cgo package.
713 if t.cgoEnabled && t.internalLink() && !disablePIE {
714 t.tests = append(t.tests, distTest{
715 name: "pie_internal_cgo",
716 heading: "internal linking of -buildmode=pie",
717 fn: func(dt *distTest) error {
718 t.addCmd(dt, "src", t.goTest(), "os/user", "-buildmode=pie", "-ldflags=-linkmode=internal", t.timeout(60))
726 if goos != "js" { // js doesn't support -cpu=10
727 t.tests = append(t.tests, distTest{
729 heading: "sync -cpu=10",
730 fn: func(dt *distTest) error {
731 t.addCmd(dt, "src", t.goTest(), "sync", t.timeout(120), "-cpu=10", t.runFlag(""))
737 if t.raceDetectorSupported() {
738 t.tests = append(t.tests, distTest{
740 heading: "Testing race detector",
745 if t.cgoEnabled && !t.iOS() {
746 // Disabled on iOS. golang.org/issue/15919
747 t.registerHostTest("cgo_stdio", "../misc/cgo/stdio", "misc/cgo/stdio", ".")
748 t.registerHostTest("cgo_life", "../misc/cgo/life", "misc/cgo/life", ".")
749 if goos != "android" {
750 t.registerHostTest("cgo_fortran", "../misc/cgo/fortran", "misc/cgo/fortran", ".")
752 if t.hasSwig() && goos != "android" {
753 t.tests = append(t.tests, distTest{
755 heading: "../misc/swig/stdio",
756 fn: func(dt *distTest) error {
757 t.addCmd(dt, "misc/swig/stdio", t.goTest(), ".")
762 t.tests = append(t.tests,
764 name: "swig_callback",
765 heading: "../misc/swig/callback",
766 fn: func(dt *distTest) error {
767 t.addCmd(dt, "misc/swig/callback", t.goTest(), ".")
772 name: "swig_callback_lto",
773 heading: "../misc/swig/callback",
774 fn: func(dt *distTest) error {
775 cmd := t.addCmd(dt, "misc/swig/callback", t.goTest(), ".")
776 setEnv(cmd, "CGO_CFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
777 setEnv(cmd, "CGO_CXXFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
778 setEnv(cmd, "CGO_LDFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
787 t.tests = append(t.tests, distTest{
789 heading: "../misc/cgo/test",
794 // Don't run these tests with $GO_GCFLAGS because most of them
795 // assume that they can run "go install" with no -gcflags and not
796 // recompile the entire standard library. If make.bash ran with
797 // special -gcflags, that's not true.
798 if t.cgoEnabled && gogcflags == "" {
799 t.registerHostTest("testgodefs", "../misc/cgo/testgodefs", "misc/cgo/testgodefs", ".")
801 t.registerTest("testso", "../misc/cgo/testso", t.goTest(), t.timeout(600), ".")
802 t.registerTest("testsovar", "../misc/cgo/testsovar", t.goTest(), t.timeout(600), ".")
803 if t.supportedBuildmode("c-archive") {
804 t.registerHostTest("testcarchive", "../misc/cgo/testcarchive", "misc/cgo/testcarchive", ".")
806 if t.supportedBuildmode("c-shared") {
807 t.registerHostTest("testcshared", "../misc/cgo/testcshared", "misc/cgo/testcshared", ".")
809 if t.supportedBuildmode("shared") {
810 t.registerTest("testshared", "../misc/cgo/testshared", t.goTest(), t.timeout(600), ".")
812 if t.supportedBuildmode("plugin") {
813 t.registerTest("testplugin", "../misc/cgo/testplugin", t.goTest(), t.timeout(600), ".")
815 if goos == "linux" || (goos == "freebsd" && goarch == "amd64") {
816 // because Pdeathsig of syscall.SysProcAttr struct used in misc/cgo/testsanitizers is only
817 // supported on Linux and FreeBSD.
818 t.registerHostTest("testsanitizers", "../misc/cgo/testsanitizers", "misc/cgo/testsanitizers", ".")
820 if t.hasBash() && goos != "android" && !t.iOS() && gohostos != "windows" {
821 t.registerHostTest("cgo_errors", "../misc/cgo/errors", "misc/cgo/errors", ".")
825 if goos != "android" && !t.iOS() {
826 // There are no tests in this directory, only benchmarks.
827 // Check that the test binary builds but don't bother running it.
828 // (It has init-time work to set up for the benchmarks that is not worth doing unnecessarily.)
829 t.registerTest("bench_go1", "../test/bench/go1", t.goTest(), "-c", "-o="+os.DevNull)
831 if goos != "android" && !t.iOS() {
832 // Only start multiple test dir shards on builders,
833 // where they get distributed to multiple machines.
834 // See issues 20141 and 31834.
836 if os.Getenv("GO_BUILDER_NAME") != "" {
839 if n, err := strconv.Atoi(os.Getenv("GO_TEST_SHARDS")); err == nil {
842 for shard := 0; shard < nShards; shard++ {
844 t.tests = append(t.tests, distTest{
845 name: fmt.Sprintf("test:%d_%d", shard, nShards),
847 fn: func(dt *distTest) error { return t.testDirTest(dt, shard, nShards) },
851 // Only run the API check on fast development platforms.
852 // Every platform checks the API on every GOOS/GOARCH/CGO_ENABLED combination anyway,
853 // so we really only need to run this check once anywhere to get adequate coverage.
854 // To help developers avoid trybot-only failures, we try to run on typical developer machines
855 // which is darwin/linux/windows and amd64/arm64.
856 if (goos == "darwin" || goos == "linux" || goos == "windows") && (goarch == "amd64" || goarch == "arm64") {
857 t.tests = append(t.tests, distTest{
859 heading: "API check",
860 fn: func(dt *distTest) error {
862 t.addCmd(dt, "src", "go", "build", "-o", os.DevNull, filepath.Join(goroot, "src/cmd/api/run.go"))
865 t.addCmd(dt, "src", "go", "run", filepath.Join(goroot, "src/cmd/api/run.go"))
871 // Ensure that the toolchain can bootstrap itself.
872 // This test adds another ~45s to all.bash if run sequentially, so run it only on the builders.
873 if os.Getenv("GO_BUILDER_NAME") != "" && goos != "android" && !t.iOS() {
874 t.registerHostTest("reboot", "../misc/reboot", "misc/reboot", ".")
878 // isRegisteredTestName reports whether a test named testName has already
880 func (t *tester) isRegisteredTestName(testName string) bool {
881 for _, tt := range t.tests {
882 if tt.name == testName {
889 func (t *tester) registerTest1(seq bool, name, dirBanner string, cmdline ...interface{}) {
890 bin, args := flattenCmdline(cmdline)
891 if bin == "time" && !t.haveTime {
892 bin, args = args[0], args[1:]
894 if t.isRegisteredTestName(name) {
895 panic("duplicate registered test name " + name)
897 t.tests = append(t.tests, distTest{
900 fn: func(dt *distTest) error {
903 timelog("start", name)
904 defer timelog("end", name)
905 return t.dirCmd(filepath.Join(goroot, "src", dirBanner), bin, args).Run()
907 t.addCmd(dt, filepath.Join(goroot, "src", dirBanner), bin, args)
913 func (t *tester) registerTest(name, dirBanner string, cmdline ...interface{}) {
914 t.registerTest1(false, name, dirBanner, cmdline...)
917 func (t *tester) registerSeqTest(name, dirBanner string, cmdline ...interface{}) {
918 t.registerTest1(true, name, dirBanner, cmdline...)
921 func (t *tester) bgDirCmd(dir, bin string, args ...string) *exec.Cmd {
922 cmd := exec.Command(bin, args...)
923 if filepath.IsAbs(dir) {
926 setDir(cmd, filepath.Join(goroot, dir))
931 func (t *tester) dirCmd(dir string, cmdline ...interface{}) *exec.Cmd {
932 bin, args := flattenCmdline(cmdline)
933 cmd := t.bgDirCmd(dir, bin, args...)
934 cmd.Stdout = os.Stdout
935 cmd.Stderr = os.Stderr
937 errprintf("%s\n", strings.Join(cmd.Args, " "))
942 // flattenCmdline flattens a mixture of string and []string as single list
943 // and then interprets it as a command line: first element is binary, then args.
944 func flattenCmdline(cmdline []interface{}) (bin string, args []string) {
946 for _, x := range cmdline {
947 switch x := x.(type) {
949 list = append(list, x)
951 list = append(list, x...)
953 panic("invalid addCmd argument type: " + reflect.TypeOf(x).String())
957 // The go command is too picky about duplicated flags.
958 // Drop all but the last of the allowed duplicated flags.
959 drop := make([]bool, len(list))
960 have := map[string]int{}
961 for i := 1; i < len(list); i++ {
962 j := strings.Index(list[i], "=")
968 case "-run", "-tags":
970 drop[have[flag]] = true
976 for i, x := range list {
990 func (t *tester) addCmd(dt *distTest, dir string, cmdline ...interface{}) *exec.Cmd {
991 bin, args := flattenCmdline(cmdline)
994 cmd: t.bgDirCmd(dir, bin, args...),
996 t.worklist = append(t.worklist, w)
1000 func (t *tester) iOS() bool {
1001 return goos == "ios"
1004 func (t *tester) out(v string) {
1008 fmt.Println("\n" + t.banner + v)
1011 func (t *tester) extLink() bool {
1012 pair := gohostos + "-" + goarch
1015 "android-arm", "android-arm64",
1016 "darwin-amd64", "darwin-arm64",
1018 "freebsd-386", "freebsd-amd64", "freebsd-arm", "freebsd-riscv64",
1019 "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-loong64", "linux-ppc64le", "linux-mips64", "linux-mips64le", "linux-mips", "linux-mipsle", "linux-riscv64", "linux-s390x",
1020 "netbsd-386", "netbsd-amd64",
1021 "openbsd-386", "openbsd-amd64",
1022 "windows-386", "windows-amd64":
1028 func (t *tester) internalLink() bool {
1029 if gohostos == "dragonfly" {
1030 // linkmode=internal fails on dragonfly since errno is a TLS relocation.
1033 if goos == "android" {
1039 if goos == "windows" && goarch == "arm64" {
1042 // Internally linking cgo is incomplete on some architectures.
1043 // https://golang.org/issue/10373
1044 // https://golang.org/issue/14449
1045 if goarch == "loong64" || goarch == "mips64" || goarch == "mips64le" || goarch == "mips" || goarch == "mipsle" || goarch == "riscv64" {
1049 // linkmode=internal isn't supported.
1055 func (t *tester) internalLinkPIE() bool {
1056 switch goos + "-" + goarch {
1057 case "darwin-amd64", "darwin-arm64",
1058 "linux-amd64", "linux-arm64", "linux-ppc64le",
1060 "windows-amd64", "windows-386", "windows-arm":
1066 func (t *tester) supportedBuildmode(mode string) bool {
1067 pair := goos + "-" + goarch
1075 "darwin-amd64", "darwin-arm64", "ios-arm64",
1076 "linux-amd64", "linux-386", "linux-ppc64le", "linux-riscv64", "linux-s390x",
1078 "windows-amd64", "windows-386":
1084 case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x",
1085 "darwin-amd64", "darwin-arm64",
1087 "android-arm", "android-arm64", "android-386",
1088 "windows-amd64", "windows-386", "windows-arm64":
1094 case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x":
1100 case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-s390x", "linux-ppc64le":
1102 case "darwin-amd64", "darwin-arm64":
1104 case "freebsd-amd64":
1111 "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x",
1112 "android-amd64", "android-arm", "android-arm64", "android-386":
1114 case "darwin-amd64", "darwin-arm64":
1116 case "windows-amd64", "windows-386", "windows-arm":
1122 fatalf("internal error: unknown buildmode %s", mode)
1127 func (t *tester) registerHostTest(name, heading, dir, pkg string) {
1128 t.tests = append(t.tests, distTest{
1131 fn: func(dt *distTest) error {
1133 timelog("start", name)
1134 defer timelog("end", name)
1135 return t.runHostTest(dir, pkg)
1140 func (t *tester) runHostTest(dir, pkg string) error {
1141 out, err := exec.Command(gorootBinGo, "env", "GOEXE", "GOTMPDIR").Output()
1146 parts := strings.Split(string(out), "\n")
1148 return fmt.Errorf("'go env GOEXE GOTMPDIR' output contains <2 lines")
1150 GOEXE := strings.TrimSpace(parts[0])
1151 GOTMPDIR := strings.TrimSpace(parts[1])
1153 f, err := os.CreateTemp(GOTMPDIR, "test.test-*"+GOEXE)
1158 defer os.Remove(f.Name())
1160 cmd := t.dirCmd(dir, t.goTest(), "-c", "-o", f.Name(), pkg)
1161 setEnv(cmd, "GOARCH", gohostarch)
1162 setEnv(cmd, "GOOS", gohostos)
1163 if err := cmd.Run(); err != nil {
1166 return t.dirCmd(dir, f.Name(), "-test.short="+short(), "-test.timeout="+t.timeoutDuration(300).String()).Run()
1169 func (t *tester) cgoTest(dt *distTest) error {
1170 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), ".")
1171 setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=auto")
1173 // Stub out various buildmode=pie tests on alpine until 54354 resolved.
1174 builderName := os.Getenv("GO_BUILDER_NAME")
1175 disablePIE := strings.HasSuffix(builderName, "-alpine")
1177 if t.internalLink() {
1178 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=internal", ".")
1179 setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=internal")
1182 pair := gohostos + "-" + goarch
1184 case "darwin-amd64", "darwin-arm64",
1185 "windows-386", "windows-amd64":
1186 // test linkmode=external, but __thread not supported, so skip testtls.
1190 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), ".")
1191 setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=external")
1193 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s", ".")
1195 if t.supportedBuildmode("pie") && !disablePIE {
1197 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", ".")
1198 if t.internalLink() && t.internalLinkPIE() {
1199 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal", "-tags=internal,internal_pie", ".")
1204 "android-arm", "android-arm64",
1206 "freebsd-386", "freebsd-amd64", "freebsd-arm", "freebsd-riscv64",
1207 "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x",
1208 "netbsd-386", "netbsd-amd64",
1209 "openbsd-386", "openbsd-amd64", "openbsd-arm", "openbsd-arm64", "openbsd-mips64":
1211 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), ".")
1212 setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=external")
1213 // cgo should be able to cope with both -g arguments and colored
1215 setEnv(cmd, "CGO_CFLAGS", "-g0 -fdiagnostics-color")
1217 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=auto", ".")
1218 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=external", ".")
1221 case "aix-ppc64", "netbsd-386", "netbsd-amd64":
1222 // no static linking
1224 // -fPIC compiled tls code will use __tls_get_addr instead
1225 // of __aeabi_read_tp, however, on FreeBSD/ARM, __tls_get_addr
1226 // is implemented in rtld-elf, so -fPIC isn't compatible with
1227 // static linking on FreeBSD/ARM with clang. (cgo depends on
1228 // -fPIC fundamentally.)
1230 cmd := t.dirCmd("misc/cgo/test",
1231 compilerEnvLookup(defaultcc, goos, goarch), "-xc", "-o", "/dev/null", "-static", "-")
1232 cmd.Stdin = strings.NewReader("int main() {}")
1233 if err := cmd.Run(); err != nil {
1234 fmt.Println("No support for static linking found (lacks libc.a?), skip cgo static linking test.")
1236 if goos != "android" {
1237 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", `-linkmode=external -extldflags "-static -pthread"`, ".")
1239 t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), ".")
1240 t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-ldflags", `-linkmode=external`, ".")
1241 if goos != "android" {
1242 t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-ldflags", `-linkmode=external -extldflags "-static -pthread"`, ".")
1243 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`, ".")
1244 // -static in CGO_LDFLAGS triggers a different code path
1245 // than -static in -extldflags, so test both.
1246 // See issue #16651.
1247 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static", ".")
1248 setEnv(cmd, "CGO_LDFLAGS", "-static -pthread")
1252 if t.supportedBuildmode("pie") && !disablePIE {
1253 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", ".")
1254 if t.internalLink() && t.internalLinkPIE() {
1255 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal", "-tags=internal,internal_pie", ".")
1257 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-buildmode=pie", ".")
1258 t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-buildmode=pie", ".")
1266 // run pending test commands, in parallel, emitting headers as appropriate.
1267 // When finished, emit header for nextTest, which is going to run after the
1268 // pending commands are done (and runPending returns).
1269 // A test should call runPending if it wants to make sure that it is not
1270 // running in parallel with earlier tests, or if it has some other reason
1271 // for needing the earlier tests to be done.
1272 func (t *tester) runPending(nextTest *distTest) {
1273 checkNotStale("go", "std")
1274 worklist := t.worklist
1276 for _, w := range worklist {
1277 w.start = make(chan bool)
1278 w.end = make(chan bool)
1281 timelog("skip", w.dt.name)
1282 w.out = []byte(fmt.Sprintf("skipped due to earlier error\n"))
1284 timelog("start", w.dt.name)
1285 w.out, w.err = w.cmd.CombinedOutput()
1287 if isUnsupportedVMASize(w) {
1288 timelog("skip", w.dt.name)
1289 w.out = []byte(fmt.Sprintf("skipped due to unsupported VMA\n"))
1294 timelog("end", w.dt.name)
1302 for ended < len(worklist) {
1303 for started < len(worklist) && started-ended < maxbg {
1304 w := worklist[started]
1306 w.start <- !t.failed || t.keepGoing
1308 w := worklist[ended]
1310 if dt.heading != "" && t.lastHeading != dt.heading {
1311 t.lastHeading = dt.heading
1315 // Assumes all the entries for a single dt are in one worklist.
1318 fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
1322 errprintf("%s\n", strings.Join(w.cmd.Args, " "))
1326 os.Stdout.Write(w.out)
1328 log.Printf("Failed: %v", w.err)
1331 checkNotStale("go", "std")
1333 if t.failed && !t.keepGoing {
1337 if dt := nextTest; dt != nil {
1338 if dt.heading != "" && t.lastHeading != dt.heading {
1339 t.lastHeading = dt.heading
1343 fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
1348 func (t *tester) hasBash() bool {
1350 case "windows", "plan9":
1356 func (t *tester) hasCxx() bool {
1357 cxx, _ := exec.LookPath(compilerEnvLookup(defaultcxx, goos, goarch))
1361 func (t *tester) hasSwig() bool {
1362 swig, err := exec.LookPath("swig")
1367 // Check that swig was installed with Go support by checking
1368 // that a go directory exists inside the swiglib directory.
1369 // See https://golang.org/issue/23469.
1370 output, err := exec.Command(swig, "-go", "-swiglib").Output()
1374 swigDir := strings.TrimSpace(string(output))
1376 _, err = os.Stat(filepath.Join(swigDir, "go"))
1381 // Check that swig has a new enough version.
1382 // See https://golang.org/issue/22858.
1383 out, err := exec.Command(swig, "-version").CombinedOutput()
1388 re := regexp.MustCompile(`[vV]ersion +(\d+)([.]\d+)?([.]\d+)?`)
1389 matches := re.FindSubmatch(out)
1391 // Can't find version number; hope for the best.
1395 major, err := strconv.Atoi(string(matches[1]))
1397 // Can't find version number; hope for the best.
1408 // We have SWIG version 3.x.
1409 if len(matches[2]) > 0 {
1410 minor, err := strconv.Atoi(string(matches[2][1:]))
1420 // We have SWIG version 3.0.x.
1421 if len(matches[3]) > 0 {
1422 patch, err := strconv.Atoi(string(matches[3][1:]))
1435 func (t *tester) raceDetectorSupported() bool {
1436 if gohostos != goos {
1442 if !raceDetectorSupported(goos, goarch) {
1445 // The race detector doesn't work on Alpine Linux:
1446 // golang.org/issue/14481
1447 if isAlpineLinux() {
1450 // NetBSD support is unfinished.
1451 // golang.org/issue/26403
1452 if goos == "netbsd" {
1458 func isAlpineLinux() bool {
1459 if runtime.GOOS != "linux" {
1462 fi, err := os.Lstat("/etc/alpine-release")
1463 return err == nil && fi.Mode().IsRegular()
1466 func (t *tester) runFlag(rx string) string {
1473 func (t *tester) raceTest(dt *distTest) error {
1474 t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("Output"), "runtime/race")
1475 t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace|TestTypeRace|TestFdRace|TestFdReadRace|TestFileCloseRace"), "flag", "net", "os", "os/exec", "encoding/gob")
1476 // We don't want the following line, because it
1477 // slows down all.bash (by 10 seconds on my laptop).
1478 // The race builder should catch any error here, but doesn't.
1479 // TODO(iant): Figure out how to catch this.
1480 // t.addCmd(dt, "src", t.goTest(), "-race", "-run=TestParallelTest", "cmd/go")
1482 // Building misc/cgo/test takes a long time.
1483 // There are already cgo-enabled packages being tested with the race detector.
1484 // We shouldn't need to redo all of misc/cgo/test too.
1485 // The race buildler will take care of this.
1486 // cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-race")
1487 // setEnv(cmd, "GOTRACEBACK", "2")
1490 // Test with external linking; see issue 9133.
1491 t.addCmd(dt, "src", t.goTest(), "-race", "-ldflags=-linkmode=external", t.runFlag("TestParse|TestEcho|TestStdinCloseRace"), "flag", "os/exec")
1496 var runtest struct {
1502 func (t *tester) testDirTest(dt *distTest, shard, shards int) error {
1504 f, err := os.CreateTemp("", "runtest-*.exe") // named exe for Windows, but harmless elsewhere
1511 runtest.exe = f.Name()
1513 os.Remove(runtest.exe)
1516 cmd := t.dirCmd("test", "go", "build", "-o", runtest.exe, "run.go")
1517 setEnv(cmd, "GOOS", gohostos)
1518 setEnv(cmd, "GOARCH", gohostarch)
1519 runtest.err = cmd.Run()
1521 if runtest.err != nil {
1527 t.addCmd(dt, "test", runtest.exe,
1528 fmt.Sprintf("--shard=%d", shard),
1529 fmt.Sprintf("--shards=%d", shards),
1534 // cgoPackages is the standard packages that use cgo.
1535 var cgoPackages = []string{
1540 var funcBenchmark = []byte("\nfunc Benchmark")
1542 // packageHasBenchmarks reports whether pkg has benchmarks.
1543 // On any error, it conservatively returns true.
1545 // This exists just to eliminate work on the builders, since compiling
1546 // a test in race mode just to discover it has no benchmarks costs a
1547 // second or two per package, and this function returns false for
1548 // about 100 packages.
1549 func (t *tester) packageHasBenchmarks(pkg string) bool {
1550 pkgDir := filepath.Join(goroot, "src", pkg)
1551 d, err := os.Open(pkgDir)
1553 return true // conservatively
1556 names, err := d.Readdirnames(-1)
1558 return true // conservatively
1560 for _, name := range names {
1561 if !strings.HasSuffix(name, "_test.go") {
1564 slurp, err := os.ReadFile(filepath.Join(pkgDir, name))
1566 return true // conservatively
1568 if bytes.Contains(slurp, funcBenchmark) {
1575 // makeGOROOTUnwritable makes all $GOROOT files & directories non-writable to
1576 // check that no tests accidentally write to $GOROOT.
1577 func (t *tester) makeGOROOTUnwritable() (undo func()) {
1578 dir := os.Getenv("GOROOT")
1580 panic("GOROOT not set")
1583 type pathMode struct {
1587 var dirs []pathMode // in lexical order
1590 for i := range dirs {
1591 os.Chmod(dirs[i].path, dirs[i].mode) // best effort
1595 gocache := os.Getenv("GOCACHE")
1597 panic("GOCACHE not set")
1599 gocacheSubdir, _ := filepath.Rel(dir, gocache)
1601 // Note: Can't use WalkDir here, because this has to compile with Go 1.4.
1602 filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
1603 if suffix := strings.TrimPrefix(path, dir+string(filepath.Separator)); suffix != "" {
1604 if suffix == gocacheSubdir {
1605 // Leave GOCACHE writable: we may need to write test binaries into it.
1606 return filepath.SkipDir
1608 if suffix == ".git" {
1609 // Leave Git metadata in whatever state it was in. It may contain a lot
1610 // of files, and it is highly unlikely that a test will try to modify
1611 // anything within that directory.
1612 return filepath.SkipDir
1617 if mode&0222 != 0 && (mode.IsDir() || mode.IsRegular()) {
1618 dirs = append(dirs, pathMode{path, mode})
1624 // Run over list backward to chmod children before parents.
1625 for i := len(dirs) - 1; i >= 0; i-- {
1626 err := os.Chmod(dirs[i].path, dirs[i].mode&^0222)
1628 dirs = dirs[i:] // Only undo what we did so far.
1630 fatalf("failed to make GOROOT read-only: %v", err)
1637 // raceDetectorSupported is a copy of the function
1638 // internal/platform.RaceDetectorSupported, which can't be used here
1639 // because cmd/dist has to be buildable by Go 1.4.
1640 // The race detector only supports 48-bit VMA on arm64. But we don't have
1641 // a good solution to check VMA size(See https://golang.org/issue/29948)
1642 // raceDetectorSupported will always return true for arm64. But race
1643 // detector tests may abort on non 48-bit VMA configuration, the tests
1644 // will be marked as "skipped" in this case.
1645 func raceDetectorSupported(goos, goarch string) bool {
1648 return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64" || goarch == "s390x"
1650 return goarch == "amd64" || goarch == "arm64"
1651 case "freebsd", "netbsd", "openbsd", "windows":
1652 return goarch == "amd64"
1658 // isUnsupportedVMASize reports whether the failure is caused by an unsupported
1659 // VMA for the race detector (for example, running the race detector on an
1660 // arm64 machine configured with 39-bit VMA)
1661 func isUnsupportedVMASize(w *work) bool {
1662 unsupportedVMA := []byte("unsupported VMA range")
1663 return w.dt.name == "race" && bytes.Contains(w.out, unsupportedVMA)
1666 // isEnvSet reports whether the environment variable evar is
1667 // set in the environment.
1668 func isEnvSet(evar string) bool {
1669 evarEq := evar + "="
1670 for _, e := range os.Environ() {
1671 if strings.HasPrefix(e, evarEq) {