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