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