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