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