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