github.com/activestate/go@v0.0.0-20170614201249-0b81c023a722/src/cmd/dist/test.go (about)

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