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