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