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  	"encoding/json"
    10  	"flag"
    11  	"fmt"
    12  	"io"
    13  	"io/fs"
    14  	"log"
    15  	"os"
    16  	"os/exec"
    17  	"path/filepath"
    18  	"reflect"
    19  	"regexp"
    20  	"runtime"
    21  	"slices"
    22  	"strconv"
    23  	"strings"
    24  	"time"
    25  )
    26  
    27  func cmdtest() {
    28  	gogcflags = os.Getenv("GO_GCFLAGS")
    29  	setNoOpt()
    30  
    31  	var t tester
    32  
    33  	t.asmflags = os.Getenv("GO_TEST_ASMFLAGS")
    34  
    35  	var noRebuild bool
    36  	flag.BoolVar(&t.listMode, "list", false, "list available tests")
    37  	flag.BoolVar(&t.rebuild, "rebuild", false, "rebuild everything first")
    38  	flag.BoolVar(&noRebuild, "no-rebuild", false, "overrides -rebuild (historical dreg)")
    39  	flag.BoolVar(&t.keepGoing, "k", false, "keep going even when error occurred")
    40  	flag.BoolVar(&t.race, "race", false, "run in race builder mode (different set of tests)")
    41  	flag.BoolVar(&t.compileOnly, "compile-only", false, "compile tests, but don't run them")
    42  	flag.StringVar(&t.banner, "banner", "##### ", "banner prefix; blank means no section banners")
    43  	flag.StringVar(&t.runRxStr, "run", "",
    44  		"run only those tests matching the regular expression; empty means to run all. "+
    45  			"Special exception: if the string begins with '!', the match is inverted.")
    46  	flag.BoolVar(&t.msan, "msan", false, "run in memory sanitizer builder mode")
    47  	flag.BoolVar(&t.asan, "asan", false, "run in address sanitizer builder mode")
    48  	flag.BoolVar(&t.json, "json", false, "report test results in JSON")
    49  	flag.StringVar(&t.artifactsDir, "artifacts-dir", "", "save test artifacts in the specified directory")
    50  
    51  	xflagparse(-1) // any number of args
    52  	if noRebuild {
    53  		t.rebuild = false
    54  	}
    55  
    56  	t.run()
    57  }
    58  
    59  // tester executes cmdtest.
    60  type tester struct {
    61  	race         bool
    62  	msan         bool
    63  	asan         bool
    64  	listMode     bool
    65  	rebuild      bool
    66  	failed       bool
    67  	keepGoing    bool
    68  	compileOnly  bool // just try to compile all tests, but no need to run
    69  	short        bool
    70  	cgoEnabled   bool
    71  	asmflags     string
    72  	json         bool
    73  	artifactsDir string
    74  	runRxStr     string
    75  	runRx        *regexp.Regexp
    76  	runRxWant    bool     // want runRx to match (true) or not match (false)
    77  	runNames     []string // tests to run, exclusive with runRx; empty means all
    78  	banner       string   // prefix, or "" for none
    79  	lastHeading  string   // last dir heading printed
    80  
    81  	tests        []distTest // use addTest to extend
    82  	testNames    map[string]bool
    83  	timeoutScale int // a non-negative integer factor to scale test timeout by; defaults to 1
    84  
    85  	worklist []*work
    86  }
    87  
    88  // work tracks command execution for a test.
    89  type work struct {
    90  	dt    *distTest     // unique test name, etc.
    91  	cmd   *exec.Cmd     // must write stdout/stderr to out
    92  	flush func()        // if non-nil, called after cmd.Run
    93  	start chan bool     // a true means to start, a false means to skip
    94  	out   bytes.Buffer  // combined stdout/stderr from cmd
    95  	err   error         // work result
    96  	end   chan struct{} // a value means cmd ended (or was skipped)
    97  }
    98  
    99  // printSkip prints a skip message for all of work.
   100  func (w *work) printSkip(t *tester, msg string) {
   101  	if t.json {
   102  		synthesizeSkipEvent(json.NewEncoder(&w.out), w.dt.name, msg)
   103  		return
   104  	}
   105  	fmt.Fprintln(&w.out, msg)
   106  }
   107  
   108  // A distTest is a test run by dist test.
   109  // Each test has a unique name and belongs to a group (heading)
   110  type distTest struct {
   111  	name    string // unique test name; may be filtered with -run flag
   112  	heading string // group section; this header is printed before the test is run.
   113  	fn      func(*distTest) error
   114  }
   115  
   116  func (t *tester) run() {
   117  	timelog("start", "dist test")
   118  
   119  	os.Setenv("PATH", fmt.Sprintf("%s%c%s", gorootBin, os.PathListSeparator, os.Getenv("PATH")))
   120  
   121  	t.short = true
   122  	if v := os.Getenv("GO_TEST_SHORT"); v != "" {
   123  		short, err := strconv.ParseBool(v)
   124  		if err != nil {
   125  			fatalf("invalid GO_TEST_SHORT %q: %v", v, err)
   126  		}
   127  		t.short = short
   128  	}
   129  
   130  	cmd := exec.Command(gorootBinGo, "env", "CGO_ENABLED")
   131  	cmd.Stderr = new(bytes.Buffer)
   132  	slurp, err := cmd.Output()
   133  	if err != nil {
   134  		fatalf("Error running %s: %v\n%s", cmd, err, cmd.Stderr)
   135  	}
   136  	parts := strings.Split(string(slurp), "\n")
   137  	if nlines := len(parts) - 1; nlines < 1 {
   138  		fatalf("Error running %s: output contains <1 lines\n%s", cmd, cmd.Stderr)
   139  	}
   140  	t.cgoEnabled, _ = strconv.ParseBool(parts[0])
   141  
   142  	if flag.NArg() > 0 && t.runRxStr != "" {
   143  		fatalf("the -run regular expression flag is mutually exclusive with test name arguments")
   144  	}
   145  
   146  	t.runNames = flag.Args()
   147  
   148  	// Set GOTRACEBACK to system if the user didn't set a level explicitly.
   149  	// Since we're running tests for Go, we want as much detail as possible
   150  	// if something goes wrong.
   151  	//
   152  	// Set it before running any commands just in case something goes wrong.
   153  	if ok := isEnvSet("GOTRACEBACK"); !ok {
   154  		if err := os.Setenv("GOTRACEBACK", "system"); err != nil {
   155  			if t.keepGoing {
   156  				log.Printf("Failed to set GOTRACEBACK: %v", err)
   157  			} else {
   158  				fatalf("Failed to set GOTRACEBACK: %v", err)
   159  			}
   160  		}
   161  	}
   162  
   163  	if t.rebuild {
   164  		t.out("Building packages and commands.")
   165  		// Force rebuild the whole toolchain.
   166  		goInstall(toolenv(), gorootBinGo, append([]string{"-a"}, toolchain...)...)
   167  	}
   168  
   169  	if !t.listMode {
   170  		if builder := os.Getenv("GO_BUILDER_NAME"); builder == "" {
   171  			// Ensure that installed commands are up to date, even with -no-rebuild,
   172  			// so that tests that run commands end up testing what's actually on disk.
   173  			// If everything is up-to-date, this is a no-op.
   174  			// We first build the toolchain twice to allow it to converge,
   175  			// as when we first bootstrap.
   176  			// See cmdbootstrap for a description of the overall process.
   177  			//
   178  			// On the builders, we skip this step: we assume that 'dist test' is
   179  			// already using the result of a clean build, and because of test sharding
   180  			// and virtualization we usually start with a clean GOCACHE, so we would
   181  			// end up rebuilding large parts of the standard library that aren't
   182  			// otherwise relevant to the actual set of packages under test.
   183  			goInstall(toolenv(), gorootBinGo, toolchain...)
   184  			goInstall(toolenv(), gorootBinGo, toolchain...)
   185  			goInstall(toolenv(), gorootBinGo, toolsToInstall...)
   186  		}
   187  	}
   188  
   189  	t.timeoutScale = 1
   190  	if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
   191  		t.timeoutScale, err = strconv.Atoi(s)
   192  		if err != nil {
   193  			fatalf("failed to parse $GO_TEST_TIMEOUT_SCALE = %q as integer: %v", s, err)
   194  		}
   195  	}
   196  
   197  	if t.runRxStr != "" {
   198  		if t.runRxStr[0] == '!' {
   199  			t.runRxWant = false
   200  			t.runRxStr = t.runRxStr[1:]
   201  		} else {
   202  			t.runRxWant = true
   203  		}
   204  		t.runRx = regexp.MustCompile(t.runRxStr)
   205  	}
   206  
   207  	t.registerTests()
   208  	if t.listMode {
   209  		for _, tt := range t.tests {
   210  			fmt.Println(tt.name)
   211  		}
   212  		return
   213  	}
   214  
   215  	for _, name := range t.runNames {
   216  		if !t.testNames[name] {
   217  			fatalf("unknown test %q", name)
   218  		}
   219  	}
   220  
   221  	// On a few builders, make GOROOT unwritable to catch tests writing to it.
   222  	if strings.HasPrefix(os.Getenv("GO_BUILDER_NAME"), "linux-") {
   223  		if os.Getuid() == 0 {
   224  			// Don't bother making GOROOT unwritable:
   225  			// we're running as root, so permissions would have no effect.
   226  		} else {
   227  			xatexit(t.makeGOROOTUnwritable())
   228  		}
   229  	}
   230  
   231  	if !t.json {
   232  		if err := t.maybeLogMetadata(); err != nil {
   233  			t.failed = true
   234  			if t.keepGoing {
   235  				log.Printf("Failed logging metadata: %v", err)
   236  			} else {
   237  				fatalf("Failed logging metadata: %v", err)
   238  			}
   239  		}
   240  	}
   241  
   242  	var anyIncluded, someExcluded bool
   243  	for _, dt := range t.tests {
   244  		if !t.shouldRunTest(dt.name) {
   245  			someExcluded = true
   246  			continue
   247  		}
   248  		anyIncluded = true
   249  		dt := dt // dt used in background after this iteration
   250  		if err := dt.fn(&dt); err != nil {
   251  			t.runPending(&dt) // in case that hasn't been done yet
   252  			t.failed = true
   253  			if t.keepGoing {
   254  				log.Printf("Failed: %v", err)
   255  			} else {
   256  				fatalf("Failed: %v", err)
   257  			}
   258  		}
   259  	}
   260  	t.runPending(nil)
   261  	timelog("end", "dist test")
   262  
   263  	if !t.json {
   264  		if t.failed {
   265  			fmt.Println("\nFAILED")
   266  		} else if !anyIncluded {
   267  			fmt.Println()
   268  			errprintf("go tool dist: warning: %q matched no tests; use the -list flag to list available tests\n", t.runRxStr)
   269  			fmt.Println("NO TESTS TO RUN")
   270  		} else if someExcluded {
   271  			fmt.Println("\nALL TESTS PASSED (some were excluded)")
   272  		} else {
   273  			fmt.Println("\nALL TESTS PASSED")
   274  		}
   275  	}
   276  	if t.failed {
   277  		xexit(1)
   278  	}
   279  }
   280  
   281  func (t *tester) shouldRunTest(name string) bool {
   282  	if t.runRx != nil {
   283  		return t.runRx.MatchString(name) == t.runRxWant
   284  	}
   285  	if len(t.runNames) == 0 {
   286  		return true
   287  	}
   288  	return slices.Contains(t.runNames, name)
   289  }
   290  
   291  func (t *tester) maybeLogMetadata() error {
   292  	if t.compileOnly {
   293  		// We need to run a subprocess to log metadata. Don't do that
   294  		// on compile-only runs.
   295  		return nil
   296  	}
   297  	t.out("Test execution environment.")
   298  	// Helper binary to print system metadata (CPU model, etc). This is a
   299  	// separate binary from dist so it need not build with the bootstrap
   300  	// toolchain.
   301  	//
   302  	// TODO(prattmic): If we split dist bootstrap and dist test then this
   303  	// could be simplified to directly use internal/sysinfo here.
   304  	return t.dirCmd(filepath.Join(goroot, "src/cmd/internal/metadata"), gorootBinGo, []string{"run", "main.go"}).Run()
   305  }
   306  
   307  // testName returns the dist test name for a given package and variant.
   308  func testName(pkg, variant string) string {
   309  	name := pkg
   310  	if variant != "" {
   311  		name += ":" + variant
   312  	}
   313  	return name
   314  }
   315  
   316  // goTest represents all options to a "go test" command. The final command will
   317  // combine configuration from goTest and tester flags.
   318  type goTest struct {
   319  	short    bool     // If true, force -short
   320  	tags     []string // Build tags
   321  	race     bool     // Force -race
   322  	bench    bool     // Run benchmarks (briefly), not tests.
   323  	runTests string   // Regexp of tests to run
   324  	cpu      string   // If non-empty, -cpu flag
   325  	skip     string   // If non-empty, -skip flag
   326  
   327  	gcflags   string // If non-empty, build with -gcflags=all=X
   328  	ldflags   string // If non-empty, build with -ldflags=X
   329  	buildmode string // If non-empty, -buildmode flag
   330  
   331  	env []string // Environment variables to add, as KEY=VAL. KEY= unsets a variable
   332  
   333  	// timeout optionally raises the per-package test timeout to be at least this long.
   334  	// The zero value means to stay with the default test timeout.
   335  	// When adding new tests, this field generally doesn't need to be set, not unless
   336  	// the go commmand's default test timeout proves to be insufficient.
   337  	//
   338  	// In either case, the per-package test timeout get scaled by a multiplier,
   339  	// and applied only if the end result is longer than the go command's default
   340  	// test timeout.
   341  	timeout time.Duration
   342  
   343  	runOnHost bool // When cross-compiling, run this test on the host instead of guest
   344  
   345  	// variant, if non-empty, is a name used to distinguish different
   346  	// configurations of the same test package(s). If set, the Package field
   347  	// in test2json output is rewritten to pkg:variant.
   348  	variant string
   349  
   350  	// We have both pkg and pkgs as a convenience. Both may be set, in which
   351  	// case they will be combined. At least one must be set.
   352  	pkgs []string // Multiple packages to test
   353  	pkg  string   // A single package to test
   354  
   355  	testFlags []string // Additional flags accepted by this test
   356  }
   357  
   358  // compileOnly reports whether this test is only for compiling,
   359  // indicated by runTests being set to '^$' and bench being false.
   360  func (opts *goTest) compileOnly() bool {
   361  	return opts.runTests == "^$" && !opts.bench
   362  }
   363  
   364  // scaledTimeout reports the per-package test timeout scaled by t.timeoutScale.
   365  func (opts *goTest) scaledTimeout(t *tester) time.Duration {
   366  	d := goTestDefaultTimeout
   367  	if opts.timeout != 0 {
   368  		d = opts.timeout
   369  	}
   370  	d *= time.Duration(t.timeoutScale)
   371  	return d
   372  }
   373  
   374  const goTestDefaultTimeout = 10 * time.Minute // Default value of go test -timeout flag.
   375  
   376  // bgCommand returns a go test Cmd and a post-Run flush function. The result
   377  // will write its output to stdout and stderr. If stdout==stderr, bgCommand
   378  // ensures Writes are serialized. The caller should call flush() after Cmd exits.
   379  func (opts *goTest) bgCommand(t *tester, stdout, stderr io.Writer) (cmd *exec.Cmd, flush func()) {
   380  	build, run, pkgs, testFlags, setupCmd := opts.buildArgs(t)
   381  
   382  	// Combine the flags.
   383  	args := append([]string{"test"}, build...)
   384  	if t.compileOnly || opts.compileOnly() {
   385  		args = append(args, "-c", "-o", os.DevNull)
   386  	} else {
   387  		args = append(args, run...)
   388  	}
   389  	args = append(args, pkgs...)
   390  	if !t.compileOnly && !opts.compileOnly() {
   391  		args = append(args, testFlags...)
   392  	}
   393  
   394  	cmd = exec.Command(gorootBinGo, args...)
   395  	setupCmd(cmd)
   396  	if t.json && opts.variant != "" {
   397  		// Rewrite Package in the JSON output to be pkg:variant.
   398  		//
   399  		// We only want to process JSON on the child's stdout. Ideally if
   400  		// stdout==stderr, we would also use the same testJSONFilter for
   401  		// cmd.Stdout and cmd.Stderr in order to keep the underlying
   402  		// interleaving of writes, but then it would see even partial writes
   403  		// interleaved, which would corrupt the JSON. So, we only process
   404  		// cmd.Stdout. This has another consequence though: if stdout==stderr,
   405  		// we have to serialize Writes in case the Writer is not concurrent
   406  		// safe. If we were just passing stdout/stderr through to exec, it would
   407  		// do this for us, but since we're wrapping stdout, we have to do it
   408  		// ourselves.
   409  		if stdout == stderr {
   410  			stdout = &lockedWriter{w: stdout}
   411  			stderr = stdout
   412  		}
   413  		f := &testJSONFilter{w: stdout, variant: opts.variant}
   414  		cmd.Stdout = f
   415  		flush = f.Flush
   416  	} else {
   417  		cmd.Stdout = stdout
   418  		flush = func() {}
   419  	}
   420  	cmd.Stderr = stderr
   421  
   422  	return cmd, flush
   423  }
   424  
   425  // run runs a go test and returns an error if it does not succeed.
   426  func (opts *goTest) run(t *tester) error {
   427  	cmd, flush := opts.bgCommand(t, os.Stdout, os.Stderr)
   428  	err := cmd.Run()
   429  	flush()
   430  	return err
   431  }
   432  
   433  // buildArgs is in internal helper for goTest that constructs the elements of
   434  // the "go test" command line. build is the flags for building the test. run is
   435  // the flags for running the test. pkgs is the list of packages to build and
   436  // run. testFlags is the list of flags to pass to the test package.
   437  //
   438  // The caller must call setupCmd on the resulting exec.Cmd to set its directory
   439  // and environment.
   440  func (opts *goTest) buildArgs(t *tester) (build, run, pkgs, testFlags []string, setupCmd func(*exec.Cmd)) {
   441  	run = append(run, "-count=1") // Disallow caching.
   442  	if d := opts.scaledTimeout(t); d > goTestDefaultTimeout {
   443  		run = append(run, "-timeout="+d.String())
   444  	}
   445  	if opts.short || t.short {
   446  		run = append(run, "-short")
   447  	}
   448  	var tags []string
   449  	if noOpt {
   450  		tags = append(tags, "noopt")
   451  	}
   452  	tags = append(tags, opts.tags...)
   453  	if len(tags) > 0 {
   454  		build = append(build, "-tags="+strings.Join(tags, ","))
   455  	}
   456  	if t.race || opts.race {
   457  		build = append(build, "-race")
   458  	}
   459  	if t.msan {
   460  		build = append(build, "-msan")
   461  	}
   462  	if t.asan {
   463  		build = append(build, "-asan")
   464  	}
   465  	if opts.bench {
   466  		// Run no tests.
   467  		run = append(run, "-run=^$")
   468  		// Run benchmarks briefly as a smoke test.
   469  		run = append(run, "-bench=.*", "-benchtime=.1s")
   470  	} else if opts.runTests != "" {
   471  		run = append(run, "-run="+opts.runTests)
   472  	}
   473  	if opts.cpu != "" {
   474  		run = append(run, "-cpu="+opts.cpu)
   475  	}
   476  	if opts.skip != "" {
   477  		run = append(run, "-skip="+opts.skip)
   478  	}
   479  	if t.json {
   480  		run = append(run, "-json")
   481  	}
   482  	if t.artifactsDir != "" {
   483  		run = append(run, "-artifacts", "-outputdir="+t.artifactsDir)
   484  	}
   485  
   486  	if opts.gcflags != "" {
   487  		build = append(build, "-gcflags=all="+opts.gcflags)
   488  	}
   489  	if opts.ldflags != "" {
   490  		build = append(build, "-ldflags="+opts.ldflags)
   491  	}
   492  	if t.asmflags != "" {
   493  		build = append(build, "-asmflags="+t.asmflags)
   494  	}
   495  	if opts.buildmode != "" {
   496  		build = append(build, "-buildmode="+opts.buildmode)
   497  	}
   498  
   499  	pkgs = opts.packages()
   500  
   501  	runOnHost := opts.runOnHost && (goarch != gohostarch || goos != gohostos)
   502  	needTestFlags := len(opts.testFlags) > 0 || runOnHost
   503  	if needTestFlags {
   504  		testFlags = append([]string{"-args"}, opts.testFlags...)
   505  	}
   506  	if runOnHost {
   507  		// -target is a special flag understood by tests that can run on the host
   508  		testFlags = append(testFlags, "-target="+goos+"/"+goarch)
   509  	}
   510  
   511  	setupCmd = func(cmd *exec.Cmd) {
   512  		setDir(cmd, filepath.Join(goroot, "src"))
   513  		if len(opts.env) != 0 {
   514  			for _, kv := range opts.env {
   515  				if i := strings.Index(kv, "="); i < 0 {
   516  					unsetEnv(cmd, kv[:len(kv)-1])
   517  				} else {
   518  					setEnv(cmd, kv[:i], kv[i+1:])
   519  				}
   520  			}
   521  		}
   522  		if runOnHost {
   523  			setEnv(cmd, "GOARCH", gohostarch)
   524  			setEnv(cmd, "GOOS", gohostos)
   525  		}
   526  	}
   527  
   528  	return
   529  }
   530  
   531  // packages returns the full list of packages to be run by this goTest. This
   532  // will always include at least one package.
   533  func (opts *goTest) packages() []string {
   534  	pkgs := opts.pkgs
   535  	if opts.pkg != "" {
   536  		pkgs = append(pkgs[:len(pkgs):len(pkgs)], opts.pkg)
   537  	}
   538  	if len(pkgs) == 0 {
   539  		panic("no packages")
   540  	}
   541  	return pkgs
   542  }
   543  
   544  // printSkip prints a skip message for all of goTest.
   545  func (opts *goTest) printSkip(t *tester, msg string) {
   546  	if t.json {
   547  		enc := json.NewEncoder(os.Stdout)
   548  		for _, pkg := range opts.packages() {
   549  			synthesizeSkipEvent(enc, pkg, msg)
   550  		}
   551  		return
   552  	}
   553  	fmt.Println(msg)
   554  }
   555  
   556  // ranGoTest and stdMatches are state closed over by the stdlib
   557  // testing func in registerStdTest below. The tests are run
   558  // sequentially, so there's no need for locks.
   559  //
   560  // ranGoBench and benchMatches are the same, but are only used
   561  // in -race mode.
   562  var (
   563  	ranGoTest  bool
   564  	stdMatches []string
   565  
   566  	ranGoBench   bool
   567  	benchMatches []string
   568  )
   569  
   570  func (t *tester) registerStdTest(pkg string) {
   571  	const stdTestHeading = "Testing packages." // known to addTest for a safety check
   572  	gcflags := gogcflags
   573  	name := testName(pkg, "")
   574  	if t.runRx == nil || t.runRx.MatchString(name) == t.runRxWant {
   575  		stdMatches = append(stdMatches, pkg)
   576  	}
   577  	t.addTest(name, stdTestHeading, func(dt *distTest) error {
   578  		if ranGoTest {
   579  			return nil
   580  		}
   581  		t.runPending(dt)
   582  		timelog("start", dt.name)
   583  		defer timelog("end", dt.name)
   584  		ranGoTest = true
   585  
   586  		return (&goTest{
   587  			gcflags: gcflags,
   588  			pkgs:    stdMatches,
   589  		}).run(t)
   590  	})
   591  }
   592  
   593  func (t *tester) registerRaceBenchTest(pkg string) {
   594  	const raceBenchHeading = "Running benchmarks briefly." // known to addTest for a safety check
   595  	name := testName(pkg, "racebench")
   596  	if t.runRx == nil || t.runRx.MatchString(name) == t.runRxWant {
   597  		benchMatches = append(benchMatches, pkg)
   598  	}
   599  	t.addTest(name, raceBenchHeading, func(dt *distTest) error {
   600  		if ranGoBench {
   601  			return nil
   602  		}
   603  		t.runPending(dt)
   604  		timelog("start", dt.name)
   605  		defer timelog("end", dt.name)
   606  		ranGoBench = true
   607  		return (&goTest{
   608  			// Include the variant even though there's no overlap in test names.
   609  			// This makes the test targets distinct, allowing our build system to record
   610  			// elapsed time for each one, which is useful for load-balancing test shards.
   611  			variant: "racebench",
   612  			timeout: 20 * time.Minute, // longer timeout for race with benchmarks
   613  			race:    true,
   614  			bench:   true,
   615  			cpu:     "4",
   616  			pkgs:    benchMatches,
   617  		}).run(t)
   618  	})
   619  }
   620  
   621  func (t *tester) registerTests() {
   622  	// registerStdTestSpecially tracks import paths in the standard library
   623  	// whose test registration happens in a special way.
   624  	//
   625  	// These tests *must* be able to run normally as part of "go test std cmd",
   626  	// even if they are also registered separately by dist, because users often
   627  	// run go test directly. Use skips or build tags in preference to expanding
   628  	// this list.
   629  	registerStdTestSpecially := map[string]bool{
   630  		// testdir can run normally as part of "go test std cmd", but because
   631  		// it's a very large test, we register is specially as several shards to
   632  		// enable better load balancing on sharded builders. Ideally the build
   633  		// system would know how to shard any large test package.
   634  		"cmd/internal/testdir": true,
   635  	}
   636  
   637  	// Fast path to avoid the ~1 second of `go list std cmd` when
   638  	// the caller lists specific tests to run. (as the continuous
   639  	// build coordinator does).
   640  	if len(t.runNames) > 0 {
   641  		for _, name := range t.runNames {
   642  			if !strings.Contains(name, ":") {
   643  				t.registerStdTest(name)
   644  			} else if strings.HasSuffix(name, ":racebench") {
   645  				t.registerRaceBenchTest(strings.TrimSuffix(name, ":racebench"))
   646  			}
   647  		}
   648  	} else {
   649  		// Use 'go list std cmd' to get a list of all Go packages
   650  		// that running 'go test std cmd' could find problems in.
   651  		// (In race test mode, also set -tags=race.)
   652  		// This includes vendored packages and other
   653  		// packages without tests so that 'dist test' finds if any of
   654  		// them don't build, have a problem reported by high-confidence
   655  		// vet checks that come with 'go test', and anything else it
   656  		// may check in the future. See go.dev/issue/60463.
   657  		// Most packages have tests, so there is not much saved
   658  		// by skipping non-test packages.
   659  		// For the packages without any test files,
   660  		// 'go test' knows not to actually build a test binary,
   661  		// so the only cost is the vet, and we still want to run vet.
   662  		cmd := exec.Command(gorootBinGo, "list")
   663  		if t.race {
   664  			cmd.Args = append(cmd.Args, "-tags=race")
   665  		}
   666  		cmd.Args = append(cmd.Args, "std", "cmd")
   667  		cmd.Stderr = new(bytes.Buffer)
   668  		all, err := cmd.Output()
   669  		if err != nil {
   670  			fatalf("Error running go list std cmd: %v:\n%s", err, cmd.Stderr)
   671  		}
   672  		pkgs := strings.Fields(string(all))
   673  		for _, pkg := range pkgs {
   674  			if registerStdTestSpecially[pkg] {
   675  				continue
   676  			}
   677  			if t.short && (strings.HasPrefix(pkg, "vendor/") || strings.HasPrefix(pkg, "cmd/vendor/")) {
   678  				// Vendored code has no tests, and we don't care too much about vet errors
   679  				// since we can't modify the code, so skip the tests in short mode.
   680  				// We still let the longtest builders vet them.
   681  				continue
   682  			}
   683  			t.registerStdTest(pkg)
   684  		}
   685  		if t.race && !t.short {
   686  			for _, pkg := range pkgs {
   687  				if t.packageHasBenchmarks(pkg) {
   688  					t.registerRaceBenchTest(pkg)
   689  				}
   690  			}
   691  		}
   692  	}
   693  
   694  	if t.race {
   695  		return
   696  	}
   697  
   698  	// Test the os/user package in the pure-Go mode too.
   699  	if !t.compileOnly {
   700  		t.registerTest("os/user with tag osusergo",
   701  			&goTest{
   702  				variant: "osusergo",
   703  				tags:    []string{"osusergo"},
   704  				pkg:     "os/user",
   705  			})
   706  	}
   707  
   708  	// Tests that the nethttpomithttp2* build tags don't rot too much,
   709  	// even if there's not a regular builder on them.
   710  	for _, tag := range []string{"nethttpomithttp2", "nethttpomithttp2server", "nethttpomithttp2client"} {
   711  		t.registerTest("net/http with tag "+tag, &goTest{
   712  			variant: tag,
   713  			tags:    []string{tag},
   714  			pkg:     "net/http",
   715  		})
   716  	}
   717  
   718  	// Check that all crypto packages compile with the purego build tag.
   719  	t.registerTest("crypto with tag purego (build and vet only)", &goTest{
   720  		variant:  "purego",
   721  		tags:     []string{"purego"},
   722  		pkg:      "crypto/...",
   723  		runTests: "^$", // only ensure they compile
   724  	})
   725  
   726  	// Check that all crypto packages compile (and test correctly, in longmode) with fips.
   727  	if t.fips140Supported() {
   728  		// Test standard crypto packages with fips140=on.
   729  		t.registerTest("GOFIPS140=latest go test crypto/...", &goTest{
   730  			variant: "gofips140",
   731  			env:     []string{"GOFIPS140=latest"},
   732  			pkg:     "crypto/...",
   733  		})
   734  
   735  		// Test that earlier FIPS snapshots build.
   736  		// In long mode, test that they work too.
   737  		for _, version := range fips140Versions() {
   738  			suffix := " # (build and vet only)"
   739  			run := "^$" // only ensure they compile
   740  			if !t.short {
   741  				suffix = ""
   742  				run = ""
   743  			}
   744  			t.registerTest("GOFIPS140="+version+" go test crypto/..."+suffix, &goTest{
   745  				variant:  "gofips140-" + version,
   746  				pkg:      "crypto/...",
   747  				runTests: run,
   748  				env:      []string{"GOFIPS140=" + version, "GOMODCACHE=" + filepath.Join(workdir, "fips-"+version)},
   749  			})
   750  		}
   751  	}
   752  
   753  	// Test GOEXPERIMENT=nojsonv2.
   754  	if !strings.Contains(goexperiment, "nojsonv2") {
   755  		t.registerTest("GOEXPERIMENT=nojsonv2 go test encoding/json/...", &goTest{
   756  			variant: "nojsonv2",
   757  			env:     []string{"GOEXPERIMENT=" + goexperiments("nojsonv2")},
   758  			pkg:     "encoding/json/...",
   759  		})
   760  	}
   761  
   762  	// Test GOEXPERIMENT=runtimesecret.
   763  	if !strings.Contains(goexperiment, "runtimesecret") {
   764  		t.registerTest("GOEXPERIMENT=runtimesecret go test runtime/secret/...", &goTest{
   765  			variant: "runtimesecret",
   766  			env:     []string{"GOEXPERIMENT=" + goexperiments("runtimesecret")},
   767  			pkg:     "runtime/secret/...",
   768  		})
   769  	}
   770  
   771  	// Test GOEXPERIMENT=simd.
   772  	if !strings.Contains(goexperiment, "simd") {
   773  		// simd package is portable.
   774  		t.registerTest("GOEXPERIMENT=simd go test simd", &goTest{
   775  			variant: "simd",
   776  			env:     []string{"GOEXPERIMENT=" + goexperiments("simd")},
   777  			pkg:     "simd",
   778  		})
   779  		// simd/archsimd supports amd64, arm64, and wasm.
   780  		archsimdSupported := goarch == "amd64" || goarch == "arm64" || goarch == "wasm"
   781  		if archsimdSupported {
   782  			t.registerTest("GOEXPERIMENT=simd go test simd/archsimd/...", &goTest{
   783  				variant: "simd",
   784  				env:     []string{"GOEXPERIMENT=" + goexperiments("simd")},
   785  				pkg:     "simd/archsimd/...",
   786  			})
   787  		}
   788  	}
   789  
   790  	// Test ios/amd64 for the iOS simulator.
   791  	if goos == "darwin" && goarch == "amd64" && t.cgoEnabled {
   792  		t.registerTest("GOOS=ios on darwin/amd64",
   793  			&goTest{
   794  				variant:  "amd64ios",
   795  				runTests: "SystemRoots",
   796  				env:      []string{"GOOS=ios", "CGO_ENABLED=1"},
   797  				pkg:      "crypto/x509",
   798  			})
   799  	}
   800  
   801  	// GC debug mode tests. We only run these in long-test mode
   802  	// (with GO_TEST_SHORT=0) because this is just testing a
   803  	// non-critical debug setting.
   804  	if !t.compileOnly && !t.short {
   805  		t.registerTest("GODEBUG=gcstoptheworld=2 archive/zip",
   806  			&goTest{
   807  				variant: "gcstoptheworld2",
   808  				short:   true,
   809  				env:     []string{"GODEBUG=gcstoptheworld=2"},
   810  				pkg:     "archive/zip",
   811  			})
   812  		t.registerTest("GODEBUG=gccheckmark=1 runtime",
   813  			&goTest{
   814  				variant: "gccheckmark",
   815  				short:   true,
   816  				env:     []string{"GODEBUG=gccheckmark=1"},
   817  				pkg:     "runtime",
   818  			})
   819  	}
   820  
   821  	// Spectre mitigation smoke test.
   822  	if goos == "linux" && goarch == "amd64" && !(gogcflags == "-spectre=all" && t.asmflags == "all=-spectre=all") {
   823  		// Pick a bunch of packages known to have some assembly.
   824  		pkgs := []string{"internal/runtime/...", "reflect", "crypto/..."}
   825  		if !t.short {
   826  			pkgs = append(pkgs, "runtime")
   827  		}
   828  		t.registerTest("spectre",
   829  			&goTest{
   830  				variant: "spectre",
   831  				short:   true,
   832  				env:     []string{"GOFLAGS=-gcflags=all=-spectre=all -asmflags=all=-spectre=all"},
   833  				pkgs:    pkgs,
   834  			})
   835  	}
   836  
   837  	// morestack tests. We only run these in long-test mode
   838  	// (with GO_TEST_SHORT=0) because the runtime test is
   839  	// already quite long and mayMoreStackMove makes it about
   840  	// twice as slow.
   841  	if !t.compileOnly && !t.short {
   842  		// hooks is the set of maymorestack hooks to test with.
   843  		hooks := []string{"mayMoreStackPreempt", "mayMoreStackMove"}
   844  		// hookPkgs is the set of package patterns to apply
   845  		// the maymorestack hook to.
   846  		hookPkgs := []string{"runtime/...", "reflect", "sync"}
   847  		// unhookPkgs is the set of package patterns to
   848  		// exclude from hookPkgs.
   849  		unhookPkgs := []string{"runtime/testdata/..."}
   850  		for _, hook := range hooks {
   851  			// Construct the build flags to use the
   852  			// maymorestack hook in the compiler and
   853  			// assembler. We pass this via the GOFLAGS
   854  			// environment variable so that it applies to
   855  			// both the test itself and to binaries built
   856  			// by the test.
   857  			goFlagsList := []string{}
   858  			for _, flag := range []string{"-gcflags", "-asmflags"} {
   859  				for _, hookPkg := range hookPkgs {
   860  					goFlagsList = append(goFlagsList, flag+"="+hookPkg+"=-d=maymorestack=runtime."+hook)
   861  				}
   862  				for _, unhookPkg := range unhookPkgs {
   863  					goFlagsList = append(goFlagsList, flag+"="+unhookPkg+"=")
   864  				}
   865  			}
   866  			goFlags := strings.Join(goFlagsList, " ")
   867  
   868  			t.registerTest("maymorestack="+hook,
   869  				&goTest{
   870  					variant: hook,
   871  					short:   true,
   872  					env:     []string{"GOFLAGS=" + goFlags},
   873  					pkgs:    []string{"runtime", "reflect", "sync"},
   874  				})
   875  		}
   876  	}
   877  
   878  	// Test that internal linking of standard packages does not
   879  	// require libgcc. This ensures that we can install a Go
   880  	// release on a system that does not have a C compiler
   881  	// installed and still build Go programs (that don't use cgo).
   882  	for _, pkg := range cgoPackages {
   883  		if !t.internalLink() {
   884  			break
   885  		}
   886  
   887  		// ARM libgcc may be Thumb, which internal linking does not support.
   888  		if goarch == "arm" {
   889  			break
   890  		}
   891  
   892  		// What matters is that the tests build and start up.
   893  		// Skip expensive tests, especially x509 TestSystemRoots.
   894  		run := "^Test[^CS]"
   895  		if pkg == "net" {
   896  			run = "TestTCPStress"
   897  		}
   898  		t.registerTest("Testing without libgcc.",
   899  			&goTest{
   900  				variant:  "nolibgcc",
   901  				ldflags:  "-linkmode=internal -libgcc=none",
   902  				runTests: run,
   903  				pkg:      pkg,
   904  			})
   905  	}
   906  
   907  	// Stub out following test on alpine until 54354 resolved.
   908  	builderName := os.Getenv("GO_BUILDER_NAME")
   909  	disablePIE := strings.HasSuffix(builderName, "-alpine")
   910  
   911  	// Test internal linking of PIE binaries where it is supported.
   912  	if t.internalLinkPIE() && !disablePIE {
   913  		t.registerTest("internal linking, -buildmode=pie",
   914  			&goTest{
   915  				variant:   "pie_internal",
   916  				buildmode: "pie",
   917  				ldflags:   "-linkmode=internal",
   918  				env:       []string{"CGO_ENABLED=0"},
   919  				pkg:       "reflect",
   920  			})
   921  		t.registerTest("internal linking, -buildmode=pie",
   922  			&goTest{
   923  				variant:   "pie_internal",
   924  				buildmode: "pie",
   925  				ldflags:   "-linkmode=internal",
   926  				env:       []string{"CGO_ENABLED=0"},
   927  				pkg:       "crypto/internal/fips140test",
   928  				runTests:  "TestFIPSCheck",
   929  			})
   930  		// Also test a cgo package.
   931  		if t.cgoEnabled && t.internalLink() && !disablePIE {
   932  			t.registerTest("internal linking, -buildmode=pie",
   933  				&goTest{
   934  					variant:   "pie_internal",
   935  					buildmode: "pie",
   936  					ldflags:   "-linkmode=internal",
   937  					pkg:       "os/user",
   938  				})
   939  		}
   940  	}
   941  
   942  	if t.extLink() && !t.compileOnly {
   943  		if goos != "android" { // Android does not support non-PIE linking
   944  			t.registerTest("external linking, -buildmode=exe",
   945  				&goTest{
   946  					variant:   "exe_external",
   947  					buildmode: "exe",
   948  					ldflags:   "-linkmode=external",
   949  					env:       []string{"CGO_ENABLED=1"},
   950  					pkg:       "crypto/internal/fips140test",
   951  					runTests:  "TestFIPSCheck",
   952  				})
   953  		}
   954  		if t.externalLinkPIE() && !disablePIE {
   955  			t.registerTest("external linking, -buildmode=pie",
   956  				&goTest{
   957  					variant:   "pie_external",
   958  					buildmode: "pie",
   959  					ldflags:   "-linkmode=external",
   960  					env:       []string{"CGO_ENABLED=1"},
   961  					pkg:       "crypto/internal/fips140test",
   962  					runTests:  "TestFIPSCheck",
   963  				})
   964  		}
   965  	}
   966  
   967  	// sync tests
   968  	if t.hasParallelism() {
   969  		t.registerTest("sync -cpu=10",
   970  			&goTest{
   971  				variant: "cpu10",
   972  				cpu:     "10",
   973  				pkg:     "sync",
   974  			})
   975  	}
   976  
   977  	const cgoHeading = "Testing cgo"
   978  	if t.cgoEnabled {
   979  		t.registerCgoTests(cgoHeading)
   980  	}
   981  
   982  	if goos == "wasip1" {
   983  		t.registerTest("wasip1 host tests",
   984  			&goTest{
   985  				variant:   "host",
   986  				pkg:       "internal/runtime/wasitest",
   987  				runOnHost: true,
   988  			})
   989  	}
   990  
   991  	// Only run the API check on fast development platforms.
   992  	// Every platform checks the API on every GOOS/GOARCH/CGO_ENABLED combination anyway,
   993  	// so we really only need to run this check once anywhere to get adequate coverage.
   994  	// To help developers avoid trybot-only failures, we try to run on typical developer machines
   995  	// which is darwin,linux,windows/amd64 and darwin/arm64.
   996  	//
   997  	// The same logic applies to the release notes that correspond to each api/next file.
   998  	//
   999  	// TODO: remove the exclusion of goexperiment simd right before dev.simd branch is merged to master.
  1000  	if goos == "darwin" || ((goos == "linux" || goos == "windows") && (goarch == "amd64" && !strings.Contains(goexperiment, "simd"))) {
  1001  		t.registerTest("API release note check", &goTest{variant: "check", pkg: "cmd/relnote", testFlags: []string{"-check"}})
  1002  		t.registerTest("API check", &goTest{variant: "check", pkg: "cmd/api", testFlags: []string{"-check"}})
  1003  	}
  1004  
  1005  	// Runtime CPU tests.
  1006  	if !t.compileOnly && t.hasParallelism() {
  1007  		for i := 1; i <= 4; i *= 2 {
  1008  			t.registerTest(fmt.Sprintf("GOMAXPROCS=2 runtime -cpu=%d -quick", i),
  1009  				&goTest{
  1010  					variant:   "cpu" + strconv.Itoa(i),
  1011  					cpu:       strconv.Itoa(i),
  1012  					gcflags:   gogcflags,
  1013  					short:     true,
  1014  					testFlags: []string{"-quick"},
  1015  					// We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
  1016  					// creation of first goroutines and first garbage collections in the parallel setting.
  1017  					env: []string{"GOMAXPROCS=2"},
  1018  					pkg: "runtime",
  1019  				})
  1020  		}
  1021  	}
  1022  
  1023  	if t.raceDetectorSupported() && !t.msan && !t.asan {
  1024  		// N.B. -race is incompatible with -msan and -asan.
  1025  		t.registerRaceTests()
  1026  	}
  1027  
  1028  	if goos != "android" && !t.iOS() {
  1029  		// Only start multiple test dir shards on builders,
  1030  		// where they get distributed to multiple machines.
  1031  		// See issues 20141 and 31834.
  1032  		nShards := 1
  1033  		if os.Getenv("GO_BUILDER_NAME") != "" {
  1034  			nShards = 10
  1035  		}
  1036  		if n, err := strconv.Atoi(os.Getenv("GO_TEST_SHARDS")); err == nil {
  1037  			nShards = n
  1038  		}
  1039  		for shard := 0; shard < nShards; shard++ {
  1040  			id := fmt.Sprintf("%d_%d", shard, nShards)
  1041  			t.registerTest("../test",
  1042  				&goTest{
  1043  					// Include the variant even though there's no overlap in test names.
  1044  					// This makes the test target more clearly distinct in our build
  1045  					// results and is important for load-balancing test shards.
  1046  					variant:   id,
  1047  					pkg:       "cmd/internal/testdir",
  1048  					testFlags: []string{fmt.Sprintf("-shard=%d", shard), fmt.Sprintf("-shards=%d", nShards)},
  1049  					runOnHost: true,
  1050  				},
  1051  			)
  1052  		}
  1053  	}
  1054  }
  1055  
  1056  // addTest adds an arbitrary test callback to the test list.
  1057  //
  1058  // name must uniquely identify the test and heading must be non-empty.
  1059  func (t *tester) addTest(name, heading string, fn func(*distTest) error) {
  1060  	if t.testNames[name] {
  1061  		panic("duplicate registered test name " + name)
  1062  	}
  1063  	if heading == "" {
  1064  		panic("empty heading")
  1065  	}
  1066  	// Two simple checks for cases that would conflict with the fast path in registerTests.
  1067  	if !strings.Contains(name, ":") && heading != "Testing packages." {
  1068  		panic("empty variant is reserved exclusively for registerStdTest")
  1069  	} else if strings.HasSuffix(name, ":racebench") && heading != "Running benchmarks briefly." {
  1070  		panic("racebench variant is reserved exclusively for registerRaceBenchTest")
  1071  	}
  1072  	if t.testNames == nil {
  1073  		t.testNames = make(map[string]bool)
  1074  	}
  1075  	t.testNames[name] = true
  1076  	t.tests = append(t.tests, distTest{
  1077  		name:    name,
  1078  		heading: heading,
  1079  		fn:      fn,
  1080  	})
  1081  }
  1082  
  1083  type registerTestOpt interface {
  1084  	isRegisterTestOpt()
  1085  }
  1086  
  1087  // rtSkipFunc is a registerTest option that runs a skip check function before
  1088  // running the test.
  1089  type rtSkipFunc struct {
  1090  	skip func(*distTest) (string, bool) // Return message, true to skip the test
  1091  }
  1092  
  1093  func (rtSkipFunc) isRegisterTestOpt() {}
  1094  
  1095  // registerTest registers a test that runs the given goTest.
  1096  //
  1097  // Each Go package in goTest will have a corresponding test
  1098  // "<pkg>:<variant>", which must uniquely identify the test.
  1099  //
  1100  // heading and test.variant must be non-empty.
  1101  func (t *tester) registerTest(heading string, test *goTest, opts ...registerTestOpt) {
  1102  	var skipFunc func(*distTest) (string, bool)
  1103  	for _, opt := range opts {
  1104  		switch opt := opt.(type) {
  1105  		case rtSkipFunc:
  1106  			skipFunc = opt.skip
  1107  		}
  1108  	}
  1109  	// Register each test package as a separate test.
  1110  	register1 := func(test *goTest) {
  1111  		if test.variant == "" {
  1112  			panic("empty variant")
  1113  		}
  1114  		name := testName(test.pkg, test.variant)
  1115  		t.addTest(name, heading, func(dt *distTest) error {
  1116  			if skipFunc != nil {
  1117  				msg, skip := skipFunc(dt)
  1118  				if skip {
  1119  					test.printSkip(t, msg)
  1120  					return nil
  1121  				}
  1122  			}
  1123  			w := &work{dt: dt}
  1124  			w.cmd, w.flush = test.bgCommand(t, &w.out, &w.out)
  1125  			t.worklist = append(t.worklist, w)
  1126  			return nil
  1127  		})
  1128  	}
  1129  	if test.pkg != "" && len(test.pkgs) == 0 {
  1130  		// Common case. Avoid copying.
  1131  		register1(test)
  1132  		return
  1133  	}
  1134  	// TODO(dmitshur,austin): It might be better to unify the execution of 'go test pkg'
  1135  	// invocations for the same variant to be done with a single 'go test pkg1 pkg2 pkg3'
  1136  	// command, just like it's already done in registerStdTest and registerRaceBenchTest.
  1137  	// Those methods accumulate matched packages in stdMatches and benchMatches slices,
  1138  	// and we can extend that mechanism to work for all other equal variant registrations.
  1139  	// Do the simple thing to start with.
  1140  	for _, pkg := range test.packages() {
  1141  		test1 := *test
  1142  		test1.pkg, test1.pkgs = pkg, nil
  1143  		register1(&test1)
  1144  	}
  1145  }
  1146  
  1147  // dirCmd constructs a Cmd intended to be run in the foreground.
  1148  // The command will be run in dir, and Stdout and Stderr will go to os.Stdout
  1149  // and os.Stderr.
  1150  func (t *tester) dirCmd(dir string, cmdline ...any) *exec.Cmd {
  1151  	bin, args := flattenCmdline(cmdline)
  1152  	cmd := exec.Command(bin, args...)
  1153  	if filepath.IsAbs(dir) {
  1154  		setDir(cmd, dir)
  1155  	} else {
  1156  		setDir(cmd, filepath.Join(goroot, dir))
  1157  	}
  1158  	cmd.Stdout = os.Stdout
  1159  	cmd.Stderr = os.Stderr
  1160  	if vflag > 1 {
  1161  		errprintf("%#q\n", cmd)
  1162  	}
  1163  	return cmd
  1164  }
  1165  
  1166  // flattenCmdline flattens a mixture of string and []string as single list
  1167  // and then interprets it as a command line: first element is binary, then args.
  1168  func flattenCmdline(cmdline []any) (bin string, args []string) {
  1169  	var list []string
  1170  	for _, x := range cmdline {
  1171  		switch x := x.(type) {
  1172  		case string:
  1173  			list = append(list, x)
  1174  		case []string:
  1175  			list = append(list, x...)
  1176  		default:
  1177  			panic("invalid dirCmd argument type: " + reflect.TypeOf(x).String())
  1178  		}
  1179  	}
  1180  
  1181  	bin = list[0]
  1182  	if !filepath.IsAbs(bin) {
  1183  		panic("command is not absolute: " + bin)
  1184  	}
  1185  	return bin, list[1:]
  1186  }
  1187  
  1188  func (t *tester) iOS() bool {
  1189  	return goos == "ios"
  1190  }
  1191  
  1192  func (t *tester) out(v string) {
  1193  	if t.json {
  1194  		return
  1195  	}
  1196  	if t.banner == "" {
  1197  		return
  1198  	}
  1199  	fmt.Println("\n" + t.banner + v)
  1200  }
  1201  
  1202  // extLink reports whether the current goos/goarch supports
  1203  // external linking.
  1204  func (t *tester) extLink() bool {
  1205  	if !cgoEnabled[goos+"/"+goarch] {
  1206  		return false
  1207  	}
  1208  	if goarch == "ppc64" && goos != "aix" && goos != "linux" {
  1209  		return false
  1210  	}
  1211  	return true
  1212  }
  1213  
  1214  func (t *tester) internalLink() bool {
  1215  	if gohostos == "dragonfly" {
  1216  		// linkmode=internal fails on dragonfly since errno is a TLS relocation.
  1217  		return false
  1218  	}
  1219  	if goos == "android" {
  1220  		return false
  1221  	}
  1222  	if goos == "ios" {
  1223  		return false
  1224  	}
  1225  	// Internally linking cgo is incomplete on some architectures.
  1226  	// https://golang.org/issue/10373
  1227  	// https://golang.org/issue/14449
  1228  	if goarch == "mips64" || goarch == "mips64le" || goarch == "mips" || goarch == "mipsle" || goarch == "riscv64" {
  1229  		return false
  1230  	}
  1231  	if goos == "aix" {
  1232  		// linkmode=internal isn't supported.
  1233  		return false
  1234  	}
  1235  	if t.msan || t.asan {
  1236  		// linkmode=internal isn't supported by msan or asan.
  1237  		return false
  1238  	}
  1239  	return true
  1240  }
  1241  
  1242  func (t *tester) internalLinkPIE() bool {
  1243  	if t.msan || t.asan {
  1244  		// linkmode=internal isn't supported by msan or asan.
  1245  		return false
  1246  	}
  1247  	switch goos + "-" + goarch {
  1248  	case "darwin-amd64", "darwin-arm64",
  1249  		"linux-amd64", "linux-arm64", "linux-loong64", "linux-ppc64", "linux-ppc64le", "linux-s390x",
  1250  		"android-arm64",
  1251  		"windows-amd64", "windows-386", "windows-arm64":
  1252  		return true
  1253  	}
  1254  	return false
  1255  }
  1256  
  1257  func (t *tester) externalLinkPIE() bool {
  1258  	// General rule is if -buildmode=pie and -linkmode=external both work, then they work together.
  1259  	return t.internalLinkPIE() && t.extLink()
  1260  }
  1261  
  1262  // supportedBuildmode reports whether the given build mode is supported.
  1263  func (t *tester) supportedBuildmode(mode string) bool {
  1264  	switch mode {
  1265  	case "c-archive", "c-shared", "shared", "plugin", "pie":
  1266  	default:
  1267  		fatalf("internal error: unknown buildmode %s", mode)
  1268  		return false
  1269  	}
  1270  
  1271  	return buildModeSupported("gc", mode, goos, goarch)
  1272  }
  1273  
  1274  func (t *tester) registerCgoTests(heading string) {
  1275  	cgoTest := func(variant string, subdir, linkmode, buildmode string, opts ...registerTestOpt) *goTest {
  1276  		gt := &goTest{
  1277  			variant:   variant,
  1278  			pkg:       "cmd/cgo/internal/" + subdir,
  1279  			buildmode: buildmode,
  1280  		}
  1281  		var ldflags []string
  1282  		if linkmode != "auto" {
  1283  			// "auto" is the default, so avoid cluttering the command line for "auto"
  1284  			ldflags = append(ldflags, "-linkmode="+linkmode)
  1285  		}
  1286  
  1287  		if linkmode == "internal" {
  1288  			gt.tags = append(gt.tags, "internal")
  1289  			if buildmode == "pie" {
  1290  				gt.tags = append(gt.tags, "internal_pie")
  1291  			}
  1292  		}
  1293  		if buildmode == "static" {
  1294  			// This isn't actually a Go buildmode, just a convenient way to tell
  1295  			// cgoTest we want static linking.
  1296  			gt.buildmode = ""
  1297  			switch linkmode {
  1298  			case "external":
  1299  				ldflags = append(ldflags, `-extldflags "-static -pthread"`)
  1300  			case "auto":
  1301  				gt.env = append(gt.env, "CGO_LDFLAGS=-static -pthread")
  1302  			default:
  1303  				panic("unknown linkmode with static build: " + linkmode)
  1304  			}
  1305  			gt.tags = append(gt.tags, "static")
  1306  		}
  1307  		gt.ldflags = strings.Join(ldflags, " ")
  1308  
  1309  		t.registerTest(heading, gt, opts...)
  1310  		return gt
  1311  	}
  1312  
  1313  	// test, testtls, and testnocgo are run with linkmode="auto", buildmode=""
  1314  	// as part of go test cmd. Here we only have to register the non-default
  1315  	// build modes of these tests.
  1316  
  1317  	// Stub out various buildmode=pie tests  on alpine until 54354 resolved.
  1318  	builderName := os.Getenv("GO_BUILDER_NAME")
  1319  	disablePIE := strings.HasSuffix(builderName, "-alpine")
  1320  
  1321  	if t.internalLink() {
  1322  		cgoTest("internal", "test", "internal", "")
  1323  	}
  1324  
  1325  	os := gohostos
  1326  	p := gohostos + "/" + goarch
  1327  	switch os {
  1328  	case "darwin", "windows":
  1329  		if !t.extLink() {
  1330  			break
  1331  		}
  1332  		// test linkmode=external, but __thread not supported, so skip testtls.
  1333  		cgoTest("external", "test", "external", "")
  1334  
  1335  		gt := cgoTest("external-s", "test", "external", "")
  1336  		gt.ldflags += " -s"
  1337  
  1338  		if t.supportedBuildmode("pie") && !disablePIE {
  1339  			cgoTest("auto-pie", "test", "auto", "pie")
  1340  			if t.internalLink() && t.internalLinkPIE() {
  1341  				cgoTest("internal-pie", "test", "internal", "pie")
  1342  			}
  1343  		}
  1344  
  1345  	case "aix", "android", "dragonfly", "freebsd", "linux", "netbsd", "openbsd":
  1346  		gt := cgoTest("external-g0", "test", "external", "")
  1347  		gt.env = append(gt.env, "CGO_CFLAGS=-g0 -fdiagnostics-color")
  1348  
  1349  		cgoTest("external", "testtls", "external", "")
  1350  		switch {
  1351  		case os == "aix":
  1352  			// no static linking
  1353  		case p == "freebsd/arm":
  1354  			// -fPIC compiled tls code will use __tls_get_addr instead
  1355  			// of __aeabi_read_tp, however, on FreeBSD/ARM, __tls_get_addr
  1356  			// is implemented in rtld-elf, so -fPIC isn't compatible with
  1357  			// static linking on FreeBSD/ARM with clang. (cgo depends on
  1358  			// -fPIC fundamentally.)
  1359  		default:
  1360  			// Check for static linking support
  1361  			var staticCheck rtSkipFunc
  1362  			ccName := compilerEnvLookup("CC", defaultcc, goos, goarch)
  1363  			cc, err := exec.LookPath(ccName)
  1364  			if err != nil {
  1365  				staticCheck.skip = func(*distTest) (string, bool) {
  1366  					return fmt.Sprintf("$CC (%q) not found, skip cgo static linking test.", ccName), true
  1367  				}
  1368  			} else {
  1369  				cmd := t.dirCmd("src/cmd/cgo/internal/test", cc, "-xc", "-o", "/dev/null", "-static", "-")
  1370  				cmd.Stdin = strings.NewReader("int main() {}")
  1371  				cmd.Stdout, cmd.Stderr = nil, nil // Discard output
  1372  				if err := cmd.Run(); err != nil {
  1373  					// Skip these tests
  1374  					staticCheck.skip = func(*distTest) (string, bool) {
  1375  						return "No support for static linking found (lacks libc.a?), skip cgo static linking test.", true
  1376  					}
  1377  				}
  1378  			}
  1379  
  1380  			// Doing a static link with boringcrypto gets
  1381  			// a C linker warning on Linux.
  1382  			// in function `bio_ip_and_port_to_socket_and_addr':
  1383  			// warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
  1384  			if staticCheck.skip == nil && goos == "linux" && strings.Contains(goexperiment, "boringcrypto") {
  1385  				staticCheck.skip = func(*distTest) (string, bool) {
  1386  					return "skipping static linking check on Linux when using boringcrypto to avoid C linker warning about getaddrinfo", true
  1387  				}
  1388  			}
  1389  
  1390  			// Static linking tests
  1391  			if goos != "android" && p != "netbsd/arm" && !t.msan && !t.asan {
  1392  				// TODO(#56629): Why does this fail on netbsd-arm?
  1393  				// TODO(#70080): Why does this fail with msan?
  1394  				// asan doesn't support static linking (this is an explicit build error on the C side).
  1395  				cgoTest("static", "testtls", "external", "static", staticCheck)
  1396  			}
  1397  			cgoTest("external", "testnocgo", "external", "", staticCheck)
  1398  			if goos != "android" && !t.msan && !t.asan {
  1399  				// TODO(#70080): Why does this fail with msan?
  1400  				// asan doesn't support static linking (this is an explicit build error on the C side).
  1401  				cgoTest("static", "testnocgo", "external", "static", staticCheck)
  1402  				cgoTest("static", "test", "external", "static", staticCheck)
  1403  				// -static in CGO_LDFLAGS triggers a different code path
  1404  				// than -static in -extldflags, so test both.
  1405  				// See issue #16651.
  1406  				if goarch != "loong64" && !t.msan && !t.asan {
  1407  					// TODO(#56623): Why does this fail on loong64?
  1408  					cgoTest("auto-static", "test", "auto", "static", staticCheck)
  1409  				}
  1410  			}
  1411  
  1412  			// PIE linking tests
  1413  			if t.supportedBuildmode("pie") && !disablePIE {
  1414  				cgoTest("auto-pie", "test", "auto", "pie")
  1415  				if t.internalLink() && t.internalLinkPIE() {
  1416  					cgoTest("internal-pie", "test", "internal", "pie")
  1417  				}
  1418  				cgoTest("auto-pie", "testtls", "auto", "pie")
  1419  				cgoTest("auto-pie", "testnocgo", "auto", "pie")
  1420  			}
  1421  		}
  1422  	}
  1423  }
  1424  
  1425  // runPending runs pending test commands, in parallel, emitting headers as appropriate.
  1426  // When finished, it emits header for nextTest, which is going to run after the
  1427  // pending commands are done (and runPending returns).
  1428  // A test should call runPending if it wants to make sure that it is not
  1429  // running in parallel with earlier tests, or if it has some other reason
  1430  // for needing the earlier tests to be done.
  1431  func (t *tester) runPending(nextTest *distTest) {
  1432  	worklist := t.worklist
  1433  	t.worklist = nil
  1434  	for _, w := range worklist {
  1435  		w.start = make(chan bool)
  1436  		w.end = make(chan struct{})
  1437  		// w.cmd must be set up to write to w.out. We can't check that, but we
  1438  		// can check for easy mistakes.
  1439  		if w.cmd.Stdout == nil || w.cmd.Stdout == os.Stdout || w.cmd.Stderr == nil || w.cmd.Stderr == os.Stderr {
  1440  			panic("work.cmd.Stdout/Stderr must be redirected")
  1441  		}
  1442  		go func(w *work) {
  1443  			if !<-w.start {
  1444  				timelog("skip", w.dt.name)
  1445  				w.printSkip(t, "skipped due to earlier error")
  1446  			} else {
  1447  				timelog("start", w.dt.name)
  1448  				w.err = w.cmd.Run()
  1449  				if w.flush != nil {
  1450  					w.flush()
  1451  				}
  1452  				if w.err != nil {
  1453  					if isUnsupportedVMASize(w) {
  1454  						timelog("skip", w.dt.name)
  1455  						w.out.Reset()
  1456  						w.printSkip(t, "skipped due to unsupported VMA")
  1457  						w.err = nil
  1458  					}
  1459  				}
  1460  			}
  1461  			timelog("end", w.dt.name)
  1462  			w.end <- struct{}{}
  1463  		}(w)
  1464  	}
  1465  
  1466  	maxbg := maxbg
  1467  	// for runtime.NumCPU() < 4 ||  runtime.GOMAXPROCS(0) == 1, do not change maxbg.
  1468  	// Because there is not enough CPU to parallel the testing of multiple packages.
  1469  	if runtime.NumCPU() > 4 && runtime.GOMAXPROCS(0) != 1 {
  1470  		for _, w := range worklist {
  1471  			// See go.dev/issue/65164
  1472  			// because GOMAXPROCS=2 runtime CPU usage is low,
  1473  			// so increase maxbg to avoid slowing down execution with low CPU usage.
  1474  			// This makes testing a single package slower,
  1475  			// but testing multiple packages together faster.
  1476  			if strings.Contains(w.dt.heading, "GOMAXPROCS=2 runtime") {
  1477  				maxbg = runtime.NumCPU()
  1478  				break
  1479  			}
  1480  		}
  1481  	}
  1482  
  1483  	started := 0
  1484  	ended := 0
  1485  	var last *distTest
  1486  	for ended < len(worklist) {
  1487  		for started < len(worklist) && started-ended < maxbg {
  1488  			w := worklist[started]
  1489  			started++
  1490  			w.start <- !t.failed || t.keepGoing
  1491  		}
  1492  		w := worklist[ended]
  1493  		dt := w.dt
  1494  		if t.lastHeading != dt.heading {
  1495  			t.lastHeading = dt.heading
  1496  			t.out(dt.heading)
  1497  		}
  1498  		if dt != last {
  1499  			// Assumes all the entries for a single dt are in one worklist.
  1500  			last = w.dt
  1501  			if vflag > 0 {
  1502  				fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
  1503  			}
  1504  		}
  1505  		if vflag > 1 {
  1506  			errprintf("%#q\n", w.cmd)
  1507  		}
  1508  		ended++
  1509  		<-w.end
  1510  		os.Stdout.Write(w.out.Bytes())
  1511  		// We no longer need the output, so drop the buffer.
  1512  		w.out = bytes.Buffer{}
  1513  		if w.err != nil {
  1514  			log.Printf("Failed: %v", w.err)
  1515  			t.failed = true
  1516  		}
  1517  	}
  1518  	if t.failed && !t.keepGoing {
  1519  		fatalf("FAILED")
  1520  	}
  1521  
  1522  	if dt := nextTest; dt != nil {
  1523  		if t.lastHeading != dt.heading {
  1524  			t.lastHeading = dt.heading
  1525  			t.out(dt.heading)
  1526  		}
  1527  		if vflag > 0 {
  1528  			fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
  1529  		}
  1530  	}
  1531  }
  1532  
  1533  // hasParallelism is a copy of the function
  1534  // internal/testenv.HasParallelism, which can't be used here
  1535  // because cmd/dist can not import internal packages during bootstrap.
  1536  func (t *tester) hasParallelism() bool {
  1537  	switch goos {
  1538  	case "js", "wasip1":
  1539  		return false
  1540  	}
  1541  	return true
  1542  }
  1543  
  1544  func (t *tester) raceDetectorSupported() bool {
  1545  	if gohostos != goos {
  1546  		return false
  1547  	}
  1548  	if !t.cgoEnabled {
  1549  		return false
  1550  	}
  1551  	if !raceDetectorSupported(goos, goarch) {
  1552  		return false
  1553  	}
  1554  	// The race detector doesn't work on Alpine Linux:
  1555  	// golang.org/issue/14481
  1556  	if isAlpineLinux() {
  1557  		return false
  1558  	}
  1559  	// NetBSD support is unfinished.
  1560  	// golang.org/issue/26403
  1561  	if goos == "netbsd" {
  1562  		return false
  1563  	}
  1564  	return true
  1565  }
  1566  
  1567  func isAlpineLinux() bool {
  1568  	if runtime.GOOS != "linux" {
  1569  		return false
  1570  	}
  1571  	fi, err := os.Lstat("/etc/alpine-release")
  1572  	return err == nil && fi.Mode().IsRegular()
  1573  }
  1574  
  1575  func (t *tester) registerRaceTests() {
  1576  	hdr := "Testing race detector"
  1577  	t.registerTest(hdr,
  1578  		&goTest{
  1579  			variant:  "race",
  1580  			race:     true,
  1581  			runTests: "Output",
  1582  			pkg:      "runtime/race",
  1583  		})
  1584  	t.registerTest(hdr,
  1585  		&goTest{
  1586  			variant:  "race",
  1587  			race:     true,
  1588  			runTests: "TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace|TestTypeRace|TestFdRace|TestFdReadRace|TestFileCloseRace",
  1589  			pkgs:     []string{"flag", "net", "os", "os/exec", "encoding/gob"},
  1590  		})
  1591  	// We don't want the following line, because it
  1592  	// slows down all.bash (by 10 seconds on my laptop).
  1593  	// The race builder should catch any error here, but doesn't.
  1594  	// TODO(iant): Figure out how to catch this.
  1595  	// t.registerTest(hdr, &goTest{variant: "race", race: true, runTests: "TestParallelTest", pkg: "cmd/go"})
  1596  	if t.cgoEnabled {
  1597  		// Building cmd/cgo/internal/test takes a long time.
  1598  		// There are already cgo-enabled packages being tested with the race detector.
  1599  		// We shouldn't need to redo all of cmd/cgo/internal/test too.
  1600  		// The race builder will take care of this.
  1601  		// t.registerTest(hdr, &goTest{variant: "race", race: true, env: []string{"GOTRACEBACK=2"}, pkg: "cmd/cgo/internal/test"})
  1602  	}
  1603  	if t.extLink() {
  1604  		// Test with external linking; see issue 9133.
  1605  		t.registerTest(hdr,
  1606  			&goTest{
  1607  				variant:  "race-external",
  1608  				race:     true,
  1609  				ldflags:  "-linkmode=external",
  1610  				runTests: "TestParse|TestEcho|TestStdinCloseRace",
  1611  				pkgs:     []string{"flag", "os/exec"},
  1612  			})
  1613  	}
  1614  }
  1615  
  1616  // cgoPackages is the standard packages that use cgo.
  1617  var cgoPackages = []string{
  1618  	"net",
  1619  	"os/user",
  1620  }
  1621  
  1622  var funcBenchmark = []byte("\nfunc Benchmark")
  1623  
  1624  // packageHasBenchmarks reports whether pkg has benchmarks.
  1625  // On any error, it conservatively returns true.
  1626  //
  1627  // This exists just to eliminate work on the builders, since compiling
  1628  // a test in race mode just to discover it has no benchmarks costs a
  1629  // second or two per package, and this function returns false for
  1630  // about 100 packages.
  1631  func (t *tester) packageHasBenchmarks(pkg string) bool {
  1632  	pkgDir := filepath.Join(goroot, "src", pkg)
  1633  	d, err := os.Open(pkgDir)
  1634  	if err != nil {
  1635  		return true // conservatively
  1636  	}
  1637  	defer d.Close()
  1638  	names, err := d.Readdirnames(-1)
  1639  	if err != nil {
  1640  		return true // conservatively
  1641  	}
  1642  	for _, name := range names {
  1643  		if !strings.HasSuffix(name, "_test.go") {
  1644  			continue
  1645  		}
  1646  		slurp, err := os.ReadFile(filepath.Join(pkgDir, name))
  1647  		if err != nil {
  1648  			return true // conservatively
  1649  		}
  1650  		if bytes.Contains(slurp, funcBenchmark) {
  1651  			return true
  1652  		}
  1653  	}
  1654  	return false
  1655  }
  1656  
  1657  // makeGOROOTUnwritable makes all $GOROOT files & directories non-writable to
  1658  // check that no tests accidentally write to $GOROOT.
  1659  func (t *tester) makeGOROOTUnwritable() (undo func()) {
  1660  	dir := os.Getenv("GOROOT")
  1661  	if dir == "" {
  1662  		panic("GOROOT not set")
  1663  	}
  1664  
  1665  	type pathMode struct {
  1666  		path string
  1667  		mode os.FileMode
  1668  	}
  1669  	var dirs []pathMode // in lexical order
  1670  
  1671  	undo = func() {
  1672  		for i := range dirs {
  1673  			os.Chmod(dirs[i].path, dirs[i].mode) // best effort
  1674  		}
  1675  	}
  1676  
  1677  	filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
  1678  		if suffix := strings.TrimPrefix(path, dir+string(filepath.Separator)); suffix != "" {
  1679  			if suffix == ".git" {
  1680  				// Leave Git metadata in whatever state it was in. It may contain a lot
  1681  				// of files, and it is highly unlikely that a test will try to modify
  1682  				// anything within that directory.
  1683  				return filepath.SkipDir
  1684  			}
  1685  		}
  1686  		if err != nil {
  1687  			return nil
  1688  		}
  1689  
  1690  		info, err := d.Info()
  1691  		if err != nil {
  1692  			return nil
  1693  		}
  1694  
  1695  		mode := info.Mode()
  1696  		if mode&0222 != 0 && (mode.IsDir() || mode.IsRegular()) {
  1697  			dirs = append(dirs, pathMode{path, mode})
  1698  		}
  1699  		return nil
  1700  	})
  1701  
  1702  	// Run over list backward to chmod children before parents.
  1703  	for i := len(dirs) - 1; i >= 0; i-- {
  1704  		err := os.Chmod(dirs[i].path, dirs[i].mode&^0222)
  1705  		if err != nil {
  1706  			dirs = dirs[i:] // Only undo what we did so far.
  1707  			undo()
  1708  			fatalf("failed to make GOROOT read-only: %v", err)
  1709  		}
  1710  	}
  1711  
  1712  	return undo
  1713  }
  1714  
  1715  // raceDetectorSupported is a copy of the function
  1716  // internal/platform.RaceDetectorSupported, which can't be used here
  1717  // because cmd/dist can not import internal packages during bootstrap.
  1718  // The race detector only supports 48-bit VMA on arm64. But we don't have
  1719  // a good solution to check VMA size (see https://go.dev/issue/29948).
  1720  // raceDetectorSupported will always return true for arm64. But race
  1721  // detector tests may abort on non 48-bit VMA configuration, the tests
  1722  // will be marked as "skipped" in this case.
  1723  func raceDetectorSupported(goos, goarch string) bool {
  1724  	switch goos {
  1725  	case "linux":
  1726  		return goarch == "amd64" || goarch == "arm64" || goarch == "loong64" || goarch == "ppc64le" || goarch == "riscv64" || goarch == "s390x"
  1727  	case "darwin":
  1728  		return goarch == "amd64" || goarch == "arm64"
  1729  	case "freebsd", "netbsd", "windows":
  1730  		return goarch == "amd64"
  1731  	default:
  1732  		return false
  1733  	}
  1734  }
  1735  
  1736  // fips140Supported is a copy of the function
  1737  // internal/platform.FIPS140Supported, which can't be used here
  1738  // because cmd/dist can not import internal packages during bootstrap.
  1739  func fips140Supported(goos, goarch string) bool {
  1740  	switch {
  1741  	case goarch == "wasm",
  1742  		goos == "windows" && goarch == "386",
  1743  		goos == "openbsd",
  1744  		goos == "aix":
  1745  		return false
  1746  	}
  1747  	return true
  1748  }
  1749  
  1750  // buildModeSupported is a copy of the function
  1751  // internal/platform.BuildModeSupported, which can't be used here
  1752  // because cmd/dist can not import internal packages during bootstrap.
  1753  func buildModeSupported(compiler, buildmode, goos, goarch string) bool {
  1754  	if compiler == "gccgo" {
  1755  		return true
  1756  	}
  1757  
  1758  	platform := goos + "/" + goarch
  1759  
  1760  	switch buildmode {
  1761  	case "archive":
  1762  		return true
  1763  
  1764  	case "c-archive":
  1765  		switch goos {
  1766  		case "aix", "darwin", "ios", "windows":
  1767  			return true
  1768  		case "linux":
  1769  			switch goarch {
  1770  			case "386", "amd64", "arm", "armbe", "arm64", "arm64be", "loong64", "ppc64", "ppc64le", "riscv64", "s390x":
  1771  				return true
  1772  			default:
  1773  				// Other targets do not support -shared,
  1774  				// per ParseFlags in
  1775  				// cmd/compile/internal/base/flag.go.
  1776  				// For c-archive the Go tool passes -shared,
  1777  				// so that the result is suitable for inclusion
  1778  				// in a PIE or shared library.
  1779  				return false
  1780  			}
  1781  		case "freebsd":
  1782  			return goarch == "amd64"
  1783  		}
  1784  		return false
  1785  
  1786  	case "c-shared":
  1787  		switch platform {
  1788  		case "linux/amd64", "linux/arm", "linux/arm64", "linux/loong64", "linux/386", "linux/ppc64", "linux/ppc64le", "linux/riscv64", "linux/s390x",
  1789  			"android/amd64", "android/arm", "android/arm64", "android/386",
  1790  			"freebsd/amd64",
  1791  			"darwin/amd64", "darwin/arm64",
  1792  			"windows/amd64", "windows/386", "windows/arm64",
  1793  			"wasip1/wasm":
  1794  			return true
  1795  		}
  1796  		return false
  1797  
  1798  	case "default":
  1799  		return true
  1800  
  1801  	case "exe":
  1802  		return true
  1803  
  1804  	case "pie":
  1805  		switch platform {
  1806  		case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/loong64", "linux/ppc64", "linux/ppc64le", "linux/riscv64", "linux/s390x",
  1807  			"android/amd64", "android/arm", "android/arm64", "android/386",
  1808  			"freebsd/amd64",
  1809  			"darwin/amd64", "darwin/arm64",
  1810  			"ios/amd64", "ios/arm64",
  1811  			"aix/ppc64",
  1812  			"openbsd/amd64", "openbsd/arm64",
  1813  			"windows/386", "windows/amd64", "windows/arm64":
  1814  			return true
  1815  		}
  1816  		return false
  1817  
  1818  	case "shared":
  1819  		switch platform {
  1820  		case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64", "linux/ppc64le", "linux/s390x":
  1821  			return true
  1822  		}
  1823  		return false
  1824  
  1825  	case "plugin":
  1826  		switch platform {
  1827  		case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/loong64", "linux/riscv64", "linux/s390x", "linux/ppc64", "linux/ppc64le",
  1828  			"android/amd64", "android/386",
  1829  			"darwin/amd64", "darwin/arm64",
  1830  			"freebsd/amd64":
  1831  			return true
  1832  		}
  1833  		return false
  1834  
  1835  	default:
  1836  		return false
  1837  	}
  1838  }
  1839  
  1840  // isUnsupportedVMASize reports whether the failure is caused by an unsupported
  1841  // VMA for the race detector (for example, running the race detector on an
  1842  // arm64 machine configured with 39-bit VMA).
  1843  func isUnsupportedVMASize(w *work) bool {
  1844  	unsupportedVMA := []byte("unsupported VMA range")
  1845  	return strings.Contains(w.dt.name, ":race") && bytes.Contains(w.out.Bytes(), unsupportedVMA)
  1846  }
  1847  
  1848  // isEnvSet reports whether the environment variable evar is
  1849  // set in the environment.
  1850  func isEnvSet(evar string) bool {
  1851  	evarEq := evar + "="
  1852  	for _, e := range os.Environ() {
  1853  		if strings.HasPrefix(e, evarEq) {
  1854  			return true
  1855  		}
  1856  	}
  1857  	return false
  1858  }
  1859  
  1860  func (t *tester) fips140Supported() bool {
  1861  	if !fips140Supported(goos, goarch) {
  1862  		return false
  1863  	}
  1864  
  1865  	// Keep the platform checks below in sync with crypto/internal/fips140.Supported.
  1866  	// We don't test with the purego tag, so no need to check it.
  1867  
  1868  	// Use GOFIPS140 or GOEXPERIMENT=boringcrypto, but not both.
  1869  	if strings.Contains(goexperiment, "boringcrypto") {
  1870  		return false
  1871  	}
  1872  
  1873  	// For now, FIPS+ASAN doesn't need to work.
  1874  	// If this is made to work, also re-enable the test in check_test.go.
  1875  	if t.asan {
  1876  		return false
  1877  	}
  1878  
  1879  	return true
  1880  }
  1881  
  1882  // fips140Versions returns the list of versions available in lib/fips140.
  1883  func fips140Versions() []string {
  1884  	var versions []string
  1885  	zips, err := filepath.Glob(filepath.Join(goroot, "lib/fips140/*.zip"))
  1886  	if err != nil {
  1887  		fatalf("%v", err)
  1888  	}
  1889  	for _, zip := range zips {
  1890  		versions = append(versions, strings.TrimSuffix(filepath.Base(zip), ".zip"))
  1891  	}
  1892  	txts, err := filepath.Glob(filepath.Join(goroot, "lib/fips140/*.txt"))
  1893  	if err != nil {
  1894  		fatalf("%v", err)
  1895  	}
  1896  	for _, txt := range txts {
  1897  		versions = append(versions, strings.TrimSuffix(filepath.Base(txt), ".txt"))
  1898  	}
  1899  	return versions
  1900  }
  1901  
  1902  // goexperiments returns the GOEXPERIMENT value to use
  1903  // when running a test with the given experiments enabled.
  1904  //
  1905  // It preserves any existing GOEXPERIMENTs.
  1906  func goexperiments(exps ...string) string {
  1907  	if len(exps) == 0 {
  1908  		return goexperiment
  1909  	}
  1910  	existing := goexperiment
  1911  	if existing != "" {
  1912  		existing += ","
  1913  	}
  1914  	return existing + strings.Join(exps, ",")
  1915  
  1916  }
  1917  

View as plain text