github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/cmd/dist/test.go (about)

     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  	"errors"
    10  	"flag"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"log"
    14  	"os"
    15  	"os/exec"
    16  	"path/filepath"
    17  	"regexp"
    18  	"runtime"
    19  	"strconv"
    20  	"strings"
    21  	"sync"
    22  	"time"
    23  )
    24  
    25  func cmdtest() {
    26  	var t tester
    27  	var noRebuild bool
    28  	flag.BoolVar(&t.listMode, "list", false, "list available tests")
    29  	flag.BoolVar(&t.rebuild, "rebuild", false, "rebuild everything first")
    30  	flag.BoolVar(&noRebuild, "no-rebuild", false, "overrides -rebuild (historical dreg)")
    31  	flag.BoolVar(&t.keepGoing, "k", false, "keep going even when error occurred")
    32  	flag.BoolVar(&t.race, "race", false, "run in race builder mode (different set of tests)")
    33  	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.")
    34  	flag.StringVar(&t.banner, "banner", "##### ", "banner prefix; blank means no section banners")
    35  	flag.StringVar(&t.runRxStr, "run", os.Getenv("GOTESTONLY"),
    36  		"run only those tests matching the regular expression; empty means to run all. "+
    37  			"Special exception: if the string begins with '!', the match is inverted.")
    38  	xflagparse(-1) // any number of args
    39  	if noRebuild {
    40  		t.rebuild = false
    41  	}
    42  	t.run()
    43  }
    44  
    45  // tester executes cmdtest.
    46  type tester struct {
    47  	race        bool
    48  	listMode    bool
    49  	rebuild     bool
    50  	failed      bool
    51  	keepGoing   bool
    52  	compileOnly bool // just try to compile all tests, but no need to run
    53  	runRxStr    string
    54  	runRx       *regexp.Regexp
    55  	runRxWant   bool     // want runRx to match (true) or not match (false)
    56  	runNames    []string // tests to run, exclusive with runRx; empty means all
    57  	banner      string   // prefix, or "" for none
    58  	lastHeading string   // last dir heading printed
    59  
    60  	goroot     string
    61  	goarch     string
    62  	gohostarch string
    63  	goos       string
    64  	gohostos   string
    65  	cgoEnabled bool
    66  	partial    bool
    67  	haveTime   bool // the 'time' binary is available
    68  
    69  	tests        []distTest
    70  	timeoutScale int
    71  
    72  	worklist []*work
    73  }
    74  
    75  type work struct {
    76  	dt    *distTest
    77  	cmd   *exec.Cmd
    78  	start chan bool
    79  	out   []byte
    80  	err   error
    81  	end   chan bool
    82  }
    83  
    84  // A distTest is a test run by dist test.
    85  // Each test has a unique name and belongs to a group (heading)
    86  type distTest struct {
    87  	name    string // unique test name; may be filtered with -run flag
    88  	heading string // group section; this header is printed before the test is run.
    89  	fn      func(*distTest) error
    90  }
    91  
    92  func mustEnv(k string) string {
    93  	v := os.Getenv(k)
    94  	if v == "" {
    95  		log.Fatalf("Unset environment variable %v", k)
    96  	}
    97  	return v
    98  }
    99  
   100  func (t *tester) run() {
   101  	t.goroot = mustEnv("GOROOT")
   102  	t.goos = mustEnv("GOOS")
   103  	t.gohostos = mustEnv("GOHOSTOS")
   104  	t.goarch = mustEnv("GOARCH")
   105  	t.gohostarch = mustEnv("GOHOSTARCH")
   106  	slurp, err := exec.Command("go", "env", "CGO_ENABLED").Output()
   107  	if err != nil {
   108  		log.Fatalf("Error running go env CGO_ENABLED: %v", err)
   109  	}
   110  	t.cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(slurp)))
   111  	if flag.NArg() > 0 && t.runRxStr != "" {
   112  		log.Fatalf("the -run regular expression flag is mutually exclusive with test name arguments")
   113  	}
   114  	t.runNames = flag.Args()
   115  
   116  	if t.hasBash() {
   117  		if _, err := exec.LookPath("time"); err == nil {
   118  			t.haveTime = true
   119  		}
   120  	}
   121  
   122  	if t.rebuild {
   123  		t.out("Building packages and commands.")
   124  		cmd := exec.Command("go", "install", "-a", "-v", "std", "cmd")
   125  		cmd.Stdout = os.Stdout
   126  		cmd.Stderr = os.Stderr
   127  		if err := cmd.Run(); err != nil {
   128  			log.Fatalf("building packages and commands: %v", err)
   129  		}
   130  	}
   131  
   132  	if t.iOS() {
   133  		// Install the Mach exception handler used to intercept
   134  		// EXC_BAD_ACCESS and convert it into a Go panic. This is
   135  		// necessary for a Go program running under lldb (the way
   136  		// we run tests). It is disabled by default because iOS
   137  		// apps are not allowed to access the exc_server symbol.
   138  		cmd := exec.Command("go", "install", "-a", "-tags", "lldb", "runtime/cgo")
   139  		cmd.Stdout = os.Stdout
   140  		cmd.Stderr = os.Stderr
   141  		if err := cmd.Run(); err != nil {
   142  			log.Fatalf("building mach exception handler: %v", err)
   143  		}
   144  
   145  		defer func() {
   146  			cmd := exec.Command("go", "install", "-a", "runtime/cgo")
   147  			cmd.Stdout = os.Stdout
   148  			cmd.Stderr = os.Stderr
   149  			if err := cmd.Run(); err != nil {
   150  				log.Fatalf("reverting mach exception handler: %v", err)
   151  			}
   152  		}()
   153  	}
   154  
   155  	t.timeoutScale = 1
   156  	switch t.goarch {
   157  	case "arm":
   158  		t.timeoutScale = 2
   159  	case "mips", "mipsle", "mips64", "mips64le":
   160  		t.timeoutScale = 4
   161  	}
   162  	if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
   163  		t.timeoutScale, err = strconv.Atoi(s)
   164  		if err != nil {
   165  			log.Fatalf("failed to parse $GO_TEST_TIMEOUT_SCALE = %q as integer: %v", s, err)
   166  		}
   167  	}
   168  
   169  	if t.runRxStr != "" {
   170  		if t.runRxStr[0] == '!' {
   171  			t.runRxWant = false
   172  			t.runRxStr = t.runRxStr[1:]
   173  		} else {
   174  			t.runRxWant = true
   175  		}
   176  		t.runRx = regexp.MustCompile(t.runRxStr)
   177  	}
   178  
   179  	t.registerTests()
   180  	if t.listMode {
   181  		for _, tt := range t.tests {
   182  			fmt.Println(tt.name)
   183  		}
   184  		return
   185  	}
   186  
   187  	// we must unset GOROOT_FINAL before tests, because runtime/debug requires
   188  	// correct access to source code, so if we have GOROOT_FINAL in effect,
   189  	// at least runtime/debug test will fail.
   190  	os.Unsetenv("GOROOT_FINAL")
   191  
   192  	for _, name := range t.runNames {
   193  		if !t.isRegisteredTestName(name) {
   194  			log.Fatalf("unknown test %q", name)
   195  		}
   196  	}
   197  
   198  	for _, dt := range t.tests {
   199  		if !t.shouldRunTest(dt.name) {
   200  			t.partial = true
   201  			continue
   202  		}
   203  		dt := dt // dt used in background after this iteration
   204  		if err := dt.fn(&dt); err != nil {
   205  			t.runPending(&dt) // in case that hasn't been done yet
   206  			t.failed = true
   207  			if t.keepGoing {
   208  				log.Printf("Failed: %v", err)
   209  			} else {
   210  				log.Fatalf("Failed: %v", err)
   211  			}
   212  		}
   213  	}
   214  	t.runPending(nil)
   215  	if t.failed {
   216  		fmt.Println("\nFAILED")
   217  		os.Exit(1)
   218  	} else if t.partial {
   219  		fmt.Println("\nALL TESTS PASSED (some were excluded)")
   220  	} else {
   221  		fmt.Println("\nALL TESTS PASSED")
   222  	}
   223  }
   224  
   225  func (t *tester) shouldRunTest(name string) bool {
   226  	if t.runRx != nil {
   227  		return t.runRx.MatchString(name) == t.runRxWant
   228  	}
   229  	if len(t.runNames) == 0 {
   230  		return true
   231  	}
   232  	for _, runName := range t.runNames {
   233  		if runName == name {
   234  			return true
   235  		}
   236  	}
   237  	return false
   238  }
   239  
   240  func (t *tester) tags() string {
   241  	if t.iOS() {
   242  		return "-tags=lldb"
   243  	}
   244  	return "-tags="
   245  }
   246  
   247  func (t *tester) timeout(sec int) string {
   248  	return "-timeout=" + fmt.Sprint(time.Duration(sec)*time.Second*time.Duration(t.timeoutScale))
   249  }
   250  
   251  // ranGoTest and stdMatches are state closed over by the stdlib
   252  // testing func in registerStdTest below. The tests are run
   253  // sequentially, so there's no need for locks.
   254  //
   255  // ranGoBench and benchMatches are the same, but are only used
   256  // in -race mode.
   257  var (
   258  	ranGoTest  bool
   259  	stdMatches []string
   260  
   261  	ranGoBench   bool
   262  	benchMatches []string
   263  )
   264  
   265  func (t *tester) registerStdTest(pkg string) {
   266  	testName := "go_test:" + pkg
   267  	if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant {
   268  		stdMatches = append(stdMatches, pkg)
   269  	}
   270  	t.tests = append(t.tests, distTest{
   271  		name:    testName,
   272  		heading: "Testing packages.",
   273  		fn: func(dt *distTest) error {
   274  			if ranGoTest {
   275  				return nil
   276  			}
   277  			t.runPending(dt)
   278  			ranGoTest = true
   279  			args := []string{
   280  				"test",
   281  				"-short",
   282  				t.tags(),
   283  				t.timeout(180),
   284  				"-gcflags=" + os.Getenv("GO_GCFLAGS"),
   285  			}
   286  			if t.race {
   287  				args = append(args, "-race")
   288  			}
   289  			if t.compileOnly {
   290  				args = append(args, "-run=^$")
   291  			}
   292  			args = append(args, stdMatches...)
   293  			cmd := exec.Command("go", args...)
   294  			cmd.Stdout = os.Stdout
   295  			cmd.Stderr = os.Stderr
   296  			return cmd.Run()
   297  		},
   298  	})
   299  }
   300  
   301  func (t *tester) registerRaceBenchTest(pkg string) {
   302  	testName := "go_test_bench:" + pkg
   303  	if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant {
   304  		benchMatches = append(benchMatches, pkg)
   305  	}
   306  	t.tests = append(t.tests, distTest{
   307  		name:    testName,
   308  		heading: "Running benchmarks briefly.",
   309  		fn: func(dt *distTest) error {
   310  			if ranGoBench {
   311  				return nil
   312  			}
   313  			t.runPending(dt)
   314  			ranGoBench = true
   315  			args := []string{
   316  				"test",
   317  				"-short",
   318  				"-race",
   319  				"-run=^$", // nothing. only benchmarks.
   320  				"-benchtime=.1s",
   321  				"-cpu=4",
   322  			}
   323  			if !t.compileOnly {
   324  				args = append(args, "-bench=.*")
   325  			}
   326  			args = append(args, benchMatches...)
   327  			cmd := exec.Command("go", args...)
   328  			cmd.Stdout = os.Stdout
   329  			cmd.Stderr = os.Stderr
   330  			return cmd.Run()
   331  		},
   332  	})
   333  }
   334  
   335  // stdOutErrAreTerminals is defined in test_linux.go, to report
   336  // whether stdout & stderr are terminals.
   337  var stdOutErrAreTerminals func() bool
   338  
   339  func (t *tester) registerTests() {
   340  	if strings.HasSuffix(os.Getenv("GO_BUILDER_NAME"), "-vetall") {
   341  		// Run vet over std and cmd and call it quits.
   342  		for k := range cgoEnabled {
   343  			osarch := k
   344  			t.tests = append(t.tests, distTest{
   345  				name:    "vet/" + osarch,
   346  				heading: "go vet std cmd",
   347  				fn: func(dt *distTest) error {
   348  					t.addCmd(dt, "src/cmd/vet/all", "go", "run", "main.go", "-p="+osarch)
   349  					return nil
   350  				},
   351  			})
   352  		}
   353  		return
   354  	}
   355  
   356  	// This test needs its stdout/stderr to be terminals, so we don't run it from cmd/go's tests.
   357  	// See issue 18153.
   358  	if t.goos == "linux" {
   359  		t.tests = append(t.tests, distTest{
   360  			name:    "cmd_go_test_terminal",
   361  			heading: "cmd/go terminal test",
   362  			fn: func(dt *distTest) error {
   363  				t.runPending(dt)
   364  				if !stdOutErrAreTerminals() {
   365  					fmt.Println("skipping terminal test; stdout/stderr not terminals")
   366  					return nil
   367  				}
   368  				cmd := exec.Command("go", "test")
   369  				cmd.Dir = filepath.Join(os.Getenv("GOROOT"), "src/cmd/go/testdata/testterminal18153")
   370  				cmd.Stdout = os.Stdout
   371  				cmd.Stderr = os.Stderr
   372  				return cmd.Run()
   373  			},
   374  		})
   375  	}
   376  
   377  	// Fast path to avoid the ~1 second of `go list std cmd` when
   378  	// the caller lists specific tests to run. (as the continuous
   379  	// build coordinator does).
   380  	if len(t.runNames) > 0 {
   381  		for _, name := range t.runNames {
   382  			if strings.HasPrefix(name, "go_test:") {
   383  				t.registerStdTest(strings.TrimPrefix(name, "go_test:"))
   384  			}
   385  			if strings.HasPrefix(name, "go_test_bench:") {
   386  				t.registerRaceBenchTest(strings.TrimPrefix(name, "go_test_bench:"))
   387  			}
   388  		}
   389  	} else {
   390  		// Use a format string to only list packages and commands that have tests.
   391  		const format = "{{if (or .TestGoFiles .XTestGoFiles)}}{{.ImportPath}}{{end}}"
   392  		cmd := exec.Command("go", "list", "-f", format)
   393  		if t.race {
   394  			cmd.Args = append(cmd.Args, "-tags", "race")
   395  		}
   396  		cmd.Args = append(cmd.Args, "std")
   397  		if !t.race {
   398  			cmd.Args = append(cmd.Args, "cmd")
   399  		}
   400  		all, err := cmd.Output()
   401  		if err != nil {
   402  			log.Fatalf("Error running go list std cmd: %v, %s", err, all)
   403  		}
   404  		pkgs := strings.Fields(string(all))
   405  		for _, pkg := range pkgs {
   406  			t.registerStdTest(pkg)
   407  		}
   408  		if t.race {
   409  			for _, pkg := range pkgs {
   410  				if t.packageHasBenchmarks(pkg) {
   411  					t.registerRaceBenchTest(pkg)
   412  				}
   413  			}
   414  		}
   415  	}
   416  
   417  	if t.race {
   418  		return
   419  	}
   420  
   421  	// Runtime CPU tests.
   422  	if !t.compileOnly {
   423  		testName := "runtime:cpu124"
   424  		t.tests = append(t.tests, distTest{
   425  			name:    testName,
   426  			heading: "GOMAXPROCS=2 runtime -cpu=1,2,4",
   427  			fn: func(dt *distTest) error {
   428  				cmd := t.addCmd(dt, "src", "go", "test", "-short", t.timeout(300), t.tags(), "runtime", "-cpu=1,2,4")
   429  				// We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
   430  				// creation of first goroutines and first garbage collections in the parallel setting.
   431  				cmd.Env = append(os.Environ(), "GOMAXPROCS=2")
   432  				return nil
   433  			},
   434  		})
   435  	}
   436  
   437  	// On the builders only, test that a moved GOROOT still works.
   438  	// Fails on iOS because CC_FOR_TARGET refers to clangwrap.sh
   439  	// in the unmoved GOROOT.
   440  	// Fails on Android with an exec format error.
   441  	// Fails on plan9 with "cannot find GOROOT" (issue #21016).
   442  	if os.Getenv("GO_BUILDER_NAME") != "" && t.goos != "android" && !t.iOS() && t.goos != "plan9" {
   443  		t.tests = append(t.tests, distTest{
   444  			name:    "moved_goroot",
   445  			heading: "moved GOROOT",
   446  			fn: func(dt *distTest) error {
   447  				t.runPending(dt)
   448  				moved := t.goroot + "-moved"
   449  				if err := os.Rename(t.goroot, moved); err != nil {
   450  					if t.goos == "windows" {
   451  						// Fails on Windows (with "Access is denied") if a process
   452  						// or binary is in this directory. For instance, using all.bat
   453  						// when run from c:\workdir\go\src fails here
   454  						// if GO_BUILDER_NAME is set. Our builders invoke tests
   455  						// a different way which happens to work when sharding
   456  						// tests, but we should be tolerant of the non-sharded
   457  						// all.bat case.
   458  						log.Printf("skipping test on Windows")
   459  						return nil
   460  					}
   461  					return err
   462  				}
   463  
   464  				// Run `go test fmt` in the moved GOROOT.
   465  				cmd := exec.Command(filepath.Join(moved, "bin", "go"), "test", "fmt")
   466  				cmd.Stdout = os.Stdout
   467  				cmd.Stderr = os.Stderr
   468  				// Don't set GOROOT in the environment.
   469  				for _, e := range os.Environ() {
   470  					if !strings.HasPrefix(e, "GOROOT=") {
   471  						cmd.Env = append(cmd.Env, e)
   472  					}
   473  				}
   474  				err := cmd.Run()
   475  
   476  				if rerr := os.Rename(moved, t.goroot); rerr != nil {
   477  					log.Fatalf("failed to restore GOROOT: %v", rerr)
   478  				}
   479  				return err
   480  			},
   481  		})
   482  	}
   483  
   484  	// Test that internal linking of standard packages does not
   485  	// require libgcc. This ensures that we can install a Go
   486  	// release on a system that does not have a C compiler
   487  	// installed and still build Go programs (that don't use cgo).
   488  	for _, pkg := range cgoPackages {
   489  		if !t.internalLink() {
   490  			break
   491  		}
   492  
   493  		// ARM libgcc may be Thumb, which internal linking does not support.
   494  		if t.goarch == "arm" {
   495  			break
   496  		}
   497  
   498  		pkg := pkg
   499  		var run string
   500  		if pkg == "net" {
   501  			run = "TestTCPStress"
   502  		}
   503  		t.tests = append(t.tests, distTest{
   504  			name:    "nolibgcc:" + pkg,
   505  			heading: "Testing without libgcc.",
   506  			fn: func(dt *distTest) error {
   507  				t.addCmd(dt, "src", "go", "test", "-short", "-ldflags=-linkmode=internal -libgcc=none", t.tags(), pkg, t.runFlag(run))
   508  				return nil
   509  			},
   510  		})
   511  	}
   512  
   513  	// Test internal linking of PIE binaries where it is supported.
   514  	if t.goos == "linux" && t.goarch == "amd64" && !isAlpineLinux() {
   515  		// Issue 18243: We don't have a way to set the default
   516  		// dynamic linker used in internal linking mode. So
   517  		// this test is skipped on Alpine.
   518  		t.tests = append(t.tests, distTest{
   519  			name:    "pie_internal",
   520  			heading: "internal linking of -buildmode=pie",
   521  			fn: func(dt *distTest) error {
   522  				t.addCmd(dt, "src", "go", "test", "reflect", "-short", "-buildmode=pie", "-ldflags=-linkmode=internal", t.timeout(60), t.tags(), t.runFlag(""))
   523  				return nil
   524  			},
   525  		})
   526  	}
   527  
   528  	// sync tests
   529  	t.tests = append(t.tests, distTest{
   530  		name:    "sync_cpu",
   531  		heading: "sync -cpu=10",
   532  		fn: func(dt *distTest) error {
   533  			t.addCmd(dt, "src", "go", "test", "sync", "-short", t.timeout(120), t.tags(), "-cpu=10", t.runFlag(""))
   534  			return nil
   535  		},
   536  	})
   537  
   538  	if t.cgoEnabled && !t.iOS() {
   539  		// Disabled on iOS. golang.org/issue/15919
   540  		t.tests = append(t.tests, distTest{
   541  			name:    "cgo_stdio",
   542  			heading: "../misc/cgo/stdio",
   543  			fn: func(dt *distTest) error {
   544  				t.addCmd(dt, "misc/cgo/stdio", "go", "run", filepath.Join(os.Getenv("GOROOT"), "test/run.go"), "-", ".")
   545  				return nil
   546  			},
   547  		})
   548  		t.tests = append(t.tests, distTest{
   549  			name:    "cgo_life",
   550  			heading: "../misc/cgo/life",
   551  			fn: func(dt *distTest) error {
   552  				t.addCmd(dt, "misc/cgo/life", "go", "run", filepath.Join(os.Getenv("GOROOT"), "test/run.go"), "-", ".")
   553  				return nil
   554  			},
   555  		})
   556  		fortran := os.Getenv("FC")
   557  		if fortran == "" {
   558  			fortran, _ = exec.LookPath("gfortran")
   559  		}
   560  		if t.hasBash() && fortran != "" {
   561  			t.tests = append(t.tests, distTest{
   562  				name:    "cgo_fortran",
   563  				heading: "../misc/cgo/fortran",
   564  				fn: func(dt *distTest) error {
   565  					t.addCmd(dt, "misc/cgo/fortran", "./test.bash", fortran)
   566  					return nil
   567  				},
   568  			})
   569  		}
   570  	}
   571  	if t.cgoEnabled {
   572  		t.tests = append(t.tests, distTest{
   573  			name:    "cgo_test",
   574  			heading: "../misc/cgo/test",
   575  			fn:      t.cgoTest,
   576  		})
   577  	}
   578  
   579  	if t.raceDetectorSupported() {
   580  		t.tests = append(t.tests, distTest{
   581  			name:    "race",
   582  			heading: "Testing race detector",
   583  			fn:      t.raceTest,
   584  		})
   585  	}
   586  
   587  	if t.hasBash() && t.cgoEnabled && t.goos != "android" && t.goos != "darwin" {
   588  		t.registerTest("testgodefs", "../misc/cgo/testgodefs", "./test.bash")
   589  	}
   590  	if t.cgoEnabled {
   591  		if t.cgoTestSOSupported() {
   592  			t.tests = append(t.tests, distTest{
   593  				name:    "testso",
   594  				heading: "../misc/cgo/testso",
   595  				fn: func(dt *distTest) error {
   596  					return t.cgoTestSO(dt, "misc/cgo/testso")
   597  				},
   598  			})
   599  			t.tests = append(t.tests, distTest{
   600  				name:    "testsovar",
   601  				heading: "../misc/cgo/testsovar",
   602  				fn: func(dt *distTest) error {
   603  					return t.cgoTestSO(dt, "misc/cgo/testsovar")
   604  				},
   605  			})
   606  		}
   607  		if t.supportedBuildmode("c-archive") {
   608  			t.registerHostTest("testcarchive", "../misc/cgo/testcarchive", "misc/cgo/testcarchive", "carchive_test.go")
   609  		}
   610  		if t.supportedBuildmode("c-shared") {
   611  			t.registerTest("testcshared", "../misc/cgo/testcshared", "./test.bash")
   612  		}
   613  		if t.supportedBuildmode("shared") {
   614  			t.registerTest("testshared", "../misc/cgo/testshared", "go", "test")
   615  		}
   616  		if t.supportedBuildmode("plugin") {
   617  			t.registerTest("testplugin", "../misc/cgo/testplugin", "./test.bash")
   618  		}
   619  		if t.gohostos == "linux" && t.goarch == "amd64" {
   620  			t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go")
   621  		}
   622  		if t.goos == "linux" && t.goarch == "amd64" {
   623  			t.registerTest("testsanitizers", "../misc/cgo/testsanitizers", "./test.bash")
   624  		}
   625  		if t.hasBash() && t.goos != "android" && !t.iOS() && t.gohostos != "windows" {
   626  			t.registerTest("cgo_errors", "../misc/cgo/errors", "./test.bash")
   627  		}
   628  		if t.gohostos == "linux" && t.extLink() {
   629  			t.registerTest("testsigfwd", "../misc/cgo/testsigfwd", "go", "run", "main.go")
   630  		}
   631  	}
   632  
   633  	// Doc tests only run on builders.
   634  	// They find problems approximately never.
   635  	if t.hasBash() && t.goos != "nacl" && t.goos != "android" && !t.iOS() && os.Getenv("GO_BUILDER_NAME") != "" {
   636  		t.registerTest("doc_progs", "../doc/progs", "time", "go", "run", "run.go")
   637  		t.registerTest("wiki", "../doc/articles/wiki", "./test.bash")
   638  		t.registerTest("codewalk", "../doc/codewalk", "time", "./run")
   639  	}
   640  
   641  	if t.goos != "android" && !t.iOS() {
   642  		t.registerTest("bench_go1", "../test/bench/go1", "go", "test", t.timeout(600), t.runFlag(""))
   643  	}
   644  	if t.goos != "android" && !t.iOS() {
   645  		// Only start multiple test dir shards on builders,
   646  		// where they get distributed to multiple machines.
   647  		// See issue 20141.
   648  		nShards := 1
   649  		if os.Getenv("GO_BUILDER_NAME") != "" {
   650  			nShards = 10
   651  		}
   652  		for shard := 0; shard < nShards; shard++ {
   653  			shard := shard
   654  			t.tests = append(t.tests, distTest{
   655  				name:    fmt.Sprintf("test:%d_%d", shard, nShards),
   656  				heading: "../test",
   657  				fn:      func(dt *distTest) error { return t.testDirTest(dt, shard, nShards) },
   658  			})
   659  		}
   660  	}
   661  	if t.goos != "nacl" && t.goos != "android" && !t.iOS() {
   662  		t.tests = append(t.tests, distTest{
   663  			name:    "api",
   664  			heading: "API check",
   665  			fn: func(dt *distTest) error {
   666  				if t.compileOnly {
   667  					t.addCmd(dt, "src", "go", "build", filepath.Join(t.goroot, "src/cmd/api/run.go"))
   668  					return nil
   669  				}
   670  				t.addCmd(dt, "src", "go", "run", filepath.Join(t.goroot, "src/cmd/api/run.go"))
   671  				return nil
   672  			},
   673  		})
   674  	}
   675  }
   676  
   677  // isRegisteredTestName reports whether a test named testName has already
   678  // been registered.
   679  func (t *tester) isRegisteredTestName(testName string) bool {
   680  	for _, tt := range t.tests {
   681  		if tt.name == testName {
   682  			return true
   683  		}
   684  	}
   685  	return false
   686  }
   687  
   688  func (t *tester) registerTest1(seq bool, name, dirBanner, bin string, args ...string) {
   689  	if bin == "time" && !t.haveTime {
   690  		bin, args = args[0], args[1:]
   691  	}
   692  	if t.isRegisteredTestName(name) {
   693  		panic("duplicate registered test name " + name)
   694  	}
   695  	t.tests = append(t.tests, distTest{
   696  		name:    name,
   697  		heading: dirBanner,
   698  		fn: func(dt *distTest) error {
   699  			if seq {
   700  				t.runPending(dt)
   701  				return t.dirCmd(filepath.Join(t.goroot, "src", dirBanner), bin, args...).Run()
   702  			}
   703  			t.addCmd(dt, filepath.Join(t.goroot, "src", dirBanner), bin, args...)
   704  			return nil
   705  		},
   706  	})
   707  }
   708  
   709  func (t *tester) registerTest(name, dirBanner, bin string, args ...string) {
   710  	t.registerTest1(false, name, dirBanner, bin, args...)
   711  }
   712  
   713  func (t *tester) registerSeqTest(name, dirBanner, bin string, args ...string) {
   714  	t.registerTest1(true, name, dirBanner, bin, args...)
   715  }
   716  
   717  func (t *tester) bgDirCmd(dir, bin string, args ...string) *exec.Cmd {
   718  	cmd := exec.Command(bin, args...)
   719  	if filepath.IsAbs(dir) {
   720  		cmd.Dir = dir
   721  	} else {
   722  		cmd.Dir = filepath.Join(t.goroot, dir)
   723  	}
   724  	return cmd
   725  }
   726  
   727  func (t *tester) dirCmd(dir, bin string, args ...string) *exec.Cmd {
   728  	cmd := t.bgDirCmd(dir, bin, args...)
   729  	cmd.Stdout = os.Stdout
   730  	cmd.Stderr = os.Stderr
   731  	if vflag > 1 {
   732  		errprintf("%s\n", strings.Join(cmd.Args, " "))
   733  	}
   734  	return cmd
   735  }
   736  
   737  func (t *tester) addCmd(dt *distTest, dir, bin string, args ...string) *exec.Cmd {
   738  	w := &work{
   739  		dt:  dt,
   740  		cmd: t.bgDirCmd(dir, bin, args...),
   741  	}
   742  	t.worklist = append(t.worklist, w)
   743  	return w.cmd
   744  }
   745  
   746  func (t *tester) iOS() bool {
   747  	return t.goos == "darwin" && (t.goarch == "arm" || t.goarch == "arm64")
   748  }
   749  
   750  func (t *tester) out(v string) {
   751  	if t.banner == "" {
   752  		return
   753  	}
   754  	fmt.Println("\n" + t.banner + v)
   755  }
   756  
   757  func (t *tester) extLink() bool {
   758  	pair := t.gohostos + "-" + t.goarch
   759  	switch pair {
   760  	case "android-arm",
   761  		"darwin-arm", "darwin-arm64",
   762  		"dragonfly-386", "dragonfly-amd64",
   763  		"freebsd-386", "freebsd-amd64", "freebsd-arm",
   764  		"linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le", "linux-mips", "linux-mipsle", "linux-s390x",
   765  		"netbsd-386", "netbsd-amd64",
   766  		"openbsd-386", "openbsd-amd64",
   767  		"windows-386", "windows-amd64":
   768  		return true
   769  	case "darwin-386", "darwin-amd64":
   770  		// linkmode=external fails on OS X 10.6 and earlier == Darwin
   771  		// 10.8 and earlier.
   772  		unameR, err := exec.Command("uname", "-r").Output()
   773  		if err != nil {
   774  			log.Fatalf("uname -r: %v", err)
   775  		}
   776  		major, _ := strconv.Atoi(string(unameR[:bytes.IndexByte(unameR, '.')]))
   777  		return major > 10
   778  	}
   779  	return false
   780  }
   781  
   782  func (t *tester) internalLink() bool {
   783  	if t.gohostos == "dragonfly" {
   784  		// linkmode=internal fails on dragonfly since errno is a TLS relocation.
   785  		return false
   786  	}
   787  	if t.gohostarch == "ppc64le" {
   788  		// linkmode=internal fails on ppc64le because cmd/link doesn't
   789  		// handle the TOC correctly (issue 15409).
   790  		return false
   791  	}
   792  	if t.goos == "android" {
   793  		return false
   794  	}
   795  	if t.goos == "darwin" && (t.goarch == "arm" || t.goarch == "arm64") {
   796  		return false
   797  	}
   798  	// Internally linking cgo is incomplete on some architectures.
   799  	// https://golang.org/issue/10373
   800  	// https://golang.org/issue/14449
   801  	if t.goarch == "arm64" || t.goarch == "mips64" || t.goarch == "mips64le" || t.goarch == "mips" || t.goarch == "mipsle" {
   802  		return false
   803  	}
   804  	if isAlpineLinux() {
   805  		// Issue 18243.
   806  		return false
   807  	}
   808  	return true
   809  }
   810  
   811  func (t *tester) supportedBuildmode(mode string) bool {
   812  	pair := t.goos + "-" + t.goarch
   813  	switch mode {
   814  	case "c-archive":
   815  		if !t.extLink() {
   816  			return false
   817  		}
   818  		switch pair {
   819  		case "darwin-386", "darwin-amd64", "darwin-arm", "darwin-arm64",
   820  			"linux-amd64", "linux-386", "linux-ppc64le",
   821  			"windows-amd64", "windows-386":
   822  			return true
   823  		}
   824  		return false
   825  	case "c-shared":
   826  		switch pair {
   827  		case "linux-386", "linux-amd64", "linux-arm", "linux-arm64",
   828  			"darwin-amd64", "darwin-386",
   829  			"android-arm", "android-arm64", "android-386":
   830  			return true
   831  		}
   832  		return false
   833  	case "shared":
   834  		switch pair {
   835  		case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x":
   836  			return true
   837  		}
   838  		return false
   839  	case "plugin":
   840  		if os.Getenv("GO_BUILDER_NAME") == "linux-amd64-noopt" {
   841  			// Skip the plugin tests on noopt. They're
   842  			// causing build failures potentially
   843  			// obscuring other issues. This is hopefully a
   844  			// temporary workaround. See golang.org/issue/17937.
   845  			return false
   846  		}
   847  
   848  		// linux-arm64 is missing because it causes the external linker
   849  		// to crash, see https://golang.org/issue/17138
   850  		switch pair {
   851  		case "linux-386", "linux-amd64", "linux-arm", "linux-s390x":
   852  			return true
   853  		}
   854  		return false
   855  	default:
   856  		log.Fatalf("internal error: unknown buildmode %s", mode)
   857  		return false
   858  	}
   859  }
   860  
   861  func (t *tester) registerHostTest(name, heading, dir, pkg string) {
   862  	t.tests = append(t.tests, distTest{
   863  		name:    name,
   864  		heading: heading,
   865  		fn: func(dt *distTest) error {
   866  			t.runPending(dt)
   867  			return t.runHostTest(dir, pkg)
   868  		},
   869  	})
   870  }
   871  
   872  func (t *tester) runHostTest(dir, pkg string) error {
   873  	defer os.Remove(filepath.Join(t.goroot, dir, "test.test"))
   874  	cmd := t.dirCmd(dir, "go", "test", t.tags(), "-c", "-o", "test.test", pkg)
   875  	cmd.Env = append(os.Environ(), "GOARCH="+t.gohostarch, "GOOS="+t.gohostos)
   876  	if err := cmd.Run(); err != nil {
   877  		return err
   878  	}
   879  	return t.dirCmd(dir, "./test.test").Run()
   880  }
   881  
   882  func (t *tester) cgoTest(dt *distTest) error {
   883  	env := append(os.Environ(), "GOTRACEBACK=2")
   884  
   885  	cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", t.tags(), "-ldflags", "-linkmode=auto", t.runFlag(""))
   886  	cmd.Env = env
   887  
   888  	if t.internalLink() {
   889  		cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-ldflags", "-linkmode=internal", t.runFlag(""))
   890  		cmd.Env = env
   891  	}
   892  
   893  	pair := t.gohostos + "-" + t.goarch
   894  	switch pair {
   895  	case "darwin-386", "darwin-amd64",
   896  		"openbsd-386", "openbsd-amd64",
   897  		"windows-386", "windows-amd64":
   898  		// test linkmode=external, but __thread not supported, so skip testtls.
   899  		if !t.extLink() {
   900  			break
   901  		}
   902  		cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-ldflags", "-linkmode=external")
   903  		cmd.Env = env
   904  		cmd = t.addCmd(dt, "misc/cgo/test", "go", "test", "-ldflags", "-linkmode=external -s")
   905  		cmd.Env = env
   906  	case "android-arm",
   907  		"dragonfly-386", "dragonfly-amd64",
   908  		"freebsd-386", "freebsd-amd64", "freebsd-arm",
   909  		"linux-386", "linux-amd64", "linux-arm", "linux-ppc64le", "linux-s390x",
   910  		"netbsd-386", "netbsd-amd64":
   911  
   912  		cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-ldflags", "-linkmode=external")
   913  		cmd.Env = env
   914  
   915  		cmd = t.addCmd(dt, "misc/cgo/testtls", "go", "test", "-ldflags", "-linkmode=auto")
   916  		cmd.Env = env
   917  
   918  		cmd = t.addCmd(dt, "misc/cgo/testtls", "go", "test", "-ldflags", "-linkmode=external")
   919  		cmd.Env = env
   920  
   921  		switch pair {
   922  		case "netbsd-386", "netbsd-amd64":
   923  			// no static linking
   924  		case "freebsd-arm":
   925  			// -fPIC compiled tls code will use __tls_get_addr instead
   926  			// of __aeabi_read_tp, however, on FreeBSD/ARM, __tls_get_addr
   927  			// is implemented in rtld-elf, so -fPIC isn't compatible with
   928  			// static linking on FreeBSD/ARM with clang. (cgo depends on
   929  			// -fPIC fundamentally.)
   930  		default:
   931  			cc := mustEnv("CC")
   932  			cmd := t.dirCmd("misc/cgo/test",
   933  				cc, "-xc", "-o", "/dev/null", "-static", "-")
   934  			cmd.Env = env
   935  			cmd.Stdin = strings.NewReader("int main() {}")
   936  			if err := cmd.Run(); err != nil {
   937  				fmt.Println("No support for static linking found (lacks libc.a?), skip cgo static linking test.")
   938  			} else {
   939  				if t.goos != "android" {
   940  					cmd = t.addCmd(dt, "misc/cgo/testtls", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
   941  					cmd.Env = env
   942  				}
   943  
   944  				cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test")
   945  				cmd.Env = env
   946  
   947  				cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external`)
   948  				cmd.Env = env
   949  
   950  				if t.goos != "android" {
   951  					cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
   952  					cmd.Env = env
   953  				}
   954  			}
   955  
   956  			if pair != "freebsd-amd64" { // clang -pie fails to link misc/cgo/test
   957  				cmd := t.dirCmd("misc/cgo/test",
   958  					cc, "-xc", "-o", "/dev/null", "-pie", "-")
   959  				cmd.Env = env
   960  				cmd.Stdin = strings.NewReader("int main() {}")
   961  				if err := cmd.Run(); err != nil {
   962  					fmt.Println("No support for -pie found, skip cgo PIE test.")
   963  				} else {
   964  					cmd = t.addCmd(dt, "misc/cgo/test", "go", "test", "-ldflags", `-linkmode=external -extldflags "-pie"`)
   965  					cmd.Env = env
   966  
   967  					cmd = t.addCmd(dt, "misc/cgo/testtls", "go", "test", "-ldflags", `-linkmode=external -extldflags "-pie"`)
   968  					cmd.Env = env
   969  
   970  					cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external -extldflags "-pie"`)
   971  					cmd.Env = env
   972  
   973  				}
   974  			}
   975  		}
   976  	}
   977  
   978  	return nil
   979  }
   980  
   981  // run pending test commands, in parallel, emitting headers as appropriate.
   982  // When finished, emit header for nextTest, which is going to run after the
   983  // pending commands are done (and runPending returns).
   984  // A test should call runPending if it wants to make sure that it is not
   985  // running in parallel with earlier tests, or if it has some other reason
   986  // for needing the earlier tests to be done.
   987  func (t *tester) runPending(nextTest *distTest) {
   988  	worklist := t.worklist
   989  	t.worklist = nil
   990  	for _, w := range worklist {
   991  		w.start = make(chan bool)
   992  		w.end = make(chan bool)
   993  		go func(w *work) {
   994  			if !<-w.start {
   995  				w.out = []byte(fmt.Sprintf("skipped due to earlier error\n"))
   996  			} else {
   997  				w.out, w.err = w.cmd.CombinedOutput()
   998  			}
   999  			w.end <- true
  1000  		}(w)
  1001  	}
  1002  
  1003  	started := 0
  1004  	ended := 0
  1005  	var last *distTest
  1006  	for ended < len(worklist) {
  1007  		for started < len(worklist) && started-ended < maxbg {
  1008  			//println("start", started)
  1009  			w := worklist[started]
  1010  			started++
  1011  			w.start <- !t.failed || t.keepGoing
  1012  		}
  1013  		w := worklist[ended]
  1014  		dt := w.dt
  1015  		if dt.heading != "" && t.lastHeading != dt.heading {
  1016  			t.lastHeading = dt.heading
  1017  			t.out(dt.heading)
  1018  		}
  1019  		if dt != last {
  1020  			// Assumes all the entries for a single dt are in one worklist.
  1021  			last = w.dt
  1022  			if vflag > 0 {
  1023  				fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
  1024  			}
  1025  		}
  1026  		if vflag > 1 {
  1027  			errprintf("%s\n", strings.Join(w.cmd.Args, " "))
  1028  		}
  1029  		//println("wait", ended)
  1030  		ended++
  1031  		<-w.end
  1032  		os.Stdout.Write(w.out)
  1033  		if w.err != nil {
  1034  			log.Printf("Failed: %v", w.err)
  1035  			t.failed = true
  1036  		}
  1037  	}
  1038  	if t.failed && !t.keepGoing {
  1039  		log.Fatal("FAILED")
  1040  	}
  1041  
  1042  	if dt := nextTest; dt != nil {
  1043  		if dt.heading != "" && t.lastHeading != dt.heading {
  1044  			t.lastHeading = dt.heading
  1045  			t.out(dt.heading)
  1046  		}
  1047  		if vflag > 0 {
  1048  			fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
  1049  		}
  1050  	}
  1051  }
  1052  
  1053  func (t *tester) cgoTestSOSupported() bool {
  1054  	if t.goos == "android" || t.iOS() {
  1055  		// No exec facility on Android or iOS.
  1056  		return false
  1057  	}
  1058  	if t.goarch == "ppc64" {
  1059  		// External linking not implemented on ppc64 (issue #8912).
  1060  		return false
  1061  	}
  1062  	if t.goarch == "mips64le" || t.goarch == "mips64" {
  1063  		// External linking not implemented on mips64.
  1064  		return false
  1065  	}
  1066  	return true
  1067  }
  1068  
  1069  func (t *tester) cgoTestSO(dt *distTest, testpath string) error {
  1070  	t.runPending(dt)
  1071  
  1072  	dir := filepath.Join(t.goroot, testpath)
  1073  
  1074  	// build shared object
  1075  	output, err := exec.Command("go", "env", "CC").Output()
  1076  	if err != nil {
  1077  		return fmt.Errorf("Error running go env CC: %v", err)
  1078  	}
  1079  	cc := strings.TrimSuffix(string(output), "\n")
  1080  	if cc == "" {
  1081  		return errors.New("CC environment variable (go env CC) cannot be empty")
  1082  	}
  1083  	output, err = exec.Command("go", "env", "GOGCCFLAGS").Output()
  1084  	if err != nil {
  1085  		return fmt.Errorf("Error running go env GOGCCFLAGS: %v", err)
  1086  	}
  1087  	gogccflags := strings.Split(strings.TrimSuffix(string(output), "\n"), " ")
  1088  
  1089  	ext := "so"
  1090  	args := append(gogccflags, "-shared")
  1091  	switch t.goos {
  1092  	case "darwin":
  1093  		ext = "dylib"
  1094  		args = append(args, "-undefined", "suppress", "-flat_namespace")
  1095  	case "windows":
  1096  		ext = "dll"
  1097  		args = append(args, "-DEXPORT_DLL")
  1098  	}
  1099  	sofname := "libcgosotest." + ext
  1100  	args = append(args, "-o", sofname, "cgoso_c.c")
  1101  
  1102  	if err := t.dirCmd(dir, cc, args...).Run(); err != nil {
  1103  		return err
  1104  	}
  1105  	defer os.Remove(filepath.Join(dir, sofname))
  1106  
  1107  	if err := t.dirCmd(dir, "go", "build", "-o", "main.exe", "main.go").Run(); err != nil {
  1108  		return err
  1109  	}
  1110  	defer os.Remove(filepath.Join(dir, "main.exe"))
  1111  
  1112  	cmd := t.dirCmd(dir, "./main.exe")
  1113  	if t.goos != "windows" {
  1114  		s := "LD_LIBRARY_PATH"
  1115  		if t.goos == "darwin" {
  1116  			s = "DYLD_LIBRARY_PATH"
  1117  		}
  1118  		cmd.Env = append(os.Environ(), s+"=.")
  1119  
  1120  		// On FreeBSD 64-bit architectures, the 32-bit linker looks for
  1121  		// different environment variables.
  1122  		if t.goos == "freebsd" && t.gohostarch == "386" {
  1123  			cmd.Env = append(cmd.Env, "LD_32_LIBRARY_PATH=.")
  1124  		}
  1125  	}
  1126  	return cmd.Run()
  1127  }
  1128  
  1129  func (t *tester) hasBash() bool {
  1130  	switch t.gohostos {
  1131  	case "windows", "plan9":
  1132  		return false
  1133  	}
  1134  	return true
  1135  }
  1136  
  1137  func (t *tester) raceDetectorSupported() bool {
  1138  	switch t.gohostos {
  1139  	case "linux", "darwin", "freebsd", "windows":
  1140  		// The race detector doesn't work on Alpine Linux:
  1141  		// golang.org/issue/14481
  1142  		return t.cgoEnabled && t.goarch == "amd64" && t.gohostos == t.goos && !isAlpineLinux()
  1143  	}
  1144  	return false
  1145  }
  1146  
  1147  func isAlpineLinux() bool {
  1148  	if runtime.GOOS != "linux" {
  1149  		return false
  1150  	}
  1151  	fi, err := os.Lstat("/etc/alpine-release")
  1152  	return err == nil && fi.Mode().IsRegular()
  1153  }
  1154  
  1155  func (t *tester) runFlag(rx string) string {
  1156  	if t.compileOnly {
  1157  		return "-run=^$"
  1158  	}
  1159  	return "-run=" + rx
  1160  }
  1161  
  1162  func (t *tester) raceTest(dt *distTest) error {
  1163  	t.addCmd(dt, "src", "go", "test", "-race", "-i", "runtime/race", "flag", "os", "os/exec")
  1164  	t.addCmd(dt, "src", "go", "test", "-race", t.runFlag("Output"), "runtime/race")
  1165  	t.addCmd(dt, "src", "go", "test", "-race", "-short", t.runFlag("TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace"), "flag", "os", "os/exec")
  1166  	// We don't want the following line, because it
  1167  	// slows down all.bash (by 10 seconds on my laptop).
  1168  	// The race builder should catch any error here, but doesn't.
  1169  	// TODO(iant): Figure out how to catch this.
  1170  	// t.addCmd(dt, "src", "go", "test", "-race", "-run=TestParallelTest", "cmd/go")
  1171  	if t.cgoEnabled {
  1172  		cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-race", "-short", t.runFlag(""))
  1173  		cmd.Env = append(os.Environ(), "GOTRACEBACK=2")
  1174  	}
  1175  	if t.extLink() {
  1176  		// Test with external linking; see issue 9133.
  1177  		t.addCmd(dt, "src", "go", "test", "-race", "-short", "-ldflags=-linkmode=external", t.runFlag("TestParse|TestEcho|TestStdinCloseRace"), "flag", "os/exec")
  1178  	}
  1179  	return nil
  1180  }
  1181  
  1182  var runtest struct {
  1183  	sync.Once
  1184  	exe string
  1185  	err error
  1186  }
  1187  
  1188  func (t *tester) testDirTest(dt *distTest, shard, shards int) error {
  1189  	runtest.Do(func() {
  1190  		const exe = "runtest.exe" // named exe for Windows, but harmless elsewhere
  1191  		cmd := t.dirCmd("test", "go", "build", "-o", exe, "run.go")
  1192  		cmd.Env = append(os.Environ(), "GOOS="+t.gohostos, "GOARCH="+t.gohostarch)
  1193  		runtest.exe = filepath.Join(cmd.Dir, exe)
  1194  		if err := cmd.Run(); err != nil {
  1195  			runtest.err = err
  1196  			return
  1197  		}
  1198  		xatexit(func() {
  1199  			os.Remove(runtest.exe)
  1200  		})
  1201  	})
  1202  	if runtest.err != nil {
  1203  		return runtest.err
  1204  	}
  1205  	if t.compileOnly {
  1206  		return nil
  1207  	}
  1208  	t.addCmd(dt, "test", runtest.exe,
  1209  		fmt.Sprintf("--shard=%d", shard),
  1210  		fmt.Sprintf("--shards=%d", shards),
  1211  	)
  1212  	return nil
  1213  }
  1214  
  1215  // cgoPackages is the standard packages that use cgo.
  1216  var cgoPackages = []string{
  1217  	"crypto/x509",
  1218  	"net",
  1219  	"os/user",
  1220  }
  1221  
  1222  var funcBenchmark = []byte("\nfunc Benchmark")
  1223  
  1224  // packageHasBenchmarks reports whether pkg has benchmarks.
  1225  // On any error, it conservatively returns true.
  1226  //
  1227  // This exists just to eliminate work on the builders, since compiling
  1228  // a test in race mode just to discover it has no benchmarks costs a
  1229  // second or two per package, and this function returns false for
  1230  // about 100 packages.
  1231  func (t *tester) packageHasBenchmarks(pkg string) bool {
  1232  	pkgDir := filepath.Join(t.goroot, "src", pkg)
  1233  	d, err := os.Open(pkgDir)
  1234  	if err != nil {
  1235  		return true // conservatively
  1236  	}
  1237  	defer d.Close()
  1238  	names, err := d.Readdirnames(-1)
  1239  	if err != nil {
  1240  		return true // conservatively
  1241  	}
  1242  	for _, name := range names {
  1243  		if !strings.HasSuffix(name, "_test.go") {
  1244  			continue
  1245  		}
  1246  		slurp, err := ioutil.ReadFile(filepath.Join(pkgDir, name))
  1247  		if err != nil {
  1248  			return true // conservatively
  1249  		}
  1250  		if bytes.Contains(slurp, funcBenchmark) {
  1251  			return true
  1252  		}
  1253  	}
  1254  	return false
  1255  }