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