Source file 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/ioutil"
    12  	"log"
    13  	"os"
    14  	"os/exec"
    15  	"path"
    16  	"path/filepath"
    17  	"reflect"
    18  	"regexp"
    19  	"runtime"
    20  	"strconv"
    21  	"strings"
    22  	"sync"
    23  	"time"
    24  )
    25  
    26  func cmdtest() {
    27  	gogcflags = os.Getenv("GO_GCFLAGS")
    28  
    29  	var t tester
    30  	var noRebuild bool
    31  	flag.BoolVar(&t.listMode, "list", false, "list available tests")
    32  	flag.BoolVar(&t.rebuild, "rebuild", false, "rebuild everything first")
    33  	flag.BoolVar(&noRebuild, "no-rebuild", false, "overrides -rebuild (historical dreg)")
    34  	flag.BoolVar(&t.keepGoing, "k", false, "keep going even when error occurred")
    35  	flag.BoolVar(&t.race, "race", false, "run in race builder mode (different set of tests)")
    36  	flag.BoolVar(&t.compileOnly, "compile-only", false, "compile tests, but don't run them. This is for some builders. Not all dist tests respect this flag, but most do.")
    37  	flag.StringVar(&t.banner, "banner", "##### ", "banner prefix; blank means no section banners")
    38  	flag.StringVar(&t.runRxStr, "run", os.Getenv("GOTESTONLY"),
    39  		"run only those tests matching the regular expression; empty means to run all. "+
    40  			"Special exception: if the string begins with '!', the match is inverted.")
    41  	xflagparse(-1) // any number of args
    42  	if noRebuild {
    43  		t.rebuild = false
    44  	}
    45  
    46  	t.run()
    47  }
    48  
    49  // tester executes cmdtest.
    50  type 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  
    74  type 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)
    85  type 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  
    91  func (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  
   256  func (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.
   280  func 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.
   296  func (t *tester) goTest() []string {
   297  	return []string{
   298  		"go", "test", "-short=" + short(), "-count=1", t.tags(), t.runFlag(""),
   299  	}
   300  }
   301  
   302  func (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.
   311  func (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.
   318  func (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.
   328  var (
   329  	ranGoTest  bool
   330  	stdMatches []string
   331  
   332  	ranGoBench   bool
   333  	benchMatches []string
   334  )
   335  
   336  func (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  
   397  func (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.
   436  var stdOutErrAreTerminals func() bool
   437  
   438  func (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.
   831  func (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  
   840  func (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  
   864  func (t *tester) registerTest(name, dirBanner string, cmdline ...interface{}) {
   865  	t.registerTest1(false, name, dirBanner, cmdline...)
   866  }
   867  
   868  func (t *tester) registerSeqTest(name, dirBanner string, cmdline ...interface{}) {
   869  	t.registerTest1(true, name, dirBanner, cmdline...)
   870  }
   871  
   872  func (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  
   882  func (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.
   895  func 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  
   937  func (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  
   947  func (t *tester) iOS() bool {
   948  	return goos == "ios"
   949  }
   950  
   951  func (t *tester) out(v string) {
   952  	if t.banner == "" {
   953  		return
   954  	}
   955  	fmt.Println("\n" + t.banner + v)
   956  }
   957  
   958  func (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  
   975  func (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  
  1002  func (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  
  1013  func (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  
  1074  func (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  
  1087  func (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  
  1116  func (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 arm64 to support GCC-9.4 and above.
  1121  	// See issue #39466.
  1122  	skipInternalLink := goarch == "arm64" && goos != "darwin"
  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.
  1218  func (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  
  1294  func (t *tester) hasBash() bool {
  1295  	switch gohostos {
  1296  	case "windows", "plan9":
  1297  		return false
  1298  	}
  1299  	return true
  1300  }
  1301  
  1302  func (t *tester) hasCxx() bool {
  1303  	cxx, _ := exec.LookPath(compilerEnvLookup(defaultcxx, goos, goarch))
  1304  	return cxx != ""
  1305  }
  1306  
  1307  func (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  
  1381  func (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  
  1404  func 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  
  1412  func (t *tester) runFlag(rx string) string {
  1413  	if t.compileOnly {
  1414  		return "-run=^$"
  1415  	}
  1416  	return "-run=" + rx
  1417  }
  1418  
  1419  func (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  
  1442  var runtest struct {
  1443  	sync.Once
  1444  	exe string
  1445  	err error
  1446  }
  1447  
  1448  func (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.
  1481  var cgoPackages = []string{
  1482  	"net",
  1483  	"os/user",
  1484  }
  1485  
  1486  var 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.
  1495  func (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.
  1523  func (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.
  1593  func (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  
  1602  func (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.
  1614  func (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.
  1624  func (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.
  1653  func 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)
  1669  func 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.
  1676  func 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  

View as plain text