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