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.
4
5package main
6
7import (
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
26func 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) // any number of args
42	if noRebuild {
43		t.rebuild = false
44	}
45
46	t.run()
47}
48
49// tester executes cmdtest.
50type tester struct {
51	race        bool
52	listMode    bool
53	rebuild     bool
54	failed      bool
55	keepGoing   bool
56	compileOnly bool // just try to compile all tests, but no need to run
57	runRxStr    string
58	runRx       *regexp.Regexp
59	runRxWant   bool     // want runRx to match (true) or not match (false)
60	runNames    []string // tests to run, exclusive with runRx; empty means all
61	banner      string   // prefix, or "" for none
62	lastHeading string   // last dir heading printed
63
64	cgoEnabled bool
65	partial    bool
66	haveTime   bool // the 'time' binary is available
67
68	tests        []distTest
69	timeoutScale int
70
71	worklist []*work
72}
73
74type work struct {
75	dt    *distTest
76	cmd   *exec.Cmd
77	start chan bool
78	out   []byte
79	err   error
80	end   chan bool
81}
82
83// A distTest is a test run by dist test.
84// Each test has a unique name and belongs to a group (heading)
85type distTest struct {
86	name    string // unique test name; may be filtered with -run flag
87	heading string // group section; this header is printed before the test is run.
88	fn      func(*distTest) error
89}
90
91func (t *tester) run() {
92	timelog("start", "dist test")
93
94	var exeSuffix string
95	if goos == "windows" {
96		exeSuffix = ".exe"
97	}
98	if _, err := os.Stat(filepath.Join(gobin, "go"+exeSuffix)); err == nil {
99		os.Setenv("PATH", fmt.Sprintf("%s%c%s", gobin, os.PathListSeparator, os.Getenv("PATH")))
100	}
101
102	cmd := exec.Command("go", "env", "CGO_ENABLED")
103	cmd.Stderr = new(bytes.Buffer)
104	slurp, err := cmd.Output()
105	if err != nil {
106		fatalf("Error running go env CGO_ENABLED: %v\n%s", err, cmd.Stderr)
107	}
108	t.cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(slurp)))
109	if flag.NArg() > 0 && t.runRxStr != "" {
110		fatalf("the -run regular expression flag is mutually exclusive with test name arguments")
111	}
112
113	t.runNames = flag.Args()
114
115	if t.hasBash() {
116		if _, err := exec.LookPath("time"); err == nil {
117			t.haveTime = true
118		}
119	}
120
121	// Set GOTRACEBACK to system if the user didn't set a level explicitly.
122	// Since we're running tests for Go, we want as much detail as possible
123	// if something goes wrong.
124	//
125	// Set it before running any commands just in case something goes wrong.
126	if ok := isEnvSet("GOTRACEBACK"); !ok {
127		if err := os.Setenv("GOTRACEBACK", "system"); err != nil {
128			if t.keepGoing {
129				log.Printf("Failed to set GOTRACEBACK: %v", err)
130			} else {
131				fatalf("Failed to set GOTRACEBACK: %v", err)
132			}
133		}
134	}
135
136	if t.rebuild {
137		t.out("Building packages and commands.")
138		// Force rebuild the whole toolchain.
139		goInstall("go", append([]string{"-a", "-i"}, toolchain...)...)
140	}
141
142	if !t.listMode {
143		if os.Getenv("GO_BUILDER_NAME") == "" {
144			// Complete rebuild bootstrap, even with -no-rebuild.
145			// If everything is up-to-date, this is a no-op.
146			// If everything is not up-to-date, the first checkNotStale
147			// during the test process will kill the tests, so we might
148			// as well install the world.
149			// Now that for example "go install cmd/compile" does not
150			// also install runtime (you need "go install -i cmd/compile"
151			// for that), it's easy for previous workflows like
152			// "rebuild the compiler and then run run.bash"
153			// to break if we don't automatically refresh things here.
154			// Rebuilding is a shortened bootstrap.
155			// See cmdbootstrap for a description of the overall process.
156			goInstall("go", append([]string{"-i"}, toolchain...)...)
157			goInstall("go", append([]string{"-i"}, toolchain...)...)
158			goInstall("go", "std", "cmd")
159		} else {
160			// The Go builder infrastructure should always begin running tests from a
161			// clean, non-stale state, so there is no need to rebuild the world.
162			// Instead, we can just check that it is not stale, which may be less
163			// expensive (and is also more likely to catch bugs in the builder
164			// implementation).
165			willTest := []string{"std"}
166			if t.shouldTestCmd() {
167				willTest = append(willTest, "cmd")
168			}
169			checkNotStale("go", willTest...)
170		}
171	}
172
173	t.timeoutScale = 1
174	switch goarch {
175	case "arm":
176		t.timeoutScale = 2
177	case "mips", "mipsle", "mips64", "mips64le":
178		t.timeoutScale = 4
179	}
180	if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
181		t.timeoutScale, err = strconv.Atoi(s)
182		if err != nil {
183			fatalf("failed to parse $GO_TEST_TIMEOUT_SCALE = %q as integer: %v", s, err)
184		}
185	}
186
187	if t.runRxStr != "" {
188		if t.runRxStr[0] == '!' {
189			t.runRxWant = false
190			t.runRxStr = t.runRxStr[1:]
191		} else {
192			t.runRxWant = true
193		}
194		t.runRx = regexp.MustCompile(t.runRxStr)
195	}
196
197	t.registerTests()
198	if t.listMode {
199		for _, tt := range t.tests {
200			fmt.Println(tt.name)
201		}
202		return
203	}
204
205	for _, name := range t.runNames {
206		if !t.isRegisteredTestName(name) {
207			fatalf("unknown test %q", name)
208		}
209	}
210
211	// On a few builders, make GOROOT unwritable to catch tests writing to it.
212	if strings.HasPrefix(os.Getenv("GO_BUILDER_NAME"), "linux-") {
213		if os.Getuid() == 0 {
214			// Don't bother making GOROOT unwritable:
215			// we're running as root, so permissions would have no effect.
216		} else {
217			xatexit(t.makeGOROOTUnwritable())
218		}
219	}
220
221	for _, dt := range t.tests {
222		if !t.shouldRunTest(dt.name) {
223			t.partial = true
224			continue
225		}
226		dt := dt // dt used in background after this iteration
227		if err := dt.fn(&dt); err != nil {
228			t.runPending(&dt) // in case that hasn't been done yet
229			t.failed = true
230			if t.keepGoing {
231				log.Printf("Failed: %v", err)
232			} else {
233				fatalf("Failed: %v", err)
234			}
235		}
236	}
237	t.runPending(nil)
238	timelog("end", "dist test")
239
240	if t.failed {
241		fmt.Println("\nFAILED")
242		xexit(1)
243	} else if incomplete[goos+"/"+goarch] {
244		// The test succeeded, but consider it as failed so we don't
245		// forget to remove the port from the incomplete map once the
246		// port is complete.
247		fmt.Println("\nFAILED (incomplete port)")
248		xexit(1)
249	} else if t.partial {
250		fmt.Println("\nALL TESTS PASSED (some were excluded)")
251	} else {
252		fmt.Println("\nALL TESTS PASSED")
253	}
254}
255
256func (t *tester) shouldRunTest(name string) bool {
257	if t.runRx != nil {
258		return t.runRx.MatchString(name) == t.runRxWant
259	}
260	if len(t.runNames) == 0 {
261		return true
262	}
263	for _, runName := range t.runNames {
264		if runName == name {
265			return true
266		}
267	}
268	return false
269}
270
271// short returns a -short flag value to use with 'go test'
272// or a test binary for tests intended to run in short mode.
273// It returns "true", unless the environment variable
274// GO_TEST_SHORT is set to a non-empty, false-ish string.
275//
276// This environment variable is meant to be an internal
277// detail between the Go build system and cmd/dist for
278// the purpose of longtest builders, and is not intended
279// for use by users. See golang.org/issue/12508.
280func short() string {
281	if v := os.Getenv("GO_TEST_SHORT"); v != "" {
282		short, err := strconv.ParseBool(v)
283		if err != nil {
284			fatalf("invalid GO_TEST_SHORT %q: %v", v, err)
285		}
286		if !short {
287			return "false"
288		}
289	}
290	return "true"
291}
292
293// goTest returns the beginning of the go test command line.
294// Callers should use goTest and then pass flags overriding these
295// defaults as later arguments in the command line.
296func (t *tester) goTest() []string {
297	return []string{
298		"go", "test", "-short=" + short(), "-count=1", t.tags(), t.runFlag(""),
299	}
300}
301
302func (t *tester) tags() string {
303	if t.iOS() {
304		return "-tags=lldb"
305	}
306	return "-tags="
307}
308
309// timeoutDuration converts the provided number of seconds into a
310// time.Duration, scaled by the t.timeoutScale factor.
311func (t *tester) timeoutDuration(sec int) time.Duration {
312	return time.Duration(sec) * time.Second * time.Duration(t.timeoutScale)
313}
314
315// timeout returns the "-timeout=" string argument to "go test" given
316// the number of seconds of timeout. It scales it by the
317// t.timeoutScale factor.
318func (t *tester) timeout(sec int) string {
319	return "-timeout=" + t.timeoutDuration(sec).String()
320}
321
322// ranGoTest and stdMatches are state closed over by the stdlib
323// testing func in registerStdTest below. The tests are run
324// sequentially, so there's no need for locks.
325//
326// ranGoBench and benchMatches are the same, but are only used
327// in -race mode.
328var (
329	ranGoTest  bool
330	stdMatches []string
331
332	ranGoBench   bool
333	benchMatches []string
334)
335
336func (t *tester) registerStdTest(pkg string, useG3 bool) {
337	heading := "Testing packages."
338	testPrefix := "go_test:"
339	gcflags := gogcflags
340	if useG3 {
341		heading = "Testing packages with -G=3."
342		testPrefix = "go_test_g3:"
343		gcflags += " -G=3"
344	}
345
346	testName := testPrefix + pkg
347	if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant {
348		stdMatches = append(stdMatches, pkg)
349	}
350
351	t.tests = append(t.tests, distTest{
352		name:    testName,
353		heading: heading,
354		fn: func(dt *distTest) error {
355			if ranGoTest {
356				return nil
357			}
358			t.runPending(dt)
359			timelog("start", dt.name)
360			defer timelog("end", dt.name)
361			ranGoTest = true
362
363			timeoutSec := 180
364			for _, pkg := range stdMatches {
365				if pkg == "cmd/go" {
366					timeoutSec *= 3
367					break
368				}
369			}
370			// Special case for our slow cross-compiled
371			// qemu builders:
372			if t.shouldUsePrecompiledStdTest() {
373				return t.runPrecompiledStdTest(t.timeoutDuration(timeoutSec))
374			}
375			args := []string{
376				"test",
377				"-short=" + short(),
378				t.tags(),
379				t.timeout(timeoutSec),
380				"-gcflags=all=" + gcflags,
381			}
382			if t.race {
383				args = append(args, "-race")
384			}
385			if t.compileOnly {
386				args = append(args, "-run=^$")
387			}
388			args = append(args, stdMatches...)
389			cmd := exec.Command("go", args...)
390			cmd.Stdout = os.Stdout
391			cmd.Stderr = os.Stderr
392			return cmd.Run()
393		},
394	})
395}
396
397func (t *tester) registerRaceBenchTest(pkg string) {
398	testName := "go_test_bench:" + pkg
399	if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant {
400		benchMatches = append(benchMatches, pkg)
401	}
402	t.tests = append(t.tests, distTest{
403		name:    testName,
404		heading: "Running benchmarks briefly.",
405		fn: func(dt *distTest) error {
406			if ranGoBench {
407				return nil
408			}
409			t.runPending(dt)
410			timelog("start", dt.name)
411			defer timelog("end", dt.name)
412			ranGoBench = true
413			args := []string{
414				"test",
415				"-short=" + short(),
416				"-race",
417				t.timeout(1200), // longer timeout for race with benchmarks
418				"-run=^$",       // nothing. only benchmarks.
419				"-benchtime=.1s",
420				"-cpu=4",
421			}
422			if !t.compileOnly {
423				args = append(args, "-bench=.*")
424			}
425			args = append(args, benchMatches...)
426			cmd := exec.Command("go", args...)
427			cmd.Stdout = os.Stdout
428			cmd.Stderr = os.Stderr
429			return cmd.Run()
430		},
431	})
432}
433
434// stdOutErrAreTerminals is defined in test_linux.go, to report
435// whether stdout & stderr are terminals.
436var stdOutErrAreTerminals func() bool
437
438func (t *tester) registerTests() {
439	// Fast path to avoid the ~1 second of `go list std cmd` when
440	// the caller lists specific tests to run. (as the continuous
441	// build coordinator does).
442	if len(t.runNames) > 0 {
443		for _, name := range t.runNames {
444			if strings.HasPrefix(name, "go_test:") {
445				t.registerStdTest(strings.TrimPrefix(name, "go_test:"), false)
446			}
447			if strings.HasPrefix(name, "go_test_g3:") {
448				t.registerStdTest(strings.TrimPrefix(name, "go_test_g3:"), true)
449			}
450			if strings.HasPrefix(name, "go_test_bench:") {
451				t.registerRaceBenchTest(strings.TrimPrefix(name, "go_test_bench:"))
452			}
453		}
454	} else {
455		// Use a format string to only list packages and commands that have tests.
456		const format = "{{if (or .TestGoFiles .XTestGoFiles)}}{{.ImportPath}}{{end}}"
457		cmd := exec.Command("go", "list", "-f", format)
458		if t.race {
459			cmd.Args = append(cmd.Args, "-tags=race")
460		}
461		cmd.Args = append(cmd.Args, "std")
462		if t.shouldTestCmd() {
463			cmd.Args = append(cmd.Args, "cmd")
464		}
465		cmd.Stderr = new(bytes.Buffer)
466		all, err := cmd.Output()
467		if err != nil {
468			fatalf("Error running go list std cmd: %v:\n%s", err, cmd.Stderr)
469		}
470		pkgs := strings.Fields(string(all))
471		if false {
472			// Disable -G=3 option for standard tests for now, since
473			// they are flaky on the builder.
474			for _, pkg := range pkgs {
475				t.registerStdTest(pkg, true /* -G=3 flag */)
476			}
477		}
478		for _, pkg := range pkgs {
479			t.registerStdTest(pkg, false)
480		}
481		if t.race {
482			for _, pkg := range pkgs {
483				if t.packageHasBenchmarks(pkg) {
484					t.registerRaceBenchTest(pkg)
485				}
486			}
487		}
488	}
489
490	// Test the os/user package in the pure-Go mode too.
491	if !t.compileOnly {
492		t.tests = append(t.tests, distTest{
493			name:    "osusergo",
494			heading: "os/user with tag osusergo",
495			fn: func(dt *distTest) error {
496				t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-tags=osusergo", "os/user")
497				return nil
498			},
499		})
500	}
501
502	// Test ios/amd64 for the iOS simulator.
503	if goos == "darwin" && goarch == "amd64" && t.cgoEnabled {
504		t.tests = append(t.tests, distTest{
505			name:    "amd64ios",
506			heading: "GOOS=ios on darwin/amd64",
507			fn: func(dt *distTest) error {
508				cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-run=SystemRoots", "crypto/x509")
509				setEnv(cmd, "GOOS", "ios")
510				setEnv(cmd, "CGO_ENABLED", "1")
511				return nil
512			},
513		})
514	}
515
516	if t.race {
517		return
518	}
519
520	// Runtime CPU tests.
521	if !t.compileOnly && goos != "js" { // js can't handle -cpu != 1
522		testName := "runtime:cpu124"
523		t.tests = append(t.tests, distTest{
524			name:    testName,
525			heading: "GOMAXPROCS=2 runtime -cpu=1,2,4 -quick",
526			fn: func(dt *distTest) error {
527				cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(300), "runtime", "-cpu=1,2,4", "-quick")
528				// We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
529				// creation of first goroutines and first garbage collections in the parallel setting.
530				setEnv(cmd, "GOMAXPROCS", "2")
531				return nil
532			},
533		})
534	}
535
536	// This test needs its stdout/stderr to be terminals, so we don't run it from cmd/go's tests.
537	// See issue 18153.
538	if goos == "linux" {
539		t.tests = append(t.tests, distTest{
540			name:    "cmd_go_test_terminal",
541			heading: "cmd/go terminal test",
542			fn: func(dt *distTest) error {
543				t.runPending(dt)
544				timelog("start", dt.name)
545				defer timelog("end", dt.name)
546				if !stdOutErrAreTerminals() {
547					fmt.Println("skipping terminal test; stdout/stderr not terminals")
548					return nil
549				}
550				cmd := exec.Command("go", "test")
551				setDir(cmd, filepath.Join(os.Getenv("GOROOT"), "src/cmd/go/testdata/testterminal18153"))
552				cmd.Stdout = os.Stdout
553				cmd.Stderr = os.Stderr
554				return cmd.Run()
555			},
556		})
557	}
558
559	// On the builders only, test that a moved GOROOT still works.
560	// Fails on iOS because CC_FOR_TARGET refers to clangwrap.sh
561	// in the unmoved GOROOT.
562	// Fails on Android and js/wasm with an exec format error.
563	// Fails on plan9 with "cannot find GOROOT" (issue #21016).
564	if os.Getenv("GO_BUILDER_NAME") != "" && goos != "android" && !t.iOS() && goos != "plan9" && goos != "js" {
565		t.tests = append(t.tests, distTest{
566			name:    "moved_goroot",
567			heading: "moved GOROOT",
568			fn: func(dt *distTest) error {
569				t.runPending(dt)
570				timelog("start", dt.name)
571				defer timelog("end", dt.name)
572				moved := goroot + "-moved"
573				if err := os.Rename(goroot, moved); err != nil {
574					if goos == "windows" {
575						// Fails on Windows (with "Access is denied") if a process
576						// or binary is in this directory. For instance, using all.bat
577						// when run from c:\workdir\go\src fails here
578						// if GO_BUILDER_NAME is set. Our builders invoke tests
579						// a different way which happens to work when sharding
580						// tests, but we should be tolerant of the non-sharded
581						// all.bat case.
582						log.Printf("skipping test on Windows")
583						return nil
584					}
585					return err
586				}
587
588				// Run `go test fmt` in the moved GOROOT, without explicitly setting
589				// GOROOT in the environment. The 'go' command should find itself.
590				cmd := exec.Command(filepath.Join(moved, "bin", "go"), "test", "fmt")
591				cmd.Stdout = os.Stdout
592				cmd.Stderr = os.Stderr
593				unsetEnv(cmd, "GOROOT")
594				unsetEnv(cmd, "GOCACHE") // TODO(bcmills): ...why‽
595				err := cmd.Run()
596
597				if rerr := os.Rename(moved, goroot); rerr != nil {
598					fatalf("failed to restore GOROOT: %v", rerr)
599				}
600				return err
601			},
602		})
603	}
604
605	// Test that internal linking of standard packages does not
606	// require libgcc. This ensures that we can install a Go
607	// release on a system that does not have a C compiler
608	// installed and still build Go programs (that don't use cgo).
609	for _, pkg := range cgoPackages {
610		if !t.internalLink() {
611			break
612		}
613
614		// ARM libgcc may be Thumb, which internal linking does not support.
615		if goarch == "arm" {
616			break
617		}
618
619		pkg := pkg
620		var run string
621		if pkg == "net" {
622			run = "TestTCPStress"
623		}
624		t.tests = append(t.tests, distTest{
625			name:    "nolibgcc:" + pkg,
626			heading: "Testing without libgcc.",
627			fn: func(dt *distTest) error {
628				// What matters is that the tests build and start up.
629				// Skip expensive tests, especially x509 TestSystemRoots.
630				t.addCmd(dt, "src", t.goTest(), "-ldflags=-linkmode=internal -libgcc=none", "-run=^Test[^CS]", pkg, t.runFlag(run))
631				return nil
632			},
633		})
634	}
635
636	// Test internal linking of PIE binaries where it is supported.
637	if t.internalLinkPIE() {
638		t.tests = append(t.tests, distTest{
639			name:    "pie_internal",
640			heading: "internal linking of -buildmode=pie",
641			fn: func(dt *distTest) error {
642				t.addCmd(dt, "src", t.goTest(), "reflect", "-buildmode=pie", "-ldflags=-linkmode=internal", t.timeout(60))
643				return nil
644			},
645		})
646		// Also test a cgo package.
647		if t.cgoEnabled && t.internalLink() {
648			t.tests = append(t.tests, distTest{
649				name:    "pie_internal_cgo",
650				heading: "internal linking of -buildmode=pie",
651				fn: func(dt *distTest) error {
652					t.addCmd(dt, "src", t.goTest(), "os/user", "-buildmode=pie", "-ldflags=-linkmode=internal", t.timeout(60))
653					return nil
654				},
655			})
656		}
657	}
658
659	// sync tests
660	if goos != "js" { // js doesn't support -cpu=10
661		t.tests = append(t.tests, distTest{
662			name:    "sync_cpu",
663			heading: "sync -cpu=10",
664			fn: func(dt *distTest) error {
665				t.addCmd(dt, "src", t.goTest(), "sync", t.timeout(120), "-cpu=10", t.runFlag(""))
666				return nil
667			},
668		})
669	}
670
671	if t.raceDetectorSupported() {
672		t.tests = append(t.tests, distTest{
673			name:    "race",
674			heading: "Testing race detector",
675			fn:      t.raceTest,
676		})
677	}
678
679	if t.cgoEnabled && !t.iOS() {
680		// Disabled on iOS. golang.org/issue/15919
681		t.registerHostTest("cgo_stdio", "../misc/cgo/stdio", "misc/cgo/stdio", ".")
682		t.registerHostTest("cgo_life", "../misc/cgo/life", "misc/cgo/life", ".")
683		fortran := os.Getenv("FC")
684		if fortran == "" {
685			fortran, _ = exec.LookPath("gfortran")
686		}
687		if t.hasBash() && goos != "android" && fortran != "" {
688			t.tests = append(t.tests, distTest{
689				name:    "cgo_fortran",
690				heading: "../misc/cgo/fortran",
691				fn: func(dt *distTest) error {
692					t.addCmd(dt, "misc/cgo/fortran", "./test.bash", fortran)
693					return nil
694				},
695			})
696		}
697		if t.hasSwig() && goos != "android" {
698			t.tests = append(t.tests, distTest{
699				name:    "swig_stdio",
700				heading: "../misc/swig/stdio",
701				fn: func(dt *distTest) error {
702					t.addCmd(dt, "misc/swig/stdio", t.goTest())
703					return nil
704				},
705			})
706			if t.hasCxx() {
707				t.tests = append(t.tests,
708					distTest{
709						name:    "swig_callback",
710						heading: "../misc/swig/callback",
711						fn: func(dt *distTest) error {
712							t.addCmd(dt, "misc/swig/callback", t.goTest())
713							return nil
714						},
715					},
716					distTest{
717						name:    "swig_callback_lto",
718						heading: "../misc/swig/callback",
719						fn: func(dt *distTest) error {
720							cmd := t.addCmd(dt, "misc/swig/callback", t.goTest())
721							setEnv(cmd, "CGO_CFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
722							setEnv(cmd, "CGO_CXXFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
723							setEnv(cmd, "CGO_LDFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
724							return nil
725						},
726					},
727				)
728			}
729		}
730	}
731	if t.cgoEnabled {
732		t.tests = append(t.tests, distTest{
733			name:    "cgo_test",
734			heading: "../misc/cgo/test",
735			fn:      t.cgoTest,
736		})
737	}
738
739	// Don't run these tests with $GO_GCFLAGS because most of them
740	// assume that they can run "go install" with no -gcflags and not
741	// recompile the entire standard library. If make.bash ran with
742	// special -gcflags, that's not true.
743	if t.cgoEnabled && gogcflags == "" {
744		t.registerHostTest("testgodefs", "../misc/cgo/testgodefs", "misc/cgo/testgodefs", ".")
745
746		t.registerTest("testso", "../misc/cgo/testso", t.goTest(), t.timeout(600), ".")
747		t.registerTest("testsovar", "../misc/cgo/testsovar", t.goTest(), t.timeout(600), ".")
748		if t.supportedBuildmode("c-archive") {
749			t.registerHostTest("testcarchive", "../misc/cgo/testcarchive", "misc/cgo/testcarchive", ".")
750		}
751		if t.supportedBuildmode("c-shared") {
752			t.registerHostTest("testcshared", "../misc/cgo/testcshared", "misc/cgo/testcshared", ".")
753		}
754		if t.supportedBuildmode("shared") {
755			t.registerTest("testshared", "../misc/cgo/testshared", t.goTest(), t.timeout(600), ".")
756		}
757		if t.supportedBuildmode("plugin") {
758			t.registerTest("testplugin", "../misc/cgo/testplugin", t.goTest(), t.timeout(600), ".")
759		}
760		if gohostos == "linux" && goarch == "amd64" {
761			t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", ".")
762		}
763		if goos == "linux" && goarch != "ppc64le" {
764			// because syscall.SysProcAttr struct used in misc/cgo/testsanitizers is only built on linux.
765			// Some inconsistent failures happen on ppc64le so disable for now.
766			t.registerHostTest("testsanitizers", "../misc/cgo/testsanitizers", "misc/cgo/testsanitizers", ".")
767		}
768		if t.hasBash() && goos != "android" && !t.iOS() && gohostos != "windows" {
769			t.registerHostTest("cgo_errors", "../misc/cgo/errors", "misc/cgo/errors", ".")
770		}
771		if gohostos == "linux" && t.extLink() {
772			t.registerTest("testsigfwd", "../misc/cgo/testsigfwd", "go", "run", ".")
773		}
774	}
775
776	if goos != "android" && !t.iOS() {
777		// There are no tests in this directory, only benchmarks.
778		// Check that the test binary builds but don't bother running it.
779		// (It has init-time work to set up for the benchmarks that is not worth doing unnecessarily.)
780		t.registerTest("bench_go1", "../test/bench/go1", t.goTest(), "-c", "-o="+os.DevNull)
781	}
782	if goos != "android" && !t.iOS() {
783		// Only start multiple test dir shards on builders,
784		// where they get distributed to multiple machines.
785		// See issues 20141 and 31834.
786		nShards := 1
787		if os.Getenv("GO_BUILDER_NAME") != "" {
788			nShards = 10
789		}
790		if n, err := strconv.Atoi(os.Getenv("GO_TEST_SHARDS")); err == nil {
791			nShards = n
792		}
793		for shard := 0; shard < nShards; shard++ {
794			shard := shard
795			t.tests = append(t.tests, distTest{
796				name:    fmt.Sprintf("test:%d_%d", shard, nShards),
797				heading: "../test",
798				fn:      func(dt *distTest) error { return t.testDirTest(dt, shard, nShards) },
799			})
800		}
801	}
802	// Only run the API check on fast development platforms. Android, iOS, and JS
803	// are always cross-compiled, and the filesystems on our only plan9 builders
804	// are too slow to complete in a reasonable timeframe. Every platform checks
805	// the API on every GOOS/GOARCH/CGO_ENABLED combination anyway, so we really
806	// only need to run this check once anywhere to get adequate coverage.
807	if goos != "android" && !t.iOS() && goos != "js" && goos != "plan9" {
808		t.tests = append(t.tests, distTest{
809			name:    "api",
810			heading: "API check",
811			fn: func(dt *distTest) error {
812				if t.compileOnly {
813					t.addCmd(dt, "src", "go", "build", "-o", os.DevNull, filepath.Join(goroot, "src/cmd/api/run.go"))
814					return nil
815				}
816				t.addCmd(dt, "src", "go", "run", filepath.Join(goroot, "src/cmd/api/run.go"))
817				return nil
818			},
819		})
820	}
821
822	// Ensure that the toolchain can bootstrap itself.
823	// This test adds another ~45s to all.bash if run sequentially, so run it only on the builders.
824	if os.Getenv("GO_BUILDER_NAME") != "" && goos != "android" && !t.iOS() {
825		t.registerHostTest("reboot", "../misc/reboot", "misc/reboot", ".")
826	}
827}
828
829// isRegisteredTestName reports whether a test named testName has already
830// been registered.
831func (t *tester) isRegisteredTestName(testName string) bool {
832	for _, tt := range t.tests {
833		if tt.name == testName {
834			return true
835		}
836	}
837	return false
838}
839
840func (t *tester) registerTest1(seq bool, name, dirBanner string, cmdline ...interface{}) {
841	bin, args := flattenCmdline(cmdline)
842	if bin == "time" && !t.haveTime {
843		bin, args = args[0], args[1:]
844	}
845	if t.isRegisteredTestName(name) {
846		panic("duplicate registered test name " + name)
847	}
848	t.tests = append(t.tests, distTest{
849		name:    name,
850		heading: dirBanner,
851		fn: func(dt *distTest) error {
852			if seq {
853				t.runPending(dt)
854				timelog("start", name)
855				defer timelog("end", name)
856				return t.dirCmd(filepath.Join(goroot, "src", dirBanner), bin, args).Run()
857			}
858			t.addCmd(dt, filepath.Join(goroot, "src", dirBanner), bin, args)
859			return nil
860		},
861	})
862}
863
864func (t *tester) registerTest(name, dirBanner string, cmdline ...interface{}) {
865	t.registerTest1(false, name, dirBanner, cmdline...)
866}
867
868func (t *tester) registerSeqTest(name, dirBanner string, cmdline ...interface{}) {
869	t.registerTest1(true, name, dirBanner, cmdline...)
870}
871
872func (t *tester) bgDirCmd(dir, bin string, args ...string) *exec.Cmd {
873	cmd := exec.Command(bin, args...)
874	if filepath.IsAbs(dir) {
875		setDir(cmd, dir)
876	} else {
877		setDir(cmd, filepath.Join(goroot, dir))
878	}
879	return cmd
880}
881
882func (t *tester) dirCmd(dir string, cmdline ...interface{}) *exec.Cmd {
883	bin, args := flattenCmdline(cmdline)
884	cmd := t.bgDirCmd(dir, bin, args...)
885	cmd.Stdout = os.Stdout
886	cmd.Stderr = os.Stderr
887	if vflag > 1 {
888		errprintf("%s\n", strings.Join(cmd.Args, " "))
889	}
890	return cmd
891}
892
893// flattenCmdline flattens a mixture of string and []string as single list
894// and then interprets it as a command line: first element is binary, then args.
895func flattenCmdline(cmdline []interface{}) (bin string, args []string) {
896	var list []string
897	for _, x := range cmdline {
898		switch x := x.(type) {
899		case string:
900			list = append(list, x)
901		case []string:
902			list = append(list, x...)
903		default:
904			panic("invalid addCmd argument type: " + reflect.TypeOf(x).String())
905		}
906	}
907
908	// The go command is too picky about duplicated flags.
909	// Drop all but the last of the allowed duplicated flags.
910	drop := make([]bool, len(list))
911	have := map[string]int{}
912	for i := 1; i < len(list); i++ {
913		j := strings.Index(list[i], "=")
914		if j < 0 {
915			continue
916		}
917		flag := list[i][:j]
918		switch flag {
919		case "-run", "-tags":
920			if have[flag] != 0 {
921				drop[have[flag]] = true
922			}
923			have[flag] = i
924		}
925	}
926	out := list[:0]
927	for i, x := range list {
928		if !drop[i] {
929			out = append(out, x)
930		}
931	}
932	list = out
933
934	return list[0], list[1:]
935}
936
937func (t *tester) addCmd(dt *distTest, dir string, cmdline ...interface{}) *exec.Cmd {
938	bin, args := flattenCmdline(cmdline)
939	w := &work{
940		dt:  dt,
941		cmd: t.bgDirCmd(dir, bin, args...),
942	}
943	t.worklist = append(t.worklist, w)
944	return w.cmd
945}
946
947func (t *tester) iOS() bool {
948	return goos == "ios"
949}
950
951func (t *tester) out(v string) {
952	if t.banner == "" {
953		return
954	}
955	fmt.Println("\n" + t.banner + v)
956}
957
958func (t *tester) extLink() bool {
959	pair := gohostos + "-" + goarch
960	switch pair {
961	case "aix-ppc64",
962		"android-arm", "android-arm64",
963		"darwin-amd64", "darwin-arm64",
964		"dragonfly-amd64",
965		"freebsd-386", "freebsd-amd64", "freebsd-arm",
966		"linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le", "linux-mips", "linux-mipsle", "linux-riscv64", "linux-s390x",
967		"netbsd-386", "netbsd-amd64",
968		"openbsd-386", "openbsd-amd64",
969		"windows-386", "windows-amd64":
970		return true
971	}
972	return false
973}
974
975func (t *tester) internalLink() bool {
976	if gohostos == "dragonfly" {
977		// linkmode=internal fails on dragonfly since errno is a TLS relocation.
978		return false
979	}
980	if goos == "android" {
981		return false
982	}
983	if goos == "ios" {
984		return false
985	}
986	if goos == "windows" && goarch == "arm64" {
987		return false
988	}
989	// Internally linking cgo is incomplete on some architectures.
990	// https://golang.org/issue/10373
991	// https://golang.org/issue/14449
992	if goarch == "mips64" || goarch == "mips64le" || goarch == "mips" || goarch == "mipsle" || goarch == "riscv64" {
993		return false
994	}
995	if goos == "aix" {
996		// linkmode=internal isn't supported.
997		return false
998	}
999	return true
1000}
1001
1002func (t *tester) internalLinkPIE() bool {
1003	switch goos + "-" + goarch {
1004	case "darwin-amd64", "darwin-arm64",
1005		"linux-amd64", "linux-arm64", "linux-ppc64le",
1006		"android-arm64",
1007		"windows-amd64", "windows-386", "windows-arm":
1008		return true
1009	}
1010	return false
1011}
1012
1013func (t *tester) supportedBuildmode(mode string) bool {
1014	pair := goos + "-" + goarch
1015	switch mode {
1016	case "c-archive":
1017		if !t.extLink() {
1018			return false
1019		}
1020		switch pair {
1021		case "aix-ppc64",
1022			"darwin-amd64", "darwin-arm64", "ios-arm64",
1023			"linux-amd64", "linux-386", "linux-ppc64le", "linux-riscv64", "linux-s390x",
1024			"freebsd-amd64",
1025			"windows-amd64", "windows-386":
1026			return true
1027		}
1028		return false
1029	case "c-shared":
1030		switch pair {
1031		case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x",
1032			"darwin-amd64", "darwin-arm64",
1033			"freebsd-amd64",
1034			"android-arm", "android-arm64", "android-386",
1035			"windows-amd64", "windows-386", "windows-arm64":
1036			return true
1037		}
1038		return false
1039	case "shared":
1040		switch pair {
1041		case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x":
1042			return true
1043		}
1044		return false
1045	case "plugin":
1046		switch pair {
1047		case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-s390x", "linux-ppc64le":
1048			return true
1049		case "darwin-amd64", "darwin-arm64":
1050			return true
1051		case "freebsd-amd64":
1052			return true
1053		}
1054		return false
1055	case "pie":
1056		switch pair {
1057		case "aix/ppc64",
1058			"linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x",
1059			"android-amd64", "android-arm", "android-arm64", "android-386":
1060			return true
1061		case "darwin-amd64", "darwin-arm64":
1062			return true
1063		case "windows-amd64", "windows-386", "windows-arm":
1064			return true
1065		}
1066		return false
1067
1068	default:
1069		fatalf("internal error: unknown buildmode %s", mode)
1070		return false
1071	}
1072}
1073
1074func (t *tester) registerHostTest(name, heading, dir, pkg string) {
1075	t.tests = append(t.tests, distTest{
1076		name:    name,
1077		heading: heading,
1078		fn: func(dt *distTest) error {
1079			t.runPending(dt)
1080			timelog("start", name)
1081			defer timelog("end", name)
1082			return t.runHostTest(dir, pkg)
1083		},
1084	})
1085}
1086
1087func (t *tester) runHostTest(dir, pkg string) error {
1088	out, err := exec.Command("go", "env", "GOEXE", "GOTMPDIR").Output()
1089	if err != nil {
1090		return err
1091	}
1092
1093	parts := strings.Split(string(out), "\n")
1094	if len(parts) < 2 {
1095		return fmt.Errorf("'go env GOEXE GOTMPDIR' output contains <2 lines")
1096	}
1097	GOEXE := strings.TrimSpace(parts[0])
1098	GOTMPDIR := strings.TrimSpace(parts[1])
1099
1100	f, err := ioutil.TempFile(GOTMPDIR, "test.test-*"+GOEXE)
1101	if err != nil {
1102		return err
1103	}
1104	f.Close()
1105	defer os.Remove(f.Name())
1106
1107	cmd := t.dirCmd(dir, t.goTest(), "-c", "-o", f.Name(), pkg)
1108	setEnv(cmd, "GOARCH", gohostarch)
1109	setEnv(cmd, "GOOS", gohostos)
1110	if err := cmd.Run(); err != nil {
1111		return err
1112	}
1113	return t.dirCmd(dir, f.Name(), "-test.short="+short()).Run()
1114}
1115
1116func (t *tester) cgoTest(dt *distTest) error {
1117	cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
1118	setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=auto")
1119
1120	// Skip internal linking cases on linux/arm64 to support GCC-9.4 and above.
1121	// See issue #39466.
1122	skipInternalLink := goarch == "arm64" && goos == "linux"
1123
1124	if t.internalLink() && !skipInternalLink {
1125		cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=internal")
1126		setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=internal")
1127	}
1128
1129	pair := gohostos + "-" + goarch
1130	switch pair {
1131	case "darwin-amd64", "darwin-arm64",
1132		"windows-386", "windows-amd64":
1133		// test linkmode=external, but __thread not supported, so skip testtls.
1134		if !t.extLink() {
1135			break
1136		}
1137		cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
1138		setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=external")
1139
1140		t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s")
1141
1142		if t.supportedBuildmode("pie") {
1143			t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie")
1144			if t.internalLink() && t.internalLinkPIE() {
1145				t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal", "-tags=internal,internal_pie")
1146			}
1147		}
1148
1149	case "aix-ppc64",
1150		"android-arm", "android-arm64",
1151		"dragonfly-amd64",
1152		"freebsd-386", "freebsd-amd64", "freebsd-arm",
1153		"linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x",
1154		"netbsd-386", "netbsd-amd64",
1155		"openbsd-386", "openbsd-amd64", "openbsd-arm", "openbsd-arm64", "openbsd-mips64":
1156
1157		cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
1158		setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=external")
1159		// cgo should be able to cope with both -g arguments and colored
1160		// diagnostics.
1161		setEnv(cmd, "CGO_CFLAGS", "-g0 -fdiagnostics-color")
1162
1163		t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=auto")
1164		t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=external")
1165
1166		switch pair {
1167		case "aix-ppc64", "netbsd-386", "netbsd-amd64":
1168			// no static linking
1169		case "freebsd-arm":
1170			// -fPIC compiled tls code will use __tls_get_addr instead
1171			// of __aeabi_read_tp, however, on FreeBSD/ARM, __tls_get_addr
1172			// is implemented in rtld-elf, so -fPIC isn't compatible with
1173			// static linking on FreeBSD/ARM with clang. (cgo depends on
1174			// -fPIC fundamentally.)
1175		default:
1176			cmd := t.dirCmd("misc/cgo/test",
1177				compilerEnvLookup(defaultcc, goos, goarch), "-xc", "-o", "/dev/null", "-static", "-")
1178			cmd.Stdin = strings.NewReader("int main() {}")
1179			if err := cmd.Run(); err != nil {
1180				fmt.Println("No support for static linking found (lacks libc.a?), skip cgo static linking test.")
1181			} else {
1182				if goos != "android" {
1183					t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
1184				}
1185				t.addCmd(dt, "misc/cgo/nocgo", t.goTest())
1186				t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-ldflags", `-linkmode=external`)
1187				if goos != "android" {
1188					t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
1189					t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
1190					// -static in CGO_LDFLAGS triggers a different code path
1191					// than -static in -extldflags, so test both.
1192					// See issue #16651.
1193					cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static")
1194					setEnv(cmd, "CGO_LDFLAGS", "-static -pthread")
1195				}
1196			}
1197
1198			if t.supportedBuildmode("pie") {
1199				t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie")
1200				if t.internalLink() && t.internalLinkPIE() && !skipInternalLink {
1201					t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal", "-tags=internal,internal_pie")
1202				}
1203				t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-buildmode=pie")
1204				t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-buildmode=pie")
1205			}
1206		}
1207	}
1208
1209	return nil
1210}
1211
1212// run pending test commands, in parallel, emitting headers as appropriate.
1213// When finished, emit header for nextTest, which is going to run after the
1214// pending commands are done (and runPending returns).
1215// A test should call runPending if it wants to make sure that it is not
1216// running in parallel with earlier tests, or if it has some other reason
1217// for needing the earlier tests to be done.
1218func (t *tester) runPending(nextTest *distTest) {
1219	checkNotStale("go", "std")
1220	worklist := t.worklist
1221	t.worklist = nil
1222	for _, w := range worklist {
1223		w.start = make(chan bool)
1224		w.end = make(chan bool)
1225		go func(w *work) {
1226			if !<-w.start {
1227				timelog("skip", w.dt.name)
1228				w.out = []byte(fmt.Sprintf("skipped due to earlier error\n"))
1229			} else {
1230				timelog("start", w.dt.name)
1231				w.out, w.err = w.cmd.CombinedOutput()
1232				if w.err != nil {
1233					if isUnsupportedVMASize(w) {
1234						timelog("skip", w.dt.name)
1235						w.out = []byte(fmt.Sprintf("skipped due to unsupported VMA\n"))
1236						w.err = nil
1237					}
1238				}
1239			}
1240			timelog("end", w.dt.name)
1241			w.end <- true
1242		}(w)
1243	}
1244
1245	started := 0
1246	ended := 0
1247	var last *distTest
1248	for ended < len(worklist) {
1249		for started < len(worklist) && started-ended < maxbg {
1250			w := worklist[started]
1251			started++
1252			w.start <- !t.failed || t.keepGoing
1253		}
1254		w := worklist[ended]
1255		dt := w.dt
1256		if dt.heading != "" && t.lastHeading != dt.heading {
1257			t.lastHeading = dt.heading
1258			t.out(dt.heading)
1259		}
1260		if dt != last {
1261			// Assumes all the entries for a single dt are in one worklist.
1262			last = w.dt
1263			if vflag > 0 {
1264				fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
1265			}
1266		}
1267		if vflag > 1 {
1268			errprintf("%s\n", strings.Join(w.cmd.Args, " "))
1269		}
1270		ended++
1271		<-w.end
1272		os.Stdout.Write(w.out)
1273		if w.err != nil {
1274			log.Printf("Failed: %v", w.err)
1275			t.failed = true
1276		}
1277		checkNotStale("go", "std")
1278	}
1279	if t.failed && !t.keepGoing {
1280		fatalf("FAILED")
1281	}
1282
1283	if dt := nextTest; dt != nil {
1284		if dt.heading != "" && t.lastHeading != dt.heading {
1285			t.lastHeading = dt.heading
1286			t.out(dt.heading)
1287		}
1288		if vflag > 0 {
1289			fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
1290		}
1291	}
1292}
1293
1294func (t *tester) hasBash() bool {
1295	switch gohostos {
1296	case "windows", "plan9":
1297		return false
1298	}
1299	return true
1300}
1301
1302func (t *tester) hasCxx() bool {
1303	cxx, _ := exec.LookPath(compilerEnvLookup(defaultcxx, goos, goarch))
1304	return cxx != ""
1305}
1306
1307func (t *tester) hasSwig() bool {
1308	swig, err := exec.LookPath("swig")
1309	if err != nil {
1310		return false
1311	}
1312
1313	// Check that swig was installed with Go support by checking
1314	// that a go directory exists inside the swiglib directory.
1315	// See https://golang.org/issue/23469.
1316	output, err := exec.Command(swig, "-go", "-swiglib").Output()
1317	if err != nil {
1318		return false
1319	}
1320	swigDir := strings.TrimSpace(string(output))
1321
1322	_, err = os.Stat(filepath.Join(swigDir, "go"))
1323	if err != nil {
1324		return false
1325	}
1326
1327	// Check that swig has a new enough version.
1328	// See https://golang.org/issue/22858.
1329	out, err := exec.Command(swig, "-version").CombinedOutput()
1330	if err != nil {
1331		return false
1332	}
1333
1334	re := regexp.MustCompile(`[vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)?`)
1335	matches := re.FindSubmatch(out)
1336	if matches == nil {
1337		// Can't find version number; hope for the best.
1338		return true
1339	}
1340
1341	major, err := strconv.Atoi(string(matches[1]))
1342	if err != nil {
1343		// Can't find version number; hope for the best.
1344		return true
1345	}
1346	if major < 3 {
1347		return false
1348	}
1349	if major > 3 {
1350		// 4.0 or later
1351		return true
1352	}
1353
1354	// We have SWIG version 3.x.
1355	if len(matches[2]) > 0 {
1356		minor, err := strconv.Atoi(string(matches[2][1:]))
1357		if err != nil {
1358			return true
1359		}
1360		if minor > 0 {
1361			// 3.1 or later
1362			return true
1363		}
1364	}
1365
1366	// We have SWIG version 3.0.x.
1367	if len(matches[3]) > 0 {
1368		patch, err := strconv.Atoi(string(matches[3][1:]))
1369		if err != nil {
1370			return true
1371		}
1372		if patch < 6 {
1373			// Before 3.0.6.
1374			return false
1375		}
1376	}
1377
1378	return true
1379}
1380
1381func (t *tester) raceDetectorSupported() bool {
1382	if gohostos != goos {
1383		return false
1384	}
1385	if !t.cgoEnabled {
1386		return false
1387	}
1388	if !raceDetectorSupported(goos, goarch) {
1389		return false
1390	}
1391	// The race detector doesn't work on Alpine Linux:
1392	// golang.org/issue/14481
1393	if isAlpineLinux() {
1394		return false
1395	}
1396	// NetBSD support is unfinished.
1397	// golang.org/issue/26403
1398	if goos == "netbsd" {
1399		return false
1400	}
1401	return true
1402}
1403
1404func isAlpineLinux() bool {
1405	if runtime.GOOS != "linux" {
1406		return false
1407	}
1408	fi, err := os.Lstat("/etc/alpine-release")
1409	return err == nil && fi.Mode().IsRegular()
1410}
1411
1412func (t *tester) runFlag(rx string) string {
1413	if t.compileOnly {
1414		return "-run=^$"
1415	}
1416	return "-run=" + rx
1417}
1418
1419func (t *tester) raceTest(dt *distTest) error {
1420	t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("Output"), "runtime/race")
1421	t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace|TestTypeRace|TestFdRace|TestFdReadRace|TestFileCloseRace"), "flag", "net", "os", "os/exec", "encoding/gob")
1422	// We don't want the following line, because it
1423	// slows down all.bash (by 10 seconds on my laptop).
1424	// The race builder should catch any error here, but doesn't.
1425	// TODO(iant): Figure out how to catch this.
1426	// t.addCmd(dt, "src", t.goTest(),  "-race", "-run=TestParallelTest", "cmd/go")
1427	if t.cgoEnabled {
1428		// Building misc/cgo/test takes a long time.
1429		// There are already cgo-enabled packages being tested with the race detector.
1430		// We shouldn't need to redo all of misc/cgo/test too.
1431		// The race buildler will take care of this.
1432		// cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-race")
1433		// setEnv(cmd, "GOTRACEBACK", "2")
1434	}
1435	if t.extLink() {
1436		// Test with external linking; see issue 9133.
1437		t.addCmd(dt, "src", t.goTest(), "-race", "-ldflags=-linkmode=external", t.runFlag("TestParse|TestEcho|TestStdinCloseRace"), "flag", "os/exec")
1438	}
1439	return nil
1440}
1441
1442var runtest struct {
1443	sync.Once
1444	exe string
1445	err error
1446}
1447
1448func (t *tester) testDirTest(dt *distTest, shard, shards int) error {
1449	runtest.Do(func() {
1450		f, err := ioutil.TempFile("", "runtest-*.exe") // named exe for Windows, but harmless elsewhere
1451		if err != nil {
1452			runtest.err = err
1453			return
1454		}
1455		f.Close()
1456
1457		runtest.exe = f.Name()
1458		xatexit(func() {
1459			os.Remove(runtest.exe)
1460		})
1461
1462		cmd := t.dirCmd("test", "go", "build", "-o", runtest.exe, "run.go")
1463		setEnv(cmd, "GOOS", gohostos)
1464		setEnv(cmd, "GOARCH", gohostarch)
1465		runtest.err = cmd.Run()
1466	})
1467	if runtest.err != nil {
1468		return runtest.err
1469	}
1470	if t.compileOnly {
1471		return nil
1472	}
1473	t.addCmd(dt, "test", runtest.exe,
1474		fmt.Sprintf("--shard=%d", shard),
1475		fmt.Sprintf("--shards=%d", shards),
1476	)
1477	return nil
1478}
1479
1480// cgoPackages is the standard packages that use cgo.
1481var cgoPackages = []string{
1482	"net",
1483	"os/user",
1484}
1485
1486var funcBenchmark = []byte("\nfunc Benchmark")
1487
1488// packageHasBenchmarks reports whether pkg has benchmarks.
1489// On any error, it conservatively returns true.
1490//
1491// This exists just to eliminate work on the builders, since compiling
1492// a test in race mode just to discover it has no benchmarks costs a
1493// second or two per package, and this function returns false for
1494// about 100 packages.
1495func (t *tester) packageHasBenchmarks(pkg string) bool {
1496	pkgDir := filepath.Join(goroot, "src", pkg)
1497	d, err := os.Open(pkgDir)
1498	if err != nil {
1499		return true // conservatively
1500	}
1501	defer d.Close()
1502	names, err := d.Readdirnames(-1)
1503	if err != nil {
1504		return true // conservatively
1505	}
1506	for _, name := range names {
1507		if !strings.HasSuffix(name, "_test.go") {
1508			continue
1509		}
1510		slurp, err := ioutil.ReadFile(filepath.Join(pkgDir, name))
1511		if err != nil {
1512			return true // conservatively
1513		}
1514		if bytes.Contains(slurp, funcBenchmark) {
1515			return true
1516		}
1517	}
1518	return false
1519}
1520
1521// makeGOROOTUnwritable makes all $GOROOT files & directories non-writable to
1522// check that no tests accidentally write to $GOROOT.
1523func (t *tester) makeGOROOTUnwritable() (undo func()) {
1524	dir := os.Getenv("GOROOT")
1525	if dir == "" {
1526		panic("GOROOT not set")
1527	}
1528
1529	type pathMode struct {
1530		path string
1531		mode os.FileMode
1532	}
1533	var dirs []pathMode // in lexical order
1534
1535	undo = func() {
1536		for i := range dirs {
1537			os.Chmod(dirs[i].path, dirs[i].mode) // best effort
1538		}
1539	}
1540
1541	gocache := os.Getenv("GOCACHE")
1542	if gocache == "" {
1543		panic("GOCACHE not set")
1544	}
1545	gocacheSubdir, _ := filepath.Rel(dir, gocache)
1546
1547	// Note: Can't use WalkDir here, because this has to compile with Go 1.4.
1548	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
1549		if suffix := strings.TrimPrefix(path, dir+string(filepath.Separator)); suffix != "" {
1550			if suffix == gocacheSubdir {
1551				// Leave GOCACHE writable: we may need to write test binaries into it.
1552				return filepath.SkipDir
1553			}
1554			if suffix == ".git" {
1555				// Leave Git metadata in whatever state it was in. It may contain a lot
1556				// of files, and it is highly unlikely that a test will try to modify
1557				// anything within that directory.
1558				return filepath.SkipDir
1559			}
1560		}
1561		if err == nil {
1562			mode := info.Mode()
1563			if mode&0222 != 0 && (mode.IsDir() || mode.IsRegular()) {
1564				dirs = append(dirs, pathMode{path, mode})
1565			}
1566		}
1567		return nil
1568	})
1569
1570	// Run over list backward to chmod children before parents.
1571	for i := len(dirs) - 1; i >= 0; i-- {
1572		err := os.Chmod(dirs[i].path, dirs[i].mode&^0222)
1573		if err != nil {
1574			dirs = dirs[i:] // Only undo what we did so far.
1575			undo()
1576			fatalf("failed to make GOROOT read-only: %v", err)
1577		}
1578	}
1579
1580	return undo
1581}
1582
1583// shouldUsePrecompiledStdTest reports whether "dist test" should use
1584// a pre-compiled go test binary on disk rather than running "go test"
1585// and compiling it again. This is used by our slow qemu-based builder
1586// that do full processor emulation where we cross-compile the
1587// make.bash step as well as pre-compile each std test binary.
1588//
1589// This only reports true if dist is run with an single go_test:foo
1590// argument (as the build coordinator does with our slow qemu-based
1591// builders), we're in a builder environment ("GO_BUILDER_NAME" is set),
1592// and the pre-built test binary exists.
1593func (t *tester) shouldUsePrecompiledStdTest() bool {
1594	bin := t.prebuiltGoPackageTestBinary()
1595	if bin == "" {
1596		return false
1597	}
1598	_, err := os.Stat(bin)
1599	return err == nil
1600}
1601
1602func (t *tester) shouldTestCmd() bool {
1603	if goos == "js" && goarch == "wasm" {
1604		// Issues 25911, 35220
1605		return false
1606	}
1607	return true
1608}
1609
1610// prebuiltGoPackageTestBinary returns the path where we'd expect
1611// the pre-built go test binary to be on disk when dist test is run with
1612// a single argument.
1613// It returns an empty string if a pre-built binary should not be used.
1614func (t *tester) prebuiltGoPackageTestBinary() string {
1615	if len(stdMatches) != 1 || t.race || t.compileOnly || os.Getenv("GO_BUILDER_NAME") == "" {
1616		return ""
1617	}
1618	pkg := stdMatches[0]
1619	return filepath.Join(os.Getenv("GOROOT"), "src", pkg, path.Base(pkg)+".test")
1620}
1621
1622// runPrecompiledStdTest runs the pre-compiled standard library package test binary.
1623// See shouldUsePrecompiledStdTest above; it must return true for this to be called.
1624func (t *tester) runPrecompiledStdTest(timeout time.Duration) error {
1625	bin := t.prebuiltGoPackageTestBinary()
1626	fmt.Fprintf(os.Stderr, "# %s: using pre-built %s...\n", stdMatches[0], bin)
1627	cmd := exec.Command(bin, "-test.short="+short(), "-test.timeout="+timeout.String())
1628	setDir(cmd, filepath.Dir(bin))
1629	cmd.Stdout = os.Stdout
1630	cmd.Stderr = os.Stderr
1631	if err := cmd.Start(); err != nil {
1632		return err
1633	}
1634	// And start a timer to kill the process if it doesn't kill
1635	// itself in the prescribed timeout.
1636	const backupKillFactor = 1.05 // add 5%
1637	timer := time.AfterFunc(time.Duration(float64(timeout)*backupKillFactor), func() {
1638		fmt.Fprintf(os.Stderr, "# %s: timeout running %s; killing...\n", stdMatches[0], bin)
1639		cmd.Process.Kill()
1640	})
1641	defer timer.Stop()
1642	return cmd.Wait()
1643}
1644
1645// raceDetectorSupported is a copy of the function
1646// cmd/internal/sys.RaceDetectorSupported, which can't be used here
1647// because cmd/dist has to be buildable by Go 1.4.
1648// The race detector only supports 48-bit VMA on arm64. But we don't have
1649// a good solution to check VMA size(See https://golang.org/issue/29948)
1650// raceDetectorSupported will always return true for arm64. But race
1651// detector tests may abort on non 48-bit VMA configuration, the tests
1652// will be marked as "skipped" in this case.
1653func raceDetectorSupported(goos, goarch string) bool {
1654	switch goos {
1655	case "linux":
1656		return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64"
1657	case "darwin":
1658		return goarch == "amd64" || goarch == "arm64"
1659	case "freebsd", "netbsd", "openbsd", "windows":
1660		return goarch == "amd64"
1661	default:
1662		return false
1663	}
1664}
1665
1666// isUnsupportedVMASize reports whether the failure is caused by an unsupported
1667// VMA for the race detector (for example, running the race detector on an
1668// arm64 machine configured with 39-bit VMA)
1669func isUnsupportedVMASize(w *work) bool {
1670	unsupportedVMA := []byte("unsupported VMA range")
1671	return w.dt.name == "race" && bytes.Contains(w.out, unsupportedVMA)
1672}
1673
1674// isEnvSet reports whether the environment variable evar is
1675// set in the environment.
1676func isEnvSet(evar string) bool {
1677	evarEq := evar + "="
1678	for _, e := range os.Environ() {
1679		if strings.HasPrefix(e, evarEq) {
1680			return true
1681		}
1682	}
1683	return false
1684}
1685