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 5package main 6 7import ( 8 "bytes" 9 "flag" 10 "fmt" 11 "io/ioutil" 12 "log" 13 "os" 14 "os/exec" 15 "path" 16 "path/filepath" 17 "reflect" 18 "regexp" 19 "runtime" 20 "strconv" 21 "strings" 22 "sync" 23 "time" 24) 25 26func cmdtest() { 27 gogcflags = os.Getenv("GO_GCFLAGS") 28 29 var t tester 30 var noRebuild bool 31 flag.BoolVar(&t.listMode, "list", false, "list available tests") 32 flag.BoolVar(&t.rebuild, "rebuild", false, "rebuild everything first") 33 flag.BoolVar(&noRebuild, "no-rebuild", false, "overrides -rebuild (historical dreg)") 34 flag.BoolVar(&t.keepGoing, "k", false, "keep going even when error occurred") 35 flag.BoolVar(&t.race, "race", false, "run in race builder mode (different set of tests)") 36 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.") 37 flag.StringVar(&t.banner, "banner", "##### ", "banner prefix; blank means no section banners") 38 flag.StringVar(&t.runRxStr, "run", os.Getenv("GOTESTONLY"), 39 "run only those tests matching the regular expression; empty means to run all. "+ 40 "Special exception: if the string begins with '!', the match is inverted.") 41 xflagparse(-1) // any number of args 42 if noRebuild { 43 t.rebuild = false 44 } 45 46 t.run() 47} 48 49// tester executes cmdtest. 50type tester struct { 51 race bool 52 listMode bool 53 rebuild bool 54 failed bool 55 keepGoing bool 56 compileOnly bool // just try to compile all tests, but no need to run 57 runRxStr string 58 runRx *regexp.Regexp 59 runRxWant bool // want runRx to match (true) or not match (false) 60 runNames []string // tests to run, exclusive with runRx; empty means all 61 banner string // prefix, or "" for none 62 lastHeading string // last dir heading printed 63 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 74type 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) 85type 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 91func (t *tester) run() { 92 timelog("start", "dist test") 93 94 var exeSuffix string 95 if goos == "windows" { 96 exeSuffix = ".exe" 97 } 98 if _, err := os.Stat(filepath.Join(gobin, "go"+exeSuffix)); err == nil { 99 os.Setenv("PATH", fmt.Sprintf("%s%c%s", gobin, os.PathListSeparator, os.Getenv("PATH"))) 100 } 101 102 cmd := exec.Command("go", "env", "CGO_ENABLED") 103 cmd.Stderr = new(bytes.Buffer) 104 slurp, err := cmd.Output() 105 if err != nil { 106 fatalf("Error running go env CGO_ENABLED: %v\n%s", err, cmd.Stderr) 107 } 108 t.cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(slurp))) 109 if flag.NArg() > 0 && t.runRxStr != "" { 110 fatalf("the -run regular expression flag is mutually exclusive with test name arguments") 111 } 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 // Set GOTRACEBACK to system if the user didn't set a level explicitly. 122 // Since we're running tests for Go, we want as much detail as possible 123 // if something goes wrong. 124 // 125 // Set it before running any commands just in case something goes wrong. 126 if ok := isEnvSet("GOTRACEBACK"); !ok { 127 if err := os.Setenv("GOTRACEBACK", "system"); err != nil { 128 if t.keepGoing { 129 log.Printf("Failed to set GOTRACEBACK: %v", err) 130 } else { 131 fatalf("Failed to set GOTRACEBACK: %v", err) 132 } 133 } 134 } 135 136 if t.rebuild { 137 t.out("Building packages and commands.") 138 // Force rebuild the whole toolchain. 139 goInstall("go", append([]string{"-a", "-i"}, toolchain...)...) 140 } 141 142 if !t.listMode { 143 if os.Getenv("GO_BUILDER_NAME") == "" { 144 // Complete rebuild bootstrap, even with -no-rebuild. 145 // If everything is up-to-date, this is a no-op. 146 // If everything is not up-to-date, the first checkNotStale 147 // during the test process will kill the tests, so we might 148 // as well install the world. 149 // Now that for example "go install cmd/compile" does not 150 // also install runtime (you need "go install -i cmd/compile" 151 // for that), it's easy for previous workflows like 152 // "rebuild the compiler and then run run.bash" 153 // to break if we don't automatically refresh things here. 154 // Rebuilding is a shortened bootstrap. 155 // See cmdbootstrap for a description of the overall process. 156 goInstall("go", append([]string{"-i"}, toolchain...)...) 157 goInstall("go", append([]string{"-i"}, toolchain...)...) 158 goInstall("go", "std", "cmd") 159 } else { 160 // The Go builder infrastructure should always begin running tests from a 161 // clean, non-stale state, so there is no need to rebuild the world. 162 // Instead, we can just check that it is not stale, which may be less 163 // expensive (and is also more likely to catch bugs in the builder 164 // implementation). 165 willTest := []string{"std"} 166 if t.shouldTestCmd() { 167 willTest = append(willTest, "cmd") 168 } 169 checkNotStale("go", willTest...) 170 } 171 } 172 173 t.timeoutScale = 1 174 switch goarch { 175 case "arm": 176 t.timeoutScale = 2 177 case "mips", "mipsle", "mips64", "mips64le": 178 t.timeoutScale = 4 179 } 180 if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" { 181 t.timeoutScale, err = strconv.Atoi(s) 182 if err != nil { 183 fatalf("failed to parse $GO_TEST_TIMEOUT_SCALE = %q as integer: %v", s, err) 184 } 185 } 186 187 if t.runRxStr != "" { 188 if t.runRxStr[0] == '!' { 189 t.runRxWant = false 190 t.runRxStr = t.runRxStr[1:] 191 } else { 192 t.runRxWant = true 193 } 194 t.runRx = regexp.MustCompile(t.runRxStr) 195 } 196 197 t.registerTests() 198 if t.listMode { 199 for _, tt := range t.tests { 200 fmt.Println(tt.name) 201 } 202 return 203 } 204 205 for _, name := range t.runNames { 206 if !t.isRegisteredTestName(name) { 207 fatalf("unknown test %q", name) 208 } 209 } 210 211 // On a few builders, make GOROOT unwritable to catch tests writing to it. 212 if strings.HasPrefix(os.Getenv("GO_BUILDER_NAME"), "linux-") { 213 if os.Getuid() == 0 { 214 // Don't bother making GOROOT unwritable: 215 // we're running as root, so permissions would have no effect. 216 } else { 217 xatexit(t.makeGOROOTUnwritable()) 218 } 219 } 220 221 for _, dt := range t.tests { 222 if !t.shouldRunTest(dt.name) { 223 t.partial = true 224 continue 225 } 226 dt := dt // dt used in background after this iteration 227 if err := dt.fn(&dt); err != nil { 228 t.runPending(&dt) // in case that hasn't been done yet 229 t.failed = true 230 if t.keepGoing { 231 log.Printf("Failed: %v", err) 232 } else { 233 fatalf("Failed: %v", err) 234 } 235 } 236 } 237 t.runPending(nil) 238 timelog("end", "dist test") 239 240 if t.failed { 241 fmt.Println("\nFAILED") 242 xexit(1) 243 } else if incomplete[goos+"/"+goarch] { 244 // The test succeeded, but consider it as failed so we don't 245 // forget to remove the port from the incomplete map once the 246 // port is complete. 247 fmt.Println("\nFAILED (incomplete port)") 248 xexit(1) 249 } else if t.partial { 250 fmt.Println("\nALL TESTS PASSED (some were excluded)") 251 } else { 252 fmt.Println("\nALL TESTS PASSED") 253 } 254} 255 256func (t *tester) shouldRunTest(name string) bool { 257 if t.runRx != nil { 258 return t.runRx.MatchString(name) == t.runRxWant 259 } 260 if len(t.runNames) == 0 { 261 return true 262 } 263 for _, runName := range t.runNames { 264 if runName == name { 265 return true 266 } 267 } 268 return false 269} 270 271// short returns a -short flag value to use with 'go test' 272// or a test binary for tests intended to run in short mode. 273// It returns "true", unless the environment variable 274// GO_TEST_SHORT is set to a non-empty, false-ish string. 275// 276// This environment variable is meant to be an internal 277// detail between the Go build system and cmd/dist for 278// the purpose of longtest builders, and is not intended 279// for use by users. See golang.org/issue/12508. 280func short() string { 281 if v := os.Getenv("GO_TEST_SHORT"); v != "" { 282 short, err := strconv.ParseBool(v) 283 if err != nil { 284 fatalf("invalid GO_TEST_SHORT %q: %v", v, err) 285 } 286 if !short { 287 return "false" 288 } 289 } 290 return "true" 291} 292 293// goTest returns the beginning of the go test command line. 294// Callers should use goTest and then pass flags overriding these 295// defaults as later arguments in the command line. 296func (t *tester) goTest() []string { 297 return []string{ 298 "go", "test", "-short=" + short(), "-count=1", t.tags(), t.runFlag(""), 299 } 300} 301 302func (t *tester) tags() string { 303 if t.iOS() { 304 return "-tags=lldb" 305 } 306 return "-tags=" 307} 308 309// timeoutDuration converts the provided number of seconds into a 310// time.Duration, scaled by the t.timeoutScale factor. 311func (t *tester) timeoutDuration(sec int) time.Duration { 312 return time.Duration(sec) * time.Second * time.Duration(t.timeoutScale) 313} 314 315// timeout returns the "-timeout=" string argument to "go test" given 316// the number of seconds of timeout. It scales it by the 317// t.timeoutScale factor. 318func (t *tester) timeout(sec int) string { 319 return "-timeout=" + t.timeoutDuration(sec).String() 320} 321 322// ranGoTest and stdMatches are state closed over by the stdlib 323// testing func in registerStdTest below. The tests are run 324// sequentially, so there's no need for locks. 325// 326// ranGoBench and benchMatches are the same, but are only used 327// in -race mode. 328var ( 329 ranGoTest bool 330 stdMatches []string 331 332 ranGoBench bool 333 benchMatches []string 334) 335 336func (t *tester) registerStdTest(pkg string, useG3 bool) { 337 heading := "Testing packages." 338 testPrefix := "go_test:" 339 gcflags := gogcflags 340 if useG3 { 341 heading = "Testing packages with -G=3." 342 testPrefix = "go_test_g3:" 343 gcflags += " -G=3" 344 } 345 346 testName := testPrefix + pkg 347 if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant { 348 stdMatches = append(stdMatches, pkg) 349 } 350 351 t.tests = append(t.tests, distTest{ 352 name: testName, 353 heading: heading, 354 fn: func(dt *distTest) error { 355 if ranGoTest { 356 return nil 357 } 358 t.runPending(dt) 359 timelog("start", dt.name) 360 defer timelog("end", dt.name) 361 ranGoTest = true 362 363 timeoutSec := 180 364 for _, pkg := range stdMatches { 365 if pkg == "cmd/go" { 366 timeoutSec *= 3 367 break 368 } 369 } 370 // Special case for our slow cross-compiled 371 // qemu builders: 372 if t.shouldUsePrecompiledStdTest() { 373 return t.runPrecompiledStdTest(t.timeoutDuration(timeoutSec)) 374 } 375 args := []string{ 376 "test", 377 "-short=" + short(), 378 t.tags(), 379 t.timeout(timeoutSec), 380 "-gcflags=all=" + gcflags, 381 } 382 if t.race { 383 args = append(args, "-race") 384 } 385 if t.compileOnly { 386 args = append(args, "-run=^$") 387 } 388 args = append(args, stdMatches...) 389 cmd := exec.Command("go", args...) 390 cmd.Stdout = os.Stdout 391 cmd.Stderr = os.Stderr 392 return cmd.Run() 393 }, 394 }) 395} 396 397func (t *tester) registerRaceBenchTest(pkg string) { 398 testName := "go_test_bench:" + pkg 399 if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant { 400 benchMatches = append(benchMatches, pkg) 401 } 402 t.tests = append(t.tests, distTest{ 403 name: testName, 404 heading: "Running benchmarks briefly.", 405 fn: func(dt *distTest) error { 406 if ranGoBench { 407 return nil 408 } 409 t.runPending(dt) 410 timelog("start", dt.name) 411 defer timelog("end", dt.name) 412 ranGoBench = true 413 args := []string{ 414 "test", 415 "-short=" + short(), 416 "-race", 417 t.timeout(1200), // longer timeout for race with benchmarks 418 "-run=^$", // nothing. only benchmarks. 419 "-benchtime=.1s", 420 "-cpu=4", 421 } 422 if !t.compileOnly { 423 args = append(args, "-bench=.*") 424 } 425 args = append(args, benchMatches...) 426 cmd := exec.Command("go", args...) 427 cmd.Stdout = os.Stdout 428 cmd.Stderr = os.Stderr 429 return cmd.Run() 430 }, 431 }) 432} 433 434// stdOutErrAreTerminals is defined in test_linux.go, to report 435// whether stdout & stderr are terminals. 436var stdOutErrAreTerminals func() bool 437 438func (t *tester) registerTests() { 439 // Fast path to avoid the ~1 second of `go list std cmd` when 440 // the caller lists specific tests to run. (as the continuous 441 // build coordinator does). 442 if len(t.runNames) > 0 { 443 for _, name := range t.runNames { 444 if strings.HasPrefix(name, "go_test:") { 445 t.registerStdTest(strings.TrimPrefix(name, "go_test:"), false) 446 } 447 if strings.HasPrefix(name, "go_test_g3:") { 448 t.registerStdTest(strings.TrimPrefix(name, "go_test_g3:"), true) 449 } 450 if strings.HasPrefix(name, "go_test_bench:") { 451 t.registerRaceBenchTest(strings.TrimPrefix(name, "go_test_bench:")) 452 } 453 } 454 } else { 455 // Use a format string to only list packages and commands that have tests. 456 const format = "{{if (or .TestGoFiles .XTestGoFiles)}}{{.ImportPath}}{{end}}" 457 cmd := exec.Command("go", "list", "-f", format) 458 if t.race { 459 cmd.Args = append(cmd.Args, "-tags=race") 460 } 461 cmd.Args = append(cmd.Args, "std") 462 if t.shouldTestCmd() { 463 cmd.Args = append(cmd.Args, "cmd") 464 } 465 cmd.Stderr = new(bytes.Buffer) 466 all, err := cmd.Output() 467 if err != nil { 468 fatalf("Error running go list std cmd: %v:\n%s", err, cmd.Stderr) 469 } 470 pkgs := strings.Fields(string(all)) 471 if false { 472 // Disable -G=3 option for standard tests for now, since 473 // they are flaky on the builder. 474 for _, pkg := range pkgs { 475 t.registerStdTest(pkg, true /* -G=3 flag */) 476 } 477 } 478 for _, pkg := range pkgs { 479 t.registerStdTest(pkg, false) 480 } 481 if t.race { 482 for _, pkg := range pkgs { 483 if t.packageHasBenchmarks(pkg) { 484 t.registerRaceBenchTest(pkg) 485 } 486 } 487 } 488 } 489 490 // Test the os/user package in the pure-Go mode too. 491 if !t.compileOnly { 492 t.tests = append(t.tests, distTest{ 493 name: "osusergo", 494 heading: "os/user with tag osusergo", 495 fn: func(dt *distTest) error { 496 t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-tags=osusergo", "os/user") 497 return nil 498 }, 499 }) 500 } 501 502 // Test ios/amd64 for the iOS simulator. 503 if goos == "darwin" && goarch == "amd64" && t.cgoEnabled { 504 t.tests = append(t.tests, distTest{ 505 name: "amd64ios", 506 heading: "GOOS=ios on darwin/amd64", 507 fn: func(dt *distTest) error { 508 cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-run=SystemRoots", "crypto/x509") 509 setEnv(cmd, "GOOS", "ios") 510 setEnv(cmd, "CGO_ENABLED", "1") 511 return nil 512 }, 513 }) 514 } 515 516 if t.race { 517 return 518 } 519 520 // Runtime CPU tests. 521 if !t.compileOnly && goos != "js" { // js can't handle -cpu != 1 522 testName := "runtime:cpu124" 523 t.tests = append(t.tests, distTest{ 524 name: testName, 525 heading: "GOMAXPROCS=2 runtime -cpu=1,2,4 -quick", 526 fn: func(dt *distTest) error { 527 cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(300), "runtime", "-cpu=1,2,4", "-quick") 528 // We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code, 529 // creation of first goroutines and first garbage collections in the parallel setting. 530 setEnv(cmd, "GOMAXPROCS", "2") 531 return nil 532 }, 533 }) 534 } 535 536 // This test needs its stdout/stderr to be terminals, so we don't run it from cmd/go's tests. 537 // See issue 18153. 538 if goos == "linux" { 539 t.tests = append(t.tests, distTest{ 540 name: "cmd_go_test_terminal", 541 heading: "cmd/go terminal test", 542 fn: func(dt *distTest) error { 543 t.runPending(dt) 544 timelog("start", dt.name) 545 defer timelog("end", dt.name) 546 if !stdOutErrAreTerminals() { 547 fmt.Println("skipping terminal test; stdout/stderr not terminals") 548 return nil 549 } 550 cmd := exec.Command("go", "test") 551 setDir(cmd, filepath.Join(os.Getenv("GOROOT"), "src/cmd/go/testdata/testterminal18153")) 552 cmd.Stdout = os.Stdout 553 cmd.Stderr = os.Stderr 554 return cmd.Run() 555 }, 556 }) 557 } 558 559 // On the builders only, test that a moved GOROOT still works. 560 // Fails on iOS because CC_FOR_TARGET refers to clangwrap.sh 561 // in the unmoved GOROOT. 562 // Fails on Android and js/wasm with an exec format error. 563 // Fails on plan9 with "cannot find GOROOT" (issue #21016). 564 if os.Getenv("GO_BUILDER_NAME") != "" && goos != "android" && !t.iOS() && goos != "plan9" && goos != "js" { 565 t.tests = append(t.tests, distTest{ 566 name: "moved_goroot", 567 heading: "moved GOROOT", 568 fn: func(dt *distTest) error { 569 t.runPending(dt) 570 timelog("start", dt.name) 571 defer timelog("end", dt.name) 572 moved := goroot + "-moved" 573 if err := os.Rename(goroot, moved); err != nil { 574 if goos == "windows" { 575 // Fails on Windows (with "Access is denied") if a process 576 // or binary is in this directory. For instance, using all.bat 577 // when run from c:\workdir\go\src fails here 578 // if GO_BUILDER_NAME is set. Our builders invoke tests 579 // a different way which happens to work when sharding 580 // tests, but we should be tolerant of the non-sharded 581 // all.bat case. 582 log.Printf("skipping test on Windows") 583 return nil 584 } 585 return err 586 } 587 588 // Run `go test fmt` in the moved GOROOT, without explicitly setting 589 // GOROOT in the environment. The 'go' command should find itself. 590 cmd := exec.Command(filepath.Join(moved, "bin", "go"), "test", "fmt") 591 cmd.Stdout = os.Stdout 592 cmd.Stderr = os.Stderr 593 unsetEnv(cmd, "GOROOT") 594 unsetEnv(cmd, "GOCACHE") // TODO(bcmills): ...why‽ 595 err := cmd.Run() 596 597 if rerr := os.Rename(moved, goroot); rerr != nil { 598 fatalf("failed to restore GOROOT: %v", rerr) 599 } 600 return err 601 }, 602 }) 603 } 604 605 // Test that internal linking of standard packages does not 606 // require libgcc. This ensures that we can install a Go 607 // release on a system that does not have a C compiler 608 // installed and still build Go programs (that don't use cgo). 609 for _, pkg := range cgoPackages { 610 if !t.internalLink() { 611 break 612 } 613 614 // ARM libgcc may be Thumb, which internal linking does not support. 615 if goarch == "arm" { 616 break 617 } 618 619 pkg := pkg 620 var run string 621 if pkg == "net" { 622 run = "TestTCPStress" 623 } 624 t.tests = append(t.tests, distTest{ 625 name: "nolibgcc:" + pkg, 626 heading: "Testing without libgcc.", 627 fn: func(dt *distTest) error { 628 // What matters is that the tests build and start up. 629 // Skip expensive tests, especially x509 TestSystemRoots. 630 t.addCmd(dt, "src", t.goTest(), "-ldflags=-linkmode=internal -libgcc=none", "-run=^Test[^CS]", pkg, t.runFlag(run)) 631 return nil 632 }, 633 }) 634 } 635 636 // Test internal linking of PIE binaries where it is supported. 637 if t.internalLinkPIE() { 638 t.tests = append(t.tests, distTest{ 639 name: "pie_internal", 640 heading: "internal linking of -buildmode=pie", 641 fn: func(dt *distTest) error { 642 t.addCmd(dt, "src", t.goTest(), "reflect", "-buildmode=pie", "-ldflags=-linkmode=internal", t.timeout(60)) 643 return nil 644 }, 645 }) 646 // Also test a cgo package. 647 if t.cgoEnabled && t.internalLink() { 648 t.tests = append(t.tests, distTest{ 649 name: "pie_internal_cgo", 650 heading: "internal linking of -buildmode=pie", 651 fn: func(dt *distTest) error { 652 t.addCmd(dt, "src", t.goTest(), "os/user", "-buildmode=pie", "-ldflags=-linkmode=internal", t.timeout(60)) 653 return nil 654 }, 655 }) 656 } 657 } 658 659 // sync tests 660 if goos != "js" { // js doesn't support -cpu=10 661 t.tests = append(t.tests, distTest{ 662 name: "sync_cpu", 663 heading: "sync -cpu=10", 664 fn: func(dt *distTest) error { 665 t.addCmd(dt, "src", t.goTest(), "sync", t.timeout(120), "-cpu=10", t.runFlag("")) 666 return nil 667 }, 668 }) 669 } 670 671 if t.raceDetectorSupported() { 672 t.tests = append(t.tests, distTest{ 673 name: "race", 674 heading: "Testing race detector", 675 fn: t.raceTest, 676 }) 677 } 678 679 if t.cgoEnabled && !t.iOS() { 680 // Disabled on iOS. golang.org/issue/15919 681 t.registerHostTest("cgo_stdio", "../misc/cgo/stdio", "misc/cgo/stdio", ".") 682 t.registerHostTest("cgo_life", "../misc/cgo/life", "misc/cgo/life", ".") 683 fortran := os.Getenv("FC") 684 if fortran == "" { 685 fortran, _ = exec.LookPath("gfortran") 686 } 687 if t.hasBash() && goos != "android" && fortran != "" { 688 t.tests = append(t.tests, distTest{ 689 name: "cgo_fortran", 690 heading: "../misc/cgo/fortran", 691 fn: func(dt *distTest) error { 692 t.addCmd(dt, "misc/cgo/fortran", "./test.bash", fortran) 693 return nil 694 }, 695 }) 696 } 697 if t.hasSwig() && goos != "android" { 698 t.tests = append(t.tests, distTest{ 699 name: "swig_stdio", 700 heading: "../misc/swig/stdio", 701 fn: func(dt *distTest) error { 702 t.addCmd(dt, "misc/swig/stdio", t.goTest()) 703 return nil 704 }, 705 }) 706 if t.hasCxx() { 707 t.tests = append(t.tests, 708 distTest{ 709 name: "swig_callback", 710 heading: "../misc/swig/callback", 711 fn: func(dt *distTest) error { 712 t.addCmd(dt, "misc/swig/callback", t.goTest()) 713 return nil 714 }, 715 }, 716 distTest{ 717 name: "swig_callback_lto", 718 heading: "../misc/swig/callback", 719 fn: func(dt *distTest) error { 720 cmd := t.addCmd(dt, "misc/swig/callback", t.goTest()) 721 setEnv(cmd, "CGO_CFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option") 722 setEnv(cmd, "CGO_CXXFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option") 723 setEnv(cmd, "CGO_LDFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option") 724 return nil 725 }, 726 }, 727 ) 728 } 729 } 730 } 731 if t.cgoEnabled { 732 t.tests = append(t.tests, distTest{ 733 name: "cgo_test", 734 heading: "../misc/cgo/test", 735 fn: t.cgoTest, 736 }) 737 } 738 739 // Don't run these tests with $GO_GCFLAGS because most of them 740 // assume that they can run "go install" with no -gcflags and not 741 // recompile the entire standard library. If make.bash ran with 742 // special -gcflags, that's not true. 743 if t.cgoEnabled && gogcflags == "" { 744 t.registerHostTest("testgodefs", "../misc/cgo/testgodefs", "misc/cgo/testgodefs", ".") 745 746 t.registerTest("testso", "../misc/cgo/testso", t.goTest(), t.timeout(600), ".") 747 t.registerTest("testsovar", "../misc/cgo/testsovar", t.goTest(), t.timeout(600), ".") 748 if t.supportedBuildmode("c-archive") { 749 t.registerHostTest("testcarchive", "../misc/cgo/testcarchive", "misc/cgo/testcarchive", ".") 750 } 751 if t.supportedBuildmode("c-shared") { 752 t.registerHostTest("testcshared", "../misc/cgo/testcshared", "misc/cgo/testcshared", ".") 753 } 754 if t.supportedBuildmode("shared") { 755 t.registerTest("testshared", "../misc/cgo/testshared", t.goTest(), t.timeout(600), ".") 756 } 757 if t.supportedBuildmode("plugin") { 758 t.registerTest("testplugin", "../misc/cgo/testplugin", t.goTest(), t.timeout(600), ".") 759 } 760 if gohostos == "linux" && goarch == "amd64" { 761 t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", ".") 762 } 763 if goos == "linux" && goarch != "ppc64le" { 764 // because syscall.SysProcAttr struct used in misc/cgo/testsanitizers is only built on linux. 765 // Some inconsistent failures happen on ppc64le so disable for now. 766 t.registerHostTest("testsanitizers", "../misc/cgo/testsanitizers", "misc/cgo/testsanitizers", ".") 767 } 768 if t.hasBash() && goos != "android" && !t.iOS() && gohostos != "windows" { 769 t.registerHostTest("cgo_errors", "../misc/cgo/errors", "misc/cgo/errors", ".") 770 } 771 if gohostos == "linux" && t.extLink() { 772 t.registerTest("testsigfwd", "../misc/cgo/testsigfwd", "go", "run", ".") 773 } 774 } 775 776 if goos != "android" && !t.iOS() { 777 // There are no tests in this directory, only benchmarks. 778 // Check that the test binary builds but don't bother running it. 779 // (It has init-time work to set up for the benchmarks that is not worth doing unnecessarily.) 780 t.registerTest("bench_go1", "../test/bench/go1", t.goTest(), "-c", "-o="+os.DevNull) 781 } 782 if goos != "android" && !t.iOS() { 783 // Only start multiple test dir shards on builders, 784 // where they get distributed to multiple machines. 785 // See issues 20141 and 31834. 786 nShards := 1 787 if os.Getenv("GO_BUILDER_NAME") != "" { 788 nShards = 10 789 } 790 if n, err := strconv.Atoi(os.Getenv("GO_TEST_SHARDS")); err == nil { 791 nShards = n 792 } 793 for shard := 0; shard < nShards; shard++ { 794 shard := shard 795 t.tests = append(t.tests, distTest{ 796 name: fmt.Sprintf("test:%d_%d", shard, nShards), 797 heading: "../test", 798 fn: func(dt *distTest) error { return t.testDirTest(dt, shard, nShards) }, 799 }) 800 } 801 } 802 // Only run the API check on fast development platforms. Android, iOS, and JS 803 // are always cross-compiled, and the filesystems on our only plan9 builders 804 // are too slow to complete in a reasonable timeframe. Every platform checks 805 // the API on every GOOS/GOARCH/CGO_ENABLED combination anyway, so we really 806 // only need to run this check once anywhere to get adequate coverage. 807 if goos != "android" && !t.iOS() && goos != "js" && goos != "plan9" { 808 t.tests = append(t.tests, distTest{ 809 name: "api", 810 heading: "API check", 811 fn: func(dt *distTest) error { 812 if t.compileOnly { 813 t.addCmd(dt, "src", "go", "build", "-o", os.DevNull, filepath.Join(goroot, "src/cmd/api/run.go")) 814 return nil 815 } 816 t.addCmd(dt, "src", "go", "run", filepath.Join(goroot, "src/cmd/api/run.go")) 817 return nil 818 }, 819 }) 820 } 821 822 // Ensure that the toolchain can bootstrap itself. 823 // This test adds another ~45s to all.bash if run sequentially, so run it only on the builders. 824 if os.Getenv("GO_BUILDER_NAME") != "" && goos != "android" && !t.iOS() { 825 t.registerHostTest("reboot", "../misc/reboot", "misc/reboot", ".") 826 } 827} 828 829// isRegisteredTestName reports whether a test named testName has already 830// been registered. 831func (t *tester) isRegisteredTestName(testName string) bool { 832 for _, tt := range t.tests { 833 if tt.name == testName { 834 return true 835 } 836 } 837 return false 838} 839 840func (t *tester) registerTest1(seq bool, name, dirBanner string, cmdline ...interface{}) { 841 bin, args := flattenCmdline(cmdline) 842 if bin == "time" && !t.haveTime { 843 bin, args = args[0], args[1:] 844 } 845 if t.isRegisteredTestName(name) { 846 panic("duplicate registered test name " + name) 847 } 848 t.tests = append(t.tests, distTest{ 849 name: name, 850 heading: dirBanner, 851 fn: func(dt *distTest) error { 852 if seq { 853 t.runPending(dt) 854 timelog("start", name) 855 defer timelog("end", name) 856 return t.dirCmd(filepath.Join(goroot, "src", dirBanner), bin, args).Run() 857 } 858 t.addCmd(dt, filepath.Join(goroot, "src", dirBanner), bin, args) 859 return nil 860 }, 861 }) 862} 863 864func (t *tester) registerTest(name, dirBanner string, cmdline ...interface{}) { 865 t.registerTest1(false, name, dirBanner, cmdline...) 866} 867 868func (t *tester) registerSeqTest(name, dirBanner string, cmdline ...interface{}) { 869 t.registerTest1(true, name, dirBanner, cmdline...) 870} 871 872func (t *tester) bgDirCmd(dir, bin string, args ...string) *exec.Cmd { 873 cmd := exec.Command(bin, args...) 874 if filepath.IsAbs(dir) { 875 setDir(cmd, dir) 876 } else { 877 setDir(cmd, filepath.Join(goroot, dir)) 878 } 879 return cmd 880} 881 882func (t *tester) dirCmd(dir string, cmdline ...interface{}) *exec.Cmd { 883 bin, args := flattenCmdline(cmdline) 884 cmd := t.bgDirCmd(dir, bin, args...) 885 cmd.Stdout = os.Stdout 886 cmd.Stderr = os.Stderr 887 if vflag > 1 { 888 errprintf("%s\n", strings.Join(cmd.Args, " ")) 889 } 890 return cmd 891} 892 893// flattenCmdline flattens a mixture of string and []string as single list 894// and then interprets it as a command line: first element is binary, then args. 895func flattenCmdline(cmdline []interface{}) (bin string, args []string) { 896 var list []string 897 for _, x := range cmdline { 898 switch x := x.(type) { 899 case string: 900 list = append(list, x) 901 case []string: 902 list = append(list, x...) 903 default: 904 panic("invalid addCmd argument type: " + reflect.TypeOf(x).String()) 905 } 906 } 907 908 // The go command is too picky about duplicated flags. 909 // Drop all but the last of the allowed duplicated flags. 910 drop := make([]bool, len(list)) 911 have := map[string]int{} 912 for i := 1; i < len(list); i++ { 913 j := strings.Index(list[i], "=") 914 if j < 0 { 915 continue 916 } 917 flag := list[i][:j] 918 switch flag { 919 case "-run", "-tags": 920 if have[flag] != 0 { 921 drop[have[flag]] = true 922 } 923 have[flag] = i 924 } 925 } 926 out := list[:0] 927 for i, x := range list { 928 if !drop[i] { 929 out = append(out, x) 930 } 931 } 932 list = out 933 934 return list[0], list[1:] 935} 936 937func (t *tester) addCmd(dt *distTest, dir string, cmdline ...interface{}) *exec.Cmd { 938 bin, args := flattenCmdline(cmdline) 939 w := &work{ 940 dt: dt, 941 cmd: t.bgDirCmd(dir, bin, args...), 942 } 943 t.worklist = append(t.worklist, w) 944 return w.cmd 945} 946 947func (t *tester) iOS() bool { 948 return goos == "ios" 949} 950 951func (t *tester) out(v string) { 952 if t.banner == "" { 953 return 954 } 955 fmt.Println("\n" + t.banner + v) 956} 957 958func (t *tester) extLink() bool { 959 pair := gohostos + "-" + goarch 960 switch pair { 961 case "aix-ppc64", 962 "android-arm", "android-arm64", 963 "darwin-amd64", "darwin-arm64", 964 "dragonfly-amd64", 965 "freebsd-386", "freebsd-amd64", "freebsd-arm", 966 "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le", "linux-mips", "linux-mipsle", "linux-riscv64", "linux-s390x", 967 "netbsd-386", "netbsd-amd64", 968 "openbsd-386", "openbsd-amd64", 969 "windows-386", "windows-amd64": 970 return true 971 } 972 return false 973} 974 975func (t *tester) internalLink() bool { 976 if gohostos == "dragonfly" { 977 // linkmode=internal fails on dragonfly since errno is a TLS relocation. 978 return false 979 } 980 if goos == "android" { 981 return false 982 } 983 if goos == "ios" { 984 return false 985 } 986 if goos == "windows" && goarch == "arm64" { 987 return false 988 } 989 // Internally linking cgo is incomplete on some architectures. 990 // https://golang.org/issue/10373 991 // https://golang.org/issue/14449 992 if goarch == "mips64" || goarch == "mips64le" || goarch == "mips" || goarch == "mipsle" || goarch == "riscv64" { 993 return false 994 } 995 if goos == "aix" { 996 // linkmode=internal isn't supported. 997 return false 998 } 999 return true 1000} 1001 1002func (t *tester) internalLinkPIE() bool { 1003 switch goos + "-" + goarch { 1004 case "darwin-amd64", "darwin-arm64", 1005 "linux-amd64", "linux-arm64", "linux-ppc64le", 1006 "android-arm64", 1007 "windows-amd64", "windows-386", "windows-arm": 1008 return true 1009 } 1010 return false 1011} 1012 1013func (t *tester) supportedBuildmode(mode string) bool { 1014 pair := goos + "-" + goarch 1015 switch mode { 1016 case "c-archive": 1017 if !t.extLink() { 1018 return false 1019 } 1020 switch pair { 1021 case "aix-ppc64", 1022 "darwin-amd64", "darwin-arm64", "ios-arm64", 1023 "linux-amd64", "linux-386", "linux-ppc64le", "linux-riscv64", "linux-s390x", 1024 "freebsd-amd64", 1025 "windows-amd64", "windows-386": 1026 return true 1027 } 1028 return false 1029 case "c-shared": 1030 switch pair { 1031 case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x", 1032 "darwin-amd64", "darwin-arm64", 1033 "freebsd-amd64", 1034 "android-arm", "android-arm64", "android-386", 1035 "windows-amd64", "windows-386", "windows-arm64": 1036 return true 1037 } 1038 return false 1039 case "shared": 1040 switch pair { 1041 case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x": 1042 return true 1043 } 1044 return false 1045 case "plugin": 1046 switch pair { 1047 case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-s390x", "linux-ppc64le": 1048 return true 1049 case "darwin-amd64", "darwin-arm64": 1050 return true 1051 case "freebsd-amd64": 1052 return true 1053 } 1054 return false 1055 case "pie": 1056 switch pair { 1057 case "aix/ppc64", 1058 "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x", 1059 "android-amd64", "android-arm", "android-arm64", "android-386": 1060 return true 1061 case "darwin-amd64", "darwin-arm64": 1062 return true 1063 case "windows-amd64", "windows-386", "windows-arm": 1064 return true 1065 } 1066 return false 1067 1068 default: 1069 fatalf("internal error: unknown buildmode %s", mode) 1070 return false 1071 } 1072} 1073 1074func (t *tester) registerHostTest(name, heading, dir, pkg string) { 1075 t.tests = append(t.tests, distTest{ 1076 name: name, 1077 heading: heading, 1078 fn: func(dt *distTest) error { 1079 t.runPending(dt) 1080 timelog("start", name) 1081 defer timelog("end", name) 1082 return t.runHostTest(dir, pkg) 1083 }, 1084 }) 1085} 1086 1087func (t *tester) runHostTest(dir, pkg string) error { 1088 out, err := exec.Command("go", "env", "GOEXE", "GOTMPDIR").Output() 1089 if err != nil { 1090 return err 1091 } 1092 1093 parts := strings.Split(string(out), "\n") 1094 if len(parts) < 2 { 1095 return fmt.Errorf("'go env GOEXE GOTMPDIR' output contains <2 lines") 1096 } 1097 GOEXE := strings.TrimSpace(parts[0]) 1098 GOTMPDIR := strings.TrimSpace(parts[1]) 1099 1100 f, err := ioutil.TempFile(GOTMPDIR, "test.test-*"+GOEXE) 1101 if err != nil { 1102 return err 1103 } 1104 f.Close() 1105 defer os.Remove(f.Name()) 1106 1107 cmd := t.dirCmd(dir, t.goTest(), "-c", "-o", f.Name(), pkg) 1108 setEnv(cmd, "GOARCH", gohostarch) 1109 setEnv(cmd, "GOOS", gohostos) 1110 if err := cmd.Run(); err != nil { 1111 return err 1112 } 1113 return t.dirCmd(dir, f.Name(), "-test.short="+short()).Run() 1114} 1115 1116func (t *tester) cgoTest(dt *distTest) error { 1117 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest()) 1118 setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=auto") 1119 1120 // Skip internal linking cases on linux/arm64 to support GCC-9.4 and above. 1121 // See issue #39466. 1122 skipInternalLink := goarch == "arm64" && goos == "linux" 1123 1124 if t.internalLink() && !skipInternalLink { 1125 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=internal") 1126 setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=internal") 1127 } 1128 1129 pair := gohostos + "-" + goarch 1130 switch pair { 1131 case "darwin-amd64", "darwin-arm64", 1132 "windows-386", "windows-amd64": 1133 // test linkmode=external, but __thread not supported, so skip testtls. 1134 if !t.extLink() { 1135 break 1136 } 1137 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest()) 1138 setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=external") 1139 1140 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s") 1141 1142 if t.supportedBuildmode("pie") { 1143 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie") 1144 if t.internalLink() && t.internalLinkPIE() { 1145 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal", "-tags=internal,internal_pie") 1146 } 1147 } 1148 1149 case "aix-ppc64", 1150 "android-arm", "android-arm64", 1151 "dragonfly-amd64", 1152 "freebsd-386", "freebsd-amd64", "freebsd-arm", 1153 "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x", 1154 "netbsd-386", "netbsd-amd64", 1155 "openbsd-386", "openbsd-amd64", "openbsd-arm", "openbsd-arm64", "openbsd-mips64": 1156 1157 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest()) 1158 setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=external") 1159 // cgo should be able to cope with both -g arguments and colored 1160 // diagnostics. 1161 setEnv(cmd, "CGO_CFLAGS", "-g0 -fdiagnostics-color") 1162 1163 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=auto") 1164 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=external") 1165 1166 switch pair { 1167 case "aix-ppc64", "netbsd-386", "netbsd-amd64": 1168 // no static linking 1169 case "freebsd-arm": 1170 // -fPIC compiled tls code will use __tls_get_addr instead 1171 // of __aeabi_read_tp, however, on FreeBSD/ARM, __tls_get_addr 1172 // is implemented in rtld-elf, so -fPIC isn't compatible with 1173 // static linking on FreeBSD/ARM with clang. (cgo depends on 1174 // -fPIC fundamentally.) 1175 default: 1176 cmd := t.dirCmd("misc/cgo/test", 1177 compilerEnvLookup(defaultcc, goos, goarch), "-xc", "-o", "/dev/null", "-static", "-") 1178 cmd.Stdin = strings.NewReader("int main() {}") 1179 if err := cmd.Run(); err != nil { 1180 fmt.Println("No support for static linking found (lacks libc.a?), skip cgo static linking test.") 1181 } else { 1182 if goos != "android" { 1183 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", `-linkmode=external -extldflags "-static -pthread"`) 1184 } 1185 t.addCmd(dt, "misc/cgo/nocgo", t.goTest()) 1186 t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-ldflags", `-linkmode=external`) 1187 if goos != "android" { 1188 t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-ldflags", `-linkmode=external -extldflags "-static -pthread"`) 1189 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`) 1190 // -static in CGO_LDFLAGS triggers a different code path 1191 // than -static in -extldflags, so test both. 1192 // See issue #16651. 1193 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static") 1194 setEnv(cmd, "CGO_LDFLAGS", "-static -pthread") 1195 } 1196 } 1197 1198 if t.supportedBuildmode("pie") { 1199 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie") 1200 if t.internalLink() && t.internalLinkPIE() && !skipInternalLink { 1201 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal", "-tags=internal,internal_pie") 1202 } 1203 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-buildmode=pie") 1204 t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-buildmode=pie") 1205 } 1206 } 1207 } 1208 1209 return nil 1210} 1211 1212// run pending test commands, in parallel, emitting headers as appropriate. 1213// When finished, emit header for nextTest, which is going to run after the 1214// pending commands are done (and runPending returns). 1215// A test should call runPending if it wants to make sure that it is not 1216// running in parallel with earlier tests, or if it has some other reason 1217// for needing the earlier tests to be done. 1218func (t *tester) runPending(nextTest *distTest) { 1219 checkNotStale("go", "std") 1220 worklist := t.worklist 1221 t.worklist = nil 1222 for _, w := range worklist { 1223 w.start = make(chan bool) 1224 w.end = make(chan bool) 1225 go func(w *work) { 1226 if !<-w.start { 1227 timelog("skip", w.dt.name) 1228 w.out = []byte(fmt.Sprintf("skipped due to earlier error\n")) 1229 } else { 1230 timelog("start", w.dt.name) 1231 w.out, w.err = w.cmd.CombinedOutput() 1232 if w.err != nil { 1233 if isUnsupportedVMASize(w) { 1234 timelog("skip", w.dt.name) 1235 w.out = []byte(fmt.Sprintf("skipped due to unsupported VMA\n")) 1236 w.err = nil 1237 } 1238 } 1239 } 1240 timelog("end", w.dt.name) 1241 w.end <- true 1242 }(w) 1243 } 1244 1245 started := 0 1246 ended := 0 1247 var last *distTest 1248 for ended < len(worklist) { 1249 for started < len(worklist) && started-ended < maxbg { 1250 w := worklist[started] 1251 started++ 1252 w.start <- !t.failed || t.keepGoing 1253 } 1254 w := worklist[ended] 1255 dt := w.dt 1256 if dt.heading != "" && t.lastHeading != dt.heading { 1257 t.lastHeading = dt.heading 1258 t.out(dt.heading) 1259 } 1260 if dt != last { 1261 // Assumes all the entries for a single dt are in one worklist. 1262 last = w.dt 1263 if vflag > 0 { 1264 fmt.Printf("# go tool dist test -run=^%s$\n", dt.name) 1265 } 1266 } 1267 if vflag > 1 { 1268 errprintf("%s\n", strings.Join(w.cmd.Args, " ")) 1269 } 1270 ended++ 1271 <-w.end 1272 os.Stdout.Write(w.out) 1273 if w.err != nil { 1274 log.Printf("Failed: %v", w.err) 1275 t.failed = true 1276 } 1277 checkNotStale("go", "std") 1278 } 1279 if t.failed && !t.keepGoing { 1280 fatalf("FAILED") 1281 } 1282 1283 if dt := nextTest; dt != nil { 1284 if dt.heading != "" && t.lastHeading != dt.heading { 1285 t.lastHeading = dt.heading 1286 t.out(dt.heading) 1287 } 1288 if vflag > 0 { 1289 fmt.Printf("# go tool dist test -run=^%s$\n", dt.name) 1290 } 1291 } 1292} 1293 1294func (t *tester) hasBash() bool { 1295 switch gohostos { 1296 case "windows", "plan9": 1297 return false 1298 } 1299 return true 1300} 1301 1302func (t *tester) hasCxx() bool { 1303 cxx, _ := exec.LookPath(compilerEnvLookup(defaultcxx, goos, goarch)) 1304 return cxx != "" 1305} 1306 1307func (t *tester) hasSwig() bool { 1308 swig, err := exec.LookPath("swig") 1309 if err != nil { 1310 return false 1311 } 1312 1313 // Check that swig was installed with Go support by checking 1314 // that a go directory exists inside the swiglib directory. 1315 // See https://golang.org/issue/23469. 1316 output, err := exec.Command(swig, "-go", "-swiglib").Output() 1317 if err != nil { 1318 return false 1319 } 1320 swigDir := strings.TrimSpace(string(output)) 1321 1322 _, err = os.Stat(filepath.Join(swigDir, "go")) 1323 if err != nil { 1324 return false 1325 } 1326 1327 // Check that swig has a new enough version. 1328 // See https://golang.org/issue/22858. 1329 out, err := exec.Command(swig, "-version").CombinedOutput() 1330 if err != nil { 1331 return false 1332 } 1333 1334 re := regexp.MustCompile(`[vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)?`) 1335 matches := re.FindSubmatch(out) 1336 if matches == nil { 1337 // Can't find version number; hope for the best. 1338 return true 1339 } 1340 1341 major, err := strconv.Atoi(string(matches[1])) 1342 if err != nil { 1343 // Can't find version number; hope for the best. 1344 return true 1345 } 1346 if major < 3 { 1347 return false 1348 } 1349 if major > 3 { 1350 // 4.0 or later 1351 return true 1352 } 1353 1354 // We have SWIG version 3.x. 1355 if len(matches[2]) > 0 { 1356 minor, err := strconv.Atoi(string(matches[2][1:])) 1357 if err != nil { 1358 return true 1359 } 1360 if minor > 0 { 1361 // 3.1 or later 1362 return true 1363 } 1364 } 1365 1366 // We have SWIG version 3.0.x. 1367 if len(matches[3]) > 0 { 1368 patch, err := strconv.Atoi(string(matches[3][1:])) 1369 if err != nil { 1370 return true 1371 } 1372 if patch < 6 { 1373 // Before 3.0.6. 1374 return false 1375 } 1376 } 1377 1378 return true 1379} 1380 1381func (t *tester) raceDetectorSupported() bool { 1382 if gohostos != goos { 1383 return false 1384 } 1385 if !t.cgoEnabled { 1386 return false 1387 } 1388 if !raceDetectorSupported(goos, goarch) { 1389 return false 1390 } 1391 // The race detector doesn't work on Alpine Linux: 1392 // golang.org/issue/14481 1393 if isAlpineLinux() { 1394 return false 1395 } 1396 // NetBSD support is unfinished. 1397 // golang.org/issue/26403 1398 if goos == "netbsd" { 1399 return false 1400 } 1401 return true 1402} 1403 1404func isAlpineLinux() bool { 1405 if runtime.GOOS != "linux" { 1406 return false 1407 } 1408 fi, err := os.Lstat("/etc/alpine-release") 1409 return err == nil && fi.Mode().IsRegular() 1410} 1411 1412func (t *tester) runFlag(rx string) string { 1413 if t.compileOnly { 1414 return "-run=^$" 1415 } 1416 return "-run=" + rx 1417} 1418 1419func (t *tester) raceTest(dt *distTest) error { 1420 t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("Output"), "runtime/race") 1421 t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace|TestTypeRace|TestFdRace|TestFdReadRace|TestFileCloseRace"), "flag", "net", "os", "os/exec", "encoding/gob") 1422 // We don't want the following line, because it 1423 // slows down all.bash (by 10 seconds on my laptop). 1424 // The race builder should catch any error here, but doesn't. 1425 // TODO(iant): Figure out how to catch this. 1426 // t.addCmd(dt, "src", t.goTest(), "-race", "-run=TestParallelTest", "cmd/go") 1427 if t.cgoEnabled { 1428 // Building misc/cgo/test takes a long time. 1429 // There are already cgo-enabled packages being tested with the race detector. 1430 // We shouldn't need to redo all of misc/cgo/test too. 1431 // The race buildler will take care of this. 1432 // cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-race") 1433 // setEnv(cmd, "GOTRACEBACK", "2") 1434 } 1435 if t.extLink() { 1436 // Test with external linking; see issue 9133. 1437 t.addCmd(dt, "src", t.goTest(), "-race", "-ldflags=-linkmode=external", t.runFlag("TestParse|TestEcho|TestStdinCloseRace"), "flag", "os/exec") 1438 } 1439 return nil 1440} 1441 1442var runtest struct { 1443 sync.Once 1444 exe string 1445 err error 1446} 1447 1448func (t *tester) testDirTest(dt *distTest, shard, shards int) error { 1449 runtest.Do(func() { 1450 f, err := ioutil.TempFile("", "runtest-*.exe") // named exe for Windows, but harmless elsewhere 1451 if err != nil { 1452 runtest.err = err 1453 return 1454 } 1455 f.Close() 1456 1457 runtest.exe = f.Name() 1458 xatexit(func() { 1459 os.Remove(runtest.exe) 1460 }) 1461 1462 cmd := t.dirCmd("test", "go", "build", "-o", runtest.exe, "run.go") 1463 setEnv(cmd, "GOOS", gohostos) 1464 setEnv(cmd, "GOARCH", gohostarch) 1465 runtest.err = cmd.Run() 1466 }) 1467 if runtest.err != nil { 1468 return runtest.err 1469 } 1470 if t.compileOnly { 1471 return nil 1472 } 1473 t.addCmd(dt, "test", runtest.exe, 1474 fmt.Sprintf("--shard=%d", shard), 1475 fmt.Sprintf("--shards=%d", shards), 1476 ) 1477 return nil 1478} 1479 1480// cgoPackages is the standard packages that use cgo. 1481var cgoPackages = []string{ 1482 "net", 1483 "os/user", 1484} 1485 1486var funcBenchmark = []byte("\nfunc Benchmark") 1487 1488// packageHasBenchmarks reports whether pkg has benchmarks. 1489// On any error, it conservatively returns true. 1490// 1491// This exists just to eliminate work on the builders, since compiling 1492// a test in race mode just to discover it has no benchmarks costs a 1493// second or two per package, and this function returns false for 1494// about 100 packages. 1495func (t *tester) packageHasBenchmarks(pkg string) bool { 1496 pkgDir := filepath.Join(goroot, "src", pkg) 1497 d, err := os.Open(pkgDir) 1498 if err != nil { 1499 return true // conservatively 1500 } 1501 defer d.Close() 1502 names, err := d.Readdirnames(-1) 1503 if err != nil { 1504 return true // conservatively 1505 } 1506 for _, name := range names { 1507 if !strings.HasSuffix(name, "_test.go") { 1508 continue 1509 } 1510 slurp, err := ioutil.ReadFile(filepath.Join(pkgDir, name)) 1511 if err != nil { 1512 return true // conservatively 1513 } 1514 if bytes.Contains(slurp, funcBenchmark) { 1515 return true 1516 } 1517 } 1518 return false 1519} 1520 1521// makeGOROOTUnwritable makes all $GOROOT files & directories non-writable to 1522// check that no tests accidentally write to $GOROOT. 1523func (t *tester) makeGOROOTUnwritable() (undo func()) { 1524 dir := os.Getenv("GOROOT") 1525 if dir == "" { 1526 panic("GOROOT not set") 1527 } 1528 1529 type pathMode struct { 1530 path string 1531 mode os.FileMode 1532 } 1533 var dirs []pathMode // in lexical order 1534 1535 undo = func() { 1536 for i := range dirs { 1537 os.Chmod(dirs[i].path, dirs[i].mode) // best effort 1538 } 1539 } 1540 1541 gocache := os.Getenv("GOCACHE") 1542 if gocache == "" { 1543 panic("GOCACHE not set") 1544 } 1545 gocacheSubdir, _ := filepath.Rel(dir, gocache) 1546 1547 // Note: Can't use WalkDir here, because this has to compile with Go 1.4. 1548 filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 1549 if suffix := strings.TrimPrefix(path, dir+string(filepath.Separator)); suffix != "" { 1550 if suffix == gocacheSubdir { 1551 // Leave GOCACHE writable: we may need to write test binaries into it. 1552 return filepath.SkipDir 1553 } 1554 if suffix == ".git" { 1555 // Leave Git metadata in whatever state it was in. It may contain a lot 1556 // of files, and it is highly unlikely that a test will try to modify 1557 // anything within that directory. 1558 return filepath.SkipDir 1559 } 1560 } 1561 if err == nil { 1562 mode := info.Mode() 1563 if mode&0222 != 0 && (mode.IsDir() || mode.IsRegular()) { 1564 dirs = append(dirs, pathMode{path, mode}) 1565 } 1566 } 1567 return nil 1568 }) 1569 1570 // Run over list backward to chmod children before parents. 1571 for i := len(dirs) - 1; i >= 0; i-- { 1572 err := os.Chmod(dirs[i].path, dirs[i].mode&^0222) 1573 if err != nil { 1574 dirs = dirs[i:] // Only undo what we did so far. 1575 undo() 1576 fatalf("failed to make GOROOT read-only: %v", err) 1577 } 1578 } 1579 1580 return undo 1581} 1582 1583// shouldUsePrecompiledStdTest reports whether "dist test" should use 1584// a pre-compiled go test binary on disk rather than running "go test" 1585// and compiling it again. This is used by our slow qemu-based builder 1586// that do full processor emulation where we cross-compile the 1587// make.bash step as well as pre-compile each std test binary. 1588// 1589// This only reports true if dist is run with an single go_test:foo 1590// argument (as the build coordinator does with our slow qemu-based 1591// builders), we're in a builder environment ("GO_BUILDER_NAME" is set), 1592// and the pre-built test binary exists. 1593func (t *tester) shouldUsePrecompiledStdTest() bool { 1594 bin := t.prebuiltGoPackageTestBinary() 1595 if bin == "" { 1596 return false 1597 } 1598 _, err := os.Stat(bin) 1599 return err == nil 1600} 1601 1602func (t *tester) shouldTestCmd() bool { 1603 if goos == "js" && goarch == "wasm" { 1604 // Issues 25911, 35220 1605 return false 1606 } 1607 return true 1608} 1609 1610// prebuiltGoPackageTestBinary returns the path where we'd expect 1611// the pre-built go test binary to be on disk when dist test is run with 1612// a single argument. 1613// It returns an empty string if a pre-built binary should not be used. 1614func (t *tester) prebuiltGoPackageTestBinary() string { 1615 if len(stdMatches) != 1 || t.race || t.compileOnly || os.Getenv("GO_BUILDER_NAME") == "" { 1616 return "" 1617 } 1618 pkg := stdMatches[0] 1619 return filepath.Join(os.Getenv("GOROOT"), "src", pkg, path.Base(pkg)+".test") 1620} 1621 1622// runPrecompiledStdTest runs the pre-compiled standard library package test binary. 1623// See shouldUsePrecompiledStdTest above; it must return true for this to be called. 1624func (t *tester) runPrecompiledStdTest(timeout time.Duration) error { 1625 bin := t.prebuiltGoPackageTestBinary() 1626 fmt.Fprintf(os.Stderr, "# %s: using pre-built %s...\n", stdMatches[0], bin) 1627 cmd := exec.Command(bin, "-test.short="+short(), "-test.timeout="+timeout.String()) 1628 setDir(cmd, filepath.Dir(bin)) 1629 cmd.Stdout = os.Stdout 1630 cmd.Stderr = os.Stderr 1631 if err := cmd.Start(); err != nil { 1632 return err 1633 } 1634 // And start a timer to kill the process if it doesn't kill 1635 // itself in the prescribed timeout. 1636 const backupKillFactor = 1.05 // add 5% 1637 timer := time.AfterFunc(time.Duration(float64(timeout)*backupKillFactor), func() { 1638 fmt.Fprintf(os.Stderr, "# %s: timeout running %s; killing...\n", stdMatches[0], bin) 1639 cmd.Process.Kill() 1640 }) 1641 defer timer.Stop() 1642 return cmd.Wait() 1643} 1644 1645// raceDetectorSupported is a copy of the function 1646// cmd/internal/sys.RaceDetectorSupported, which can't be used here 1647// because cmd/dist has to be buildable by Go 1.4. 1648// The race detector only supports 48-bit VMA on arm64. But we don't have 1649// a good solution to check VMA size(See https://golang.org/issue/29948) 1650// raceDetectorSupported will always return true for arm64. But race 1651// detector tests may abort on non 48-bit VMA configuration, the tests 1652// will be marked as "skipped" in this case. 1653func raceDetectorSupported(goos, goarch string) bool { 1654 switch goos { 1655 case "linux": 1656 return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64" 1657 case "darwin": 1658 return goarch == "amd64" || goarch == "arm64" 1659 case "freebsd", "netbsd", "openbsd", "windows": 1660 return goarch == "amd64" 1661 default: 1662 return false 1663 } 1664} 1665 1666// isUnsupportedVMASize reports whether the failure is caused by an unsupported 1667// VMA for the race detector (for example, running the race detector on an 1668// arm64 machine configured with 39-bit VMA) 1669func isUnsupportedVMASize(w *work) bool { 1670 unsupportedVMA := []byte("unsupported VMA range") 1671 return w.dt.name == "race" && bytes.Contains(w.out, unsupportedVMA) 1672} 1673 1674// isEnvSet reports whether the environment variable evar is 1675// set in the environment. 1676func isEnvSet(evar string) bool { 1677 evarEq := evar + "=" 1678 for _, e := range os.Environ() { 1679 if strings.HasPrefix(e, evarEq) { 1680 return true 1681 } 1682 } 1683 return false 1684} 1685