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