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