Home | History | Annotate | Download | only in dist
      1 // Copyright 2015 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package main
      6 
      7 import (
      8 	"bytes"
      9 	"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 
   1214 	// Check that swig was installed with Go support by checking
   1215 	// that a go directory exists inside the swiglib directory.
   1216 	// See https://golang.org/issue/23469.
   1217 	output, err := exec.Command(swig, "-go", "-swiglib").Output()
   1218 	if err != nil {
   1219 		return false
   1220 	}
   1221 	swigDir := strings.TrimSpace(string(output))
   1222 
   1223 	_, err = os.Stat(filepath.Join(swigDir, "go"))
   1224 	if err != nil {
   1225 		return false
   1226 	}
   1227 
   1228 	// Check that swig has a new enough version.
   1229 	// See https://golang.org/issue/22858.
   1230 	out, err := exec.Command(swig, "-version").CombinedOutput()
   1231 	if err != nil {
   1232 		return false
   1233 	}
   1234 
   1235 	re := regexp.MustCompile(`[vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)?`)
   1236 	matches := re.FindSubmatch(out)
   1237 	if matches == nil {
   1238 		// Can't find version number; hope for the best.
   1239 		return true
   1240 	}
   1241 
   1242 	major, err := strconv.Atoi(string(matches[1]))
   1243 	if err != nil {
   1244 		// Can't find version number; hope for the best.
   1245 		return true
   1246 	}
   1247 	if major < 3 {
   1248 		return false
   1249 	}
   1250 	if major > 3 {
   1251 		// 4.0 or later
   1252 		return true
   1253 	}
   1254 
   1255 	// We have SWIG version 3.x.
   1256 	if len(matches[2]) > 0 {
   1257 		minor, err := strconv.Atoi(string(matches[2][1:]))
   1258 		if err != nil {
   1259 			return true
   1260 		}
   1261 		if minor > 0 {
   1262 			// 3.1 or later
   1263 			return true
   1264 		}
   1265 	}
   1266 
   1267 	// We have SWIG version 3.0.x.
   1268 	if len(matches[3]) > 0 {
   1269 		patch, err := strconv.Atoi(string(matches[3][1:]))
   1270 		if err != nil {
   1271 			return true
   1272 		}
   1273 		if patch < 6 {
   1274 			// Before 3.0.6.
   1275 			return false
   1276 		}
   1277 	}
   1278 
   1279 	return true
   1280 }
   1281 
   1282 func (t *tester) raceDetectorSupported() bool {
   1283 	switch gohostos {
   1284 	case "linux", "darwin", "freebsd", "windows":
   1285 		// The race detector doesn't work on Alpine Linux:
   1286 		// golang.org/issue/14481
   1287 		return t.cgoEnabled && goarch == "amd64" && gohostos == goos && !isAlpineLinux()
   1288 	}
   1289 	return false
   1290 }
   1291 
   1292 func isAlpineLinux() bool {
   1293 	if runtime.GOOS != "linux" {
   1294 		return false
   1295 	}
   1296 	fi, err := os.Lstat("/etc/alpine-release")
   1297 	return err == nil && fi.Mode().IsRegular()
   1298 }
   1299 
   1300 func (t *tester) runFlag(rx string) string {
   1301 	if t.compileOnly {
   1302 		return "-run=^$"
   1303 	}
   1304 	return "-run=" + rx
   1305 }
   1306 
   1307 func (t *tester) raceTest(dt *distTest) error {
   1308 	t.addCmd(dt, "src", t.goTest(), "-race", "-i", "runtime/race", "flag", "os", "os/exec")
   1309 	t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("Output"), "runtime/race")
   1310 	t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace|TestTypeRace"), "flag", "os", "os/exec", "encoding/gob")
   1311 	// We don't want the following line, because it
   1312 	// slows down all.bash (by 10 seconds on my laptop).
   1313 	// The race builder should catch any error here, but doesn't.
   1314 	// TODO(iant): Figure out how to catch this.
   1315 	// t.addCmd(dt, "src", t.goTest(),  "-race", "-run=TestParallelTest", "cmd/go")
   1316 	if t.cgoEnabled {
   1317 		cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-race")
   1318 		cmd.Env = append(os.Environ(), "GOTRACEBACK=2")
   1319 	}
   1320 	if t.extLink() {
   1321 		// Test with external linking; see issue 9133.
   1322 		t.addCmd(dt, "src", t.goTest(), "-race", "-ldflags=-linkmode=external", t.runFlag("TestParse|TestEcho|TestStdinCloseRace"), "flag", "os/exec")
   1323 	}
   1324 	return nil
   1325 }
   1326 
   1327 var runtest struct {
   1328 	sync.Once
   1329 	exe string
   1330 	err error
   1331 }
   1332 
   1333 func (t *tester) testDirTest(dt *distTest, shard, shards int) error {
   1334 	runtest.Do(func() {
   1335 		const exe = "runtest.exe" // named exe for Windows, but harmless elsewhere
   1336 		cmd := t.dirCmd("test", "go", "build", "-o", exe, "run.go")
   1337 		cmd.Env = append(os.Environ(), "GOOS="+gohostos, "GOARCH="+gohostarch)
   1338 		runtest.exe = filepath.Join(cmd.Dir, exe)
   1339 		if err := cmd.Run(); err != nil {
   1340 			runtest.err = err
   1341 			return
   1342 		}
   1343 		xatexit(func() {
   1344 			os.Remove(runtest.exe)
   1345 		})
   1346 	})
   1347 	if runtest.err != nil {
   1348 		return runtest.err
   1349 	}
   1350 	if t.compileOnly {
   1351 		return nil
   1352 	}
   1353 	t.addCmd(dt, "test", runtest.exe,
   1354 		fmt.Sprintf("--shard=%d", shard),
   1355 		fmt.Sprintf("--shards=%d", shards),
   1356 	)
   1357 	return nil
   1358 }
   1359 
   1360 // cgoPackages is the standard packages that use cgo.
   1361 var cgoPackages = []string{
   1362 	"crypto/x509",
   1363 	"net",
   1364 	"os/user",
   1365 }
   1366 
   1367 var funcBenchmark = []byte("\nfunc Benchmark")
   1368 
   1369 // packageHasBenchmarks reports whether pkg has benchmarks.
   1370 // On any error, it conservatively returns true.
   1371 //
   1372 // This exists just to eliminate work on the builders, since compiling
   1373 // a test in race mode just to discover it has no benchmarks costs a
   1374 // second or two per package, and this function returns false for
   1375 // about 100 packages.
   1376 func (t *tester) packageHasBenchmarks(pkg string) bool {
   1377 	pkgDir := filepath.Join(goroot, "src", pkg)
   1378 	d, err := os.Open(pkgDir)
   1379 	if err != nil {
   1380 		return true // conservatively
   1381 	}
   1382 	defer d.Close()
   1383 	names, err := d.Readdirnames(-1)
   1384 	if err != nil {
   1385 		return true // conservatively
   1386 	}
   1387 	for _, name := range names {
   1388 		if !strings.HasSuffix(name, "_test.go") {
   1389 			continue
   1390 		}
   1391 		slurp, err := ioutil.ReadFile(filepath.Join(pkgDir, name))
   1392 		if err != nil {
   1393 			return true // conservatively
   1394 		}
   1395 		if bytes.Contains(slurp, funcBenchmark) {
   1396 			return true
   1397 		}
   1398 	}
   1399 	return false
   1400 }
   1401