Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/dist/test.go

Documentation: cmd/dist

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

View as plain text