...

Source file src/cmd/dist/test.go

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

View as plain text