github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/src/cmd/dist/cmdtest.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 "reflect" 18 "regexp" 19 "runtime" 20 "strconv" 21 "strings" 22 "sync" 23 "time" 24 ) 25 26 func _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 t.run() 46 } 47 48 func timelog(op, name string) { 49 if !timeLogEnabled { 50 return 51 } 52 timeLogMu.Lock() 53 defer timeLogMu.Unlock() 54 if timeLogFile == nil { 55 f, err := os.OpenFile(os.Getenv("GOBUILDTIMELOGFILE"), os.O_RDWR|os.O_APPEND, 0666) 56 if err != nil { 57 log.Fatal(err) 58 } 59 buf := make([]byte, 100) 60 n, _ := f.Read(buf) 61 s := string(buf[:n]) 62 if i := strings.Index(s, "\n"); i >= 0 { 63 s = s[:i] 64 } 65 i := strings.Index(s, " start") 66 if i < 0 { 67 log.Fatalf("time log %s does not begin with start line", os.Getenv("GOBULDTIMELOGFILE")) 68 } 69 t, err := time.Parse(time.UnixDate, s[:i]) 70 if err != nil { 71 log.Fatalf("cannot parse time log line %q: %v", s, err) 72 } 73 timeLogStart = t 74 timeLogFile = f 75 } 76 t := time.Now() 77 fmt.Fprintf(timeLogFile, "%s %+.1fs %s %s\n", t.Format(time.UnixDate), t.Sub(timeLogStart).Seconds(), op, name) 78 } 79 80 // tester executes cmdtest. 81 type tester struct { 82 race bool 83 listMode bool 84 rebuild bool 85 failed bool 86 keepGoing bool 87 compileOnly bool // just try to compile all tests, but no need to run 88 runRxStr string 89 runRx *regexp.Regexp 90 runRxWant bool // want runRx to match (true) or not match (false) 91 runNames []string // tests to run, exclusive with runRx; empty means all 92 banner string // prefix, or "" for none 93 lastHeading string // last dir heading printed 94 95 cgoEnabled bool 96 partial bool 97 haveTime bool // the 'time' binary is available 98 99 tests []distTest 100 timeoutScale int 101 102 worklist []*work 103 } 104 105 type work struct { 106 dt *distTest 107 cmd *exec.Cmd 108 start chan bool 109 out []byte 110 err error 111 end chan bool 112 } 113 114 // A distTest is a test run by dist test. 115 // Each test has a unique name and belongs to a group (heading) 116 type distTest struct { 117 name string // unique test name; may be filtered with -run flag 118 heading string // group section; this header is printed before the test is run. 119 fn func(*distTest) error 120 } 121 122 func (t *tester) run() { 123 timelog("start", "dist test") 124 125 var exeSuffix string 126 if goos == "windows" { 127 exeSuffix = ".exe" 128 } 129 if _, err := os.Stat(filepath.Join(gobin, "go"+exeSuffix)); err == nil { 130 os.Setenv("PATH", fmt.Sprintf("%s%c%s", gobin, os.PathListSeparator, os.Getenv("PATH"))) 131 } 132 133 slurp, err := exec.Command("go", "env", "CGO_ENABLED").Output() 134 if err != nil { 135 log.Fatalf("Error running go env CGO_ENABLED: %v", err) 136 } 137 t.cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(slurp))) 138 if flag.NArg() > 0 && t.runRxStr != "" { 139 log.Fatalf("the -run regular expression flag is mutually exclusive with test name arguments") 140 } 141 142 t.runNames = flag.Args() 143 144 if t.hasBash() { 145 if _, err := exec.LookPath("time"); err == nil { 146 t.haveTime = true 147 } 148 } 149 150 if t.rebuild { 151 t.out("Building packages and commands.") 152 // Force rebuild the whole toolchain. 153 goInstall("go", append([]string{"-a", "-i"}, toolchain...)...) 154 } 155 156 // Complete rebuild bootstrap, even with -no-rebuild. 157 // If everything is up-to-date, this is a no-op. 158 // If everything is not up-to-date, the first checkNotStale 159 // during the test process will kill the tests, so we might 160 // as well install the world. 161 // Now that for example "go install cmd/compile" does not 162 // also install runtime (you need "go install -i cmd/compile" 163 // for that), it's easy for previous workflows like 164 // "rebuild the compiler and then run run.bash" 165 // to break if we don't automatically refresh things here. 166 // Rebuilding is a shortened bootstrap. 167 // See cmdbootstrap for a description of the overall process. 168 // 169 // But don't do this if we're running in the Go build system, 170 // where cmd/dist is invoked many times. This just slows that 171 // down (Issue 24300). 172 if !t.listMode && os.Getenv("GO_BUILDER_NAME") == "" { 173 goInstall("go", append([]string{"-i"}, toolchain...)...) 174 goInstall("go", append([]string{"-i"}, toolchain...)...) 175 goInstall("go", "std", "cmd") 176 checkNotStale("go", "std", "cmd") 177 } 178 179 t.timeoutScale = 1 180 switch goarch { 181 case "arm": 182 t.timeoutScale = 2 183 case "mips", "mipsle", "mips64", "mips64le": 184 t.timeoutScale = 4 185 } 186 if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" { 187 t.timeoutScale, err = strconv.Atoi(s) 188 if err != nil { 189 log.Fatalf("failed to parse $GO_TEST_TIMEOUT_SCALE = %q as integer: %v", s, err) 190 } 191 } 192 193 if t.runRxStr != "" { 194 if t.runRxStr[0] == '!' { 195 t.runRxWant = false 196 t.runRxStr = t.runRxStr[1:] 197 } else { 198 t.runRxWant = true 199 } 200 t.runRx = regexp.MustCompile(t.runRxStr) 201 } 202 203 t.registerTests() 204 if t.listMode { 205 for _, tt := range t.tests { 206 fmt.Println(tt.name) 207 } 208 return 209 } 210 211 // We must unset GOROOT_FINAL before tests, because runtime/debug requires 212 // correct access to source code, so if we have GOROOT_FINAL in effect, 213 // at least runtime/debug test will fail. 214 // If GOROOT_FINAL was set before, then now all the commands will appear stale. 215 // Nothing we can do about that other than not checking them below. 216 // (We call checkNotStale but only with "std" not "cmd".) 217 os.Setenv("GOROOT_FINAL_OLD", os.Getenv("GOROOT_FINAL")) // for cmd/link test 218 os.Unsetenv("GOROOT_FINAL") 219 220 for _, name := range t.runNames { 221 if !t.isRegisteredTestName(name) { 222 log.Fatalf("unknown test %q", name) 223 } 224 } 225 226 for _, dt := range t.tests { 227 if !t.shouldRunTest(dt.name) { 228 t.partial = true 229 continue 230 } 231 dt := dt // dt used in background after this iteration 232 if err := dt.fn(&dt); err != nil { 233 t.runPending(&dt) // in case that hasn't been done yet 234 t.failed = true 235 if t.keepGoing { 236 log.Printf("Failed: %v", err) 237 } else { 238 log.Fatalf("Failed: %v", err) 239 } 240 } 241 } 242 t.runPending(nil) 243 timelog("end", "dist test") 244 if t.failed { 245 fmt.Println("\nFAILED") 246 os.Exit(1) 247 } else if incomplete[goos+"/"+goarch] { 248 fmt.Println("\nFAILED (incomplete port)") 249 os.Exit(1) 250 } else if t.partial { 251 fmt.Println("\nALL TESTS PASSED (some were excluded)") 252 } else { 253 fmt.Println("\nALL TESTS PASSED") 254 } 255 } 256 257 func (t *tester) shouldRunTest(name string) bool { 258 if t.runRx != nil { 259 return t.runRx.MatchString(name) == t.runRxWant 260 } 261 if len(t.runNames) == 0 { 262 return true 263 } 264 for _, runName := range t.runNames { 265 if runName == name { 266 return true 267 } 268 } 269 return false 270 } 271 272 // short returns a -short flag to pass to 'go test'. 273 // It returns "-short", 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 278 // and is not intended for use by users. 279 func short() string { 280 if v := os.Getenv("GO_TEST_SHORT"); v != "" { 281 short, err := strconv.ParseBool(v) 282 if err != nil { 283 log.Fatalf("invalid GO_TEST_SHORT %q: %v", v, err) 284 } 285 if !short { 286 return "-short=false" 287 } 288 } 289 return "-short" 290 } 291 292 // goTest returns the beginning of the go test command line. 293 // Callers should use goTest and then pass flags overriding these 294 // defaults as later arguments in the command line. 295 func (t *tester) goTest() []string { 296 return []string{ 297 "go", "test", short(), "-count=1", t.tags(), t.runFlag(""), 298 } 299 } 300 301 func (t *tester) tags() string { 302 if t.iOS() { 303 return "-tags=lldb" 304 } 305 return "-tags=" 306 } 307 308 func (t *tester) timeout(sec int) string { 309 return "-timeout=" + fmt.Sprint(time.Duration(sec)*time.Second*time.Duration(t.timeoutScale)) 310 } 311 312 // ranGoTest and stdMatches are state closed over by the stdlib 313 // testing func in registerStdTest below. The tests are run 314 // sequentially, so there's no need for locks. 315 // 316 // ranGoBench and benchMatches are the same, but are only used 317 // in -race mode. 318 var ( 319 ranGoTest bool 320 stdMatches []string 321 322 ranGoBench bool 323 benchMatches []string 324 ) 325 326 func (t *tester) registerStdTest(pkg string) { 327 testName := "go_test:" + pkg 328 if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant { 329 stdMatches = append(stdMatches, pkg) 330 } 331 t.tests = append(t.tests, distTest{ 332 name: testName, 333 heading: "Testing packages.", 334 fn: func(dt *distTest) error { 335 if ranGoTest { 336 return nil 337 } 338 t.runPending(dt) 339 timelog("start", dt.name) 340 defer timelog("end", dt.name) 341 ranGoTest = true 342 343 timeoutSec := 180 344 for _, pkg := range stdMatches { 345 if pkg == "cmd/go" { 346 timeoutSec *= 3 347 break 348 } 349 } 350 args := []string{ 351 "test", 352 short(), 353 t.tags(), 354 t.timeout(timeoutSec), 355 "-gcflags=all=" + gogcflags, 356 } 357 if t.race { 358 args = append(args, "-race") 359 } 360 if t.compileOnly { 361 args = append(args, "-run=^$") 362 } else if goos == "js" && goarch == "wasm" { 363 args = append(args, "-run=^Test") // exclude examples; Issue 25913 364 } 365 args = append(args, stdMatches...) 366 cmd := exec.Command("go", args...) 367 cmd.Stdout = os.Stdout 368 cmd.Stderr = os.Stderr 369 return cmd.Run() 370 }, 371 }) 372 } 373 374 func (t *tester) registerRaceBenchTest(pkg string) { 375 testName := "go_test_bench:" + pkg 376 if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant { 377 benchMatches = append(benchMatches, pkg) 378 } 379 t.tests = append(t.tests, distTest{ 380 name: testName, 381 heading: "Running benchmarks briefly.", 382 fn: func(dt *distTest) error { 383 if ranGoBench { 384 return nil 385 } 386 t.runPending(dt) 387 timelog("start", dt.name) 388 defer timelog("end", dt.name) 389 ranGoBench = true 390 args := []string{ 391 "test", 392 short(), 393 "-race", 394 t.timeout(1200), // longer timeout for race with benchmarks 395 "-run=^$", // nothing. only benchmarks. 396 "-benchtime=.1s", 397 "-cpu=4", 398 } 399 if !t.compileOnly { 400 args = append(args, "-bench=.*") 401 } 402 args = append(args, benchMatches...) 403 cmd := exec.Command("go", args...) 404 cmd.Stdout = os.Stdout 405 cmd.Stderr = os.Stderr 406 return cmd.Run() 407 }, 408 }) 409 } 410 411 // stdOutErrAreTerminals is defined in test_linux.go, to report 412 // whether stdout & stderr are terminals. 413 var stdOutErrAreTerminals func() bool 414 415 func (t *tester) registerTests() { 416 if strings.HasSuffix(os.Getenv("GO_BUILDER_NAME"), "-vetall") { 417 // Run vet over std and cmd and call it quits. 418 for k := range cgoEnabled { 419 osarch := k 420 t.tests = append(t.tests, distTest{ 421 name: "vet/" + osarch, 422 heading: "cmd/vet/all", 423 fn: func(dt *distTest) error { 424 t.addCmd(dt, "src/cmd/vet/all", "go", "run", "main.go", "-p="+osarch) 425 return nil 426 }, 427 }) 428 } 429 return 430 } 431 432 // Fast path to avoid the ~1 second of `go list std cmd` when 433 // the caller lists specific tests to run. (as the continuous 434 // build coordinator does). 435 if len(t.runNames) > 0 { 436 for _, name := range t.runNames { 437 if strings.HasPrefix(name, "go_test:") { 438 t.registerStdTest(strings.TrimPrefix(name, "go_test:")) 439 } 440 if strings.HasPrefix(name, "go_test_bench:") { 441 t.registerRaceBenchTest(strings.TrimPrefix(name, "go_test_bench:")) 442 } 443 } 444 } else { 445 // Use a format string to only list packages and commands that have tests. 446 const format = "{{if (or .TestGoFiles .XTestGoFiles)}}{{.ImportPath}}{{end}}" 447 cmd := exec.Command("go", "list", "-f", format) 448 if t.race { 449 cmd.Args = append(cmd.Args, "-tags=race") 450 } 451 cmd.Args = append(cmd.Args, "std") 452 if !t.race { 453 cmd.Args = append(cmd.Args, "cmd") 454 } 455 all, err := cmd.Output() 456 if err != nil { 457 log.Fatalf("Error running go list std cmd: %v, %s", err, all) 458 } 459 pkgs := strings.Fields(string(all)) 460 for _, pkg := range pkgs { 461 t.registerStdTest(pkg) 462 } 463 if t.race { 464 for _, pkg := range pkgs { 465 if t.packageHasBenchmarks(pkg) { 466 t.registerRaceBenchTest(pkg) 467 } 468 } 469 } 470 } 471 472 // Test the os/user package in the pure-Go mode too. 473 if !t.compileOnly { 474 t.tests = append(t.tests, distTest{ 475 name: "osusergo", 476 heading: "os/user with tag osusergo", 477 fn: func(dt *distTest) error { 478 t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-tags=osusergo", "os/user") 479 return nil 480 }, 481 }) 482 } 483 484 if t.race { 485 return 486 } 487 488 // Runtime CPU tests. 489 if !t.compileOnly && goos != "js" { // js can't handle -cpu != 1 490 testName := "runtime:cpu124" 491 t.tests = append(t.tests, distTest{ 492 name: testName, 493 heading: "GOMAXPROCS=2 runtime -cpu=1,2,4 -quick", 494 fn: func(dt *distTest) error { 495 cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(300), "runtime", "-cpu=1,2,4", "-quick") 496 // We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code, 497 // creation of first goroutines and first garbage collections in the parallel setting. 498 cmd.Env = append(os.Environ(), "GOMAXPROCS=2") 499 return nil 500 }, 501 }) 502 } 503 504 // This test needs its stdout/stderr to be terminals, so we don't run it from cmd/go's tests. 505 // See issue 18153. 506 if goos == "linux" { 507 t.tests = append(t.tests, distTest{ 508 name: "cmd_go_test_terminal", 509 heading: "cmd/go terminal test", 510 fn: func(dt *distTest) error { 511 t.runPending(dt) 512 timelog("start", dt.name) 513 defer timelog("end", dt.name) 514 if !stdOutErrAreTerminals() { 515 fmt.Println("skipping terminal test; stdout/stderr not terminals") 516 return nil 517 } 518 cmd := exec.Command("go", "test") 519 cmd.Dir = filepath.Join(os.Getenv("GOROOT"), "src/cmd/go/testdata/testterminal18153") 520 cmd.Stdout = os.Stdout 521 cmd.Stderr = os.Stderr 522 return cmd.Run() 523 }, 524 }) 525 } 526 527 // On the builders only, test that a moved GOROOT still works. 528 // Fails on iOS because CC_FOR_TARGET refers to clangwrap.sh 529 // in the unmoved GOROOT. 530 // Fails on Android and js/wasm with an exec format error. 531 // Fails on plan9 with "cannot find GOROOT" (issue #21016). 532 if os.Getenv("GO_BUILDER_NAME") != "" && goos != "android" && !t.iOS() && goos != "plan9" && goos != "js" { 533 t.tests = append(t.tests, distTest{ 534 name: "moved_goroot", 535 heading: "moved GOROOT", 536 fn: func(dt *distTest) error { 537 t.runPending(dt) 538 timelog("start", dt.name) 539 defer timelog("end", dt.name) 540 moved := goroot + "-moved" 541 if err := os.Rename(goroot, moved); err != nil { 542 if goos == "windows" { 543 // Fails on Windows (with "Access is denied") if a process 544 // or binary is in this directory. For instance, using all.bat 545 // when run from c:\workdir\go\src fails here 546 // if GO_BUILDER_NAME is set. Our builders invoke tests 547 // a different way which happens to work when sharding 548 // tests, but we should be tolerant of the non-sharded 549 // all.bat case. 550 log.Printf("skipping test on Windows") 551 return nil 552 } 553 return err 554 } 555 556 // Run `go test fmt` in the moved GOROOT. 557 cmd := exec.Command(filepath.Join(moved, "bin", "go"), "test", "fmt") 558 cmd.Stdout = os.Stdout 559 cmd.Stderr = os.Stderr 560 // Don't set GOROOT in the environment. 561 for _, e := range os.Environ() { 562 if !strings.HasPrefix(e, "GOROOT=") && !strings.HasPrefix(e, "GOCACHE=") { 563 cmd.Env = append(cmd.Env, e) 564 } 565 } 566 err := cmd.Run() 567 568 if rerr := os.Rename(moved, goroot); rerr != nil { 569 log.Fatalf("failed to restore GOROOT: %v", rerr) 570 } 571 return err 572 }, 573 }) 574 } 575 576 // Test that internal linking of standard packages does not 577 // require libgcc. This ensures that we can install a Go 578 // release on a system that does not have a C compiler 579 // installed and still build Go programs (that don't use cgo). 580 for _, pkg := range cgoPackages { 581 if !t.internalLink() { 582 break 583 } 584 585 // ARM libgcc may be Thumb, which internal linking does not support. 586 if goarch == "arm" { 587 break 588 } 589 590 pkg := pkg 591 var run string 592 if pkg == "net" { 593 run = "TestTCPStress" 594 } 595 t.tests = append(t.tests, distTest{ 596 name: "nolibgcc:" + pkg, 597 heading: "Testing without libgcc.", 598 fn: func(dt *distTest) error { 599 t.addCmd(dt, "src", t.goTest(), "-ldflags=-linkmode=internal -libgcc=none", pkg, t.runFlag(run)) 600 return nil 601 }, 602 }) 603 } 604 605 // Test internal linking of PIE binaries where it is supported. 606 if goos == "linux" && goarch == "amd64" && !isAlpineLinux() { 607 // Issue 18243: We don't have a way to set the default 608 // dynamic linker used in internal linking mode. So 609 // this test is skipped on Alpine. 610 t.tests = append(t.tests, distTest{ 611 name: "pie_internal", 612 heading: "internal linking of -buildmode=pie", 613 fn: func(dt *distTest) error { 614 t.addCmd(dt, "src", t.goTest(), "reflect", "-buildmode=pie", "-ldflags=-linkmode=internal", t.timeout(60)) 615 return nil 616 }, 617 }) 618 } 619 620 // sync tests 621 if goos != "js" { // js doesn't support -cpu=10 622 t.tests = append(t.tests, distTest{ 623 name: "sync_cpu", 624 heading: "sync -cpu=10", 625 fn: func(dt *distTest) error { 626 t.addCmd(dt, "src", t.goTest(), "sync", t.timeout(120), "-cpu=10", t.runFlag("")) 627 return nil 628 }, 629 }) 630 } 631 632 if t.raceDetectorSupported() { 633 t.tests = append(t.tests, distTest{ 634 name: "race", 635 heading: "Testing race detector", 636 fn: t.raceTest, 637 }) 638 } 639 640 if t.cgoEnabled && !t.iOS() { 641 // Disabled on iOS. golang.org/issue/15919 642 t.tests = append(t.tests, distTest{ 643 name: "cgo_stdio", 644 heading: "../misc/cgo/stdio", 645 fn: func(dt *distTest) error { 646 t.addCmd(dt, "misc/cgo/stdio", "go", "run", filepath.Join(os.Getenv("GOROOT"), "test/run.go"), "-", ".") 647 return nil 648 }, 649 }) 650 t.tests = append(t.tests, distTest{ 651 name: "cgo_life", 652 heading: "../misc/cgo/life", 653 fn: func(dt *distTest) error { 654 t.addCmd(dt, "misc/cgo/life", "go", "run", filepath.Join(os.Getenv("GOROOT"), "test/run.go"), "-", ".") 655 return nil 656 }, 657 }) 658 fortran := os.Getenv("FC") 659 if fortran == "" { 660 fortran, _ = exec.LookPath("gfortran") 661 } 662 if t.hasBash() && fortran != "" { 663 t.tests = append(t.tests, distTest{ 664 name: "cgo_fortran", 665 heading: "../misc/cgo/fortran", 666 fn: func(dt *distTest) error { 667 t.addCmd(dt, "misc/cgo/fortran", "./test.bash", fortran) 668 return nil 669 }, 670 }) 671 } 672 if t.hasSwig() && goos != "android" { 673 t.tests = append(t.tests, distTest{ 674 name: "swig_stdio", 675 heading: "../misc/swig/stdio", 676 fn: func(dt *distTest) error { 677 t.addCmd(dt, "misc/swig/stdio", t.goTest()) 678 return nil 679 }, 680 }) 681 if t.hasCxx() { 682 t.tests = append(t.tests, distTest{ 683 name: "swig_callback", 684 heading: "../misc/swig/callback", 685 fn: func(dt *distTest) error { 686 t.addCmd(dt, "misc/swig/callback", t.goTest()) 687 return nil 688 }, 689 }) 690 } 691 } 692 } 693 if t.cgoEnabled { 694 t.tests = append(t.tests, distTest{ 695 name: "cgo_test", 696 heading: "../misc/cgo/test", 697 fn: t.cgoTest, 698 }) 699 } 700 701 if t.hasBash() && t.cgoEnabled && goos != "android" && goos != "darwin" { 702 t.registerTest("testgodefs", "../misc/cgo/testgodefs", "./test.bash") 703 } 704 705 // Don't run these tests with $GO_GCFLAGS because most of them 706 // assume that they can run "go install" with no -gcflags and not 707 // recompile the entire standard library. If make.bash ran with 708 // special -gcflags, that's not true. 709 if t.cgoEnabled && gogcflags == "" { 710 if t.cgoTestSOSupported() { 711 t.tests = append(t.tests, distTest{ 712 name: "testso", 713 heading: "../misc/cgo/testso", 714 fn: func(dt *distTest) error { 715 return t.cgoTestSO(dt, "misc/cgo/testso") 716 }, 717 }) 718 t.tests = append(t.tests, distTest{ 719 name: "testsovar", 720 heading: "../misc/cgo/testsovar", 721 fn: func(dt *distTest) error { 722 return t.cgoTestSO(dt, "misc/cgo/testsovar") 723 }, 724 }) 725 } 726 if t.supportedBuildmode("c-archive") { 727 t.registerHostTest("testcarchive", "../misc/cgo/testcarchive", "misc/cgo/testcarchive", "carchive_test.go") 728 } 729 if t.supportedBuildmode("c-shared") { 730 t.registerHostTest("testcshared", "../misc/cgo/testcshared", "misc/cgo/testcshared", "cshared_test.go") 731 } 732 if t.supportedBuildmode("shared") { 733 t.registerTest("testshared", "../misc/cgo/testshared", t.goTest(), t.timeout(600)) 734 } 735 if t.supportedBuildmode("plugin") { 736 t.registerTest("testplugin", "../misc/cgo/testplugin", "./test.bash") 737 } 738 if gohostos == "linux" && goarch == "amd64" { 739 t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go") 740 } 741 if mSanSupported(goos, goarch) { 742 t.registerHostTest("testsanitizers/msan", "../misc/cgo/testsanitizers", "misc/cgo/testsanitizers", ".") 743 } 744 if t.hasBash() && goos != "android" && !t.iOS() && gohostos != "windows" { 745 t.registerHostTest("cgo_errors", "../misc/cgo/errors", "misc/cgo/errors", ".") 746 } 747 if gohostos == "linux" && t.extLink() { 748 t.registerTest("testsigfwd", "../misc/cgo/testsigfwd", "go", "run", "main.go") 749 } 750 } 751 752 // Doc tests only run on builders. 753 // They find problems approximately never. 754 if t.hasBash() && goos != "nacl" && goos != "js" && goos != "android" && !t.iOS() && os.Getenv("GO_BUILDER_NAME") != "" { 755 t.registerTest("doc_progs", "../doc/progs", "time", "go", "run", "run.go") 756 t.registerTest("wiki", "../doc/articles/wiki", "./test.bash") 757 t.registerTest("codewalk", "../doc/codewalk", "time", "./run") 758 } 759 760 if goos != "android" && !t.iOS() { 761 t.registerTest("bench_go1", "../test/bench/go1", t.goTest(), t.timeout(600)) 762 } 763 if goos != "android" && !t.iOS() { 764 // Only start multiple test dir shards on builders, 765 // where they get distributed to multiple machines. 766 // See issue 20141. 767 nShards := 1 768 if os.Getenv("GO_BUILDER_NAME") != "" { 769 nShards = 10 770 } 771 for shard := 0; shard < nShards; shard++ { 772 shard := shard 773 t.tests = append(t.tests, distTest{ 774 name: fmt.Sprintf("test:%d_%d", shard, nShards), 775 heading: "../test", 776 fn: func(dt *distTest) error { return t.testDirTest(dt, shard, nShards) }, 777 }) 778 } 779 } 780 if goos != "nacl" && goos != "android" && !t.iOS() && goos != "js" { 781 t.tests = append(t.tests, distTest{ 782 name: "api", 783 heading: "API check", 784 fn: func(dt *distTest) error { 785 if t.compileOnly { 786 t.addCmd(dt, "src", "go", "build", filepath.Join(goroot, "src/cmd/api/run.go")) 787 return nil 788 } 789 t.addCmd(dt, "src", "go", "run", filepath.Join(goroot, "src/cmd/api/run.go")) 790 return nil 791 }, 792 }) 793 } 794 } 795 796 // isRegisteredTestName reports whether a test named testName has already 797 // been registered. 798 func (t *tester) isRegisteredTestName(testName string) bool { 799 for _, tt := range t.tests { 800 if tt.name == testName { 801 return true 802 } 803 } 804 return false 805 } 806 807 func (t *tester) registerTest1(seq bool, name, dirBanner string, cmdline ...interface{}) { 808 bin, args := flattenCmdline(cmdline) 809 if bin == "time" && !t.haveTime { 810 bin, args = args[0], args[1:] 811 } 812 if t.isRegisteredTestName(name) { 813 panic("duplicate registered test name " + name) 814 } 815 t.tests = append(t.tests, distTest{ 816 name: name, 817 heading: dirBanner, 818 fn: func(dt *distTest) error { 819 if seq { 820 t.runPending(dt) 821 timelog("start", name) 822 defer timelog("end", name) 823 return t.dirCmd(filepath.Join(goroot, "src", dirBanner), bin, args).Run() 824 } 825 t.addCmd(dt, filepath.Join(goroot, "src", dirBanner), bin, args) 826 return nil 827 }, 828 }) 829 } 830 831 func (t *tester) registerTest(name, dirBanner string, cmdline ...interface{}) { 832 t.registerTest1(false, name, dirBanner, cmdline...) 833 } 834 835 func (t *tester) registerSeqTest(name, dirBanner string, cmdline ...interface{}) { 836 t.registerTest1(true, name, dirBanner, cmdline...) 837 } 838 839 func (t *tester) bgDirCmd(dir, bin string, args ...string) *exec.Cmd { 840 cmd := exec.Command(bin, args...) 841 if filepath.IsAbs(dir) { 842 cmd.Dir = dir 843 } else { 844 cmd.Dir = filepath.Join(goroot, dir) 845 } 846 return cmd 847 } 848 849 func (t *tester) dirCmd(dir string, cmdline ...interface{}) *exec.Cmd { 850 bin, args := flattenCmdline(cmdline) 851 cmd := t.bgDirCmd(dir, bin, args...) 852 cmd.Stdout = os.Stdout 853 cmd.Stderr = os.Stderr 854 if vflag > 1 { 855 errprintf("%s\n", strings.Join(cmd.Args, " ")) 856 } 857 return cmd 858 } 859 860 // flattenCmdline flattens a mixture of string and []string as single list 861 // and then interprets it as a command line: first element is binary, then args. 862 func flattenCmdline(cmdline []interface{}) (bin string, args []string) { 863 var list []string 864 for _, x := range cmdline { 865 switch x := x.(type) { 866 case string: 867 list = append(list, x) 868 case []string: 869 list = append(list, x...) 870 default: 871 panic("invalid addCmd argument type: " + reflect.TypeOf(x).String()) 872 } 873 } 874 875 // The go command is too picky about duplicated flags. 876 // Drop all but the last of the allowed duplicated flags. 877 drop := make([]bool, len(list)) 878 have := map[string]int{} 879 for i := 1; i < len(list); i++ { 880 j := strings.Index(list[i], "=") 881 if j < 0 { 882 continue 883 } 884 flag := list[i][:j] 885 switch flag { 886 case "-run", "-tags": 887 if have[flag] != 0 { 888 drop[have[flag]] = true 889 } 890 have[flag] = i 891 } 892 } 893 out := list[:0] 894 for i, x := range list { 895 if !drop[i] { 896 out = append(out, x) 897 } 898 } 899 list = out 900 901 return list[0], list[1:] 902 } 903 904 func (t *tester) addCmd(dt *distTest, dir string, cmdline ...interface{}) *exec.Cmd { 905 bin, args := flattenCmdline(cmdline) 906 w := &work{ 907 dt: dt, 908 cmd: t.bgDirCmd(dir, bin, args...), 909 } 910 t.worklist = append(t.worklist, w) 911 return w.cmd 912 } 913 914 func (t *tester) iOS() bool { 915 return goos == "darwin" && (goarch == "arm" || goarch == "arm64") 916 } 917 918 func (t *tester) out(v string) { 919 if t.banner == "" { 920 return 921 } 922 fmt.Println("\n" + t.banner + v) 923 } 924 925 func (t *tester) extLink() bool { 926 pair := gohostos + "-" + goarch 927 switch pair { 928 case "android-arm", 929 "darwin-386", "darwin-amd64", "darwin-arm", "darwin-arm64", 930 "dragonfly-amd64", 931 "freebsd-386", "freebsd-amd64", "freebsd-arm", 932 "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le", "linux-mips", "linux-mipsle", "linux-s390x", 933 "netbsd-386", "netbsd-amd64", 934 "openbsd-386", "openbsd-amd64", 935 "windows-386", "windows-amd64": 936 return true 937 } 938 return false 939 } 940 941 func (t *tester) internalLink() bool { 942 if gohostos == "dragonfly" { 943 // linkmode=internal fails on dragonfly since errno is a TLS relocation. 944 return false 945 } 946 if gohostarch == "ppc64le" { 947 // linkmode=internal fails on ppc64le because cmd/link doesn't 948 // handle the TOC correctly (issue 15409). 949 return false 950 } 951 if goos == "android" { 952 return false 953 } 954 if goos == "darwin" && (goarch == "arm" || goarch == "arm64") { 955 return false 956 } 957 // Internally linking cgo is incomplete on some architectures. 958 // https://golang.org/issue/10373 959 // https://golang.org/issue/14449 960 if goarch == "arm64" || goarch == "mips64" || goarch == "mips64le" || goarch == "mips" || goarch == "mipsle" { 961 return false 962 } 963 if isAlpineLinux() { 964 // Issue 18243. 965 return false 966 } 967 return true 968 } 969 970 func (t *tester) supportedBuildmode(mode string) bool { 971 pair := goos + "-" + goarch 972 switch mode { 973 case "c-archive": 974 if !t.extLink() { 975 return false 976 } 977 switch pair { 978 case "darwin-386", "darwin-amd64", "darwin-arm", "darwin-arm64", 979 "linux-amd64", "linux-386", "linux-ppc64le", "linux-s390x", 980 "freebsd-amd64", 981 "windows-amd64", "windows-386": 982 return true 983 } 984 return false 985 case "c-shared": 986 switch pair { 987 case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x", 988 "darwin-amd64", "darwin-386", 989 "freebsd-amd64", 990 "android-arm", "android-arm64", "android-386", 991 "windows-amd64", "windows-386": 992 return true 993 } 994 return false 995 case "shared": 996 switch pair { 997 case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x": 998 return true 999 } 1000 return false 1001 case "plugin": 1002 // linux-arm64 is missing because it causes the external linker 1003 // to crash, see https://golang.org/issue/17138 1004 switch pair { 1005 case "linux-386", "linux-amd64", "linux-arm", "linux-s390x", "linux-ppc64le": 1006 return true 1007 case "darwin-amd64": 1008 return true 1009 } 1010 return false 1011 case "pie": 1012 switch pair { 1013 case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x", 1014 "android-amd64", "android-arm", "android-arm64", "android-386": 1015 return true 1016 case "darwin-amd64": 1017 return true 1018 } 1019 return false 1020 1021 default: 1022 log.Fatalf("internal error: unknown buildmode %s", mode) 1023 return false 1024 } 1025 } 1026 1027 func (t *tester) registerHostTest(name, heading, dir, pkg string) { 1028 t.tests = append(t.tests, distTest{ 1029 name: name, 1030 heading: heading, 1031 fn: func(dt *distTest) error { 1032 t.runPending(dt) 1033 timelog("start", name) 1034 defer timelog("end", name) 1035 return t.runHostTest(dir, pkg) 1036 }, 1037 }) 1038 } 1039 1040 func (t *tester) runHostTest(dir, pkg string) error { 1041 defer os.Remove(filepath.Join(goroot, dir, "test.test")) 1042 cmd := t.dirCmd(dir, t.goTest(), "-c", "-o", "test.test", pkg) 1043 cmd.Env = append(os.Environ(), "GOARCH="+gohostarch, "GOOS="+gohostos) 1044 if err := cmd.Run(); err != nil { 1045 return err 1046 } 1047 return t.dirCmd(dir, "./test.test").Run() 1048 } 1049 1050 func (t *tester) cgoTest(dt *distTest) error { 1051 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=auto") 1052 1053 if t.internalLink() { 1054 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=internal", "-ldflags", "-linkmode=internal") 1055 } 1056 1057 pair := gohostos + "-" + goarch 1058 switch pair { 1059 case "darwin-386", "darwin-amd64", 1060 "openbsd-386", "openbsd-amd64", 1061 "windows-386", "windows-amd64": 1062 // test linkmode=external, but __thread not supported, so skip testtls. 1063 if !t.extLink() { 1064 break 1065 } 1066 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external") 1067 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s") 1068 case "android-arm", 1069 "dragonfly-amd64", 1070 "freebsd-386", "freebsd-amd64", "freebsd-arm", 1071 "linux-386", "linux-amd64", "linux-arm", "linux-ppc64le", "linux-s390x", 1072 "netbsd-386", "netbsd-amd64": 1073 1074 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external") 1075 // A -g argument in CGO_CFLAGS should not affect how the test runs. 1076 cmd.Env = append(os.Environ(), "CGO_CFLAGS=-g0") 1077 1078 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=auto") 1079 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=external") 1080 1081 switch pair { 1082 case "netbsd-386", "netbsd-amd64": 1083 // no static linking 1084 case "freebsd-arm": 1085 // -fPIC compiled tls code will use __tls_get_addr instead 1086 // of __aeabi_read_tp, however, on FreeBSD/ARM, __tls_get_addr 1087 // is implemented in rtld-elf, so -fPIC isn't compatible with 1088 // static linking on FreeBSD/ARM with clang. (cgo depends on 1089 // -fPIC fundamentally.) 1090 default: 1091 cmd := t.dirCmd("misc/cgo/test", 1092 compilerEnvLookup(defaultcc, goos, goarch), "-xc", "-o", "/dev/null", "-static", "-") 1093 cmd.Stdin = strings.NewReader("int main() {}") 1094 if err := cmd.Run(); err != nil { 1095 fmt.Println("No support for static linking found (lacks libc.a?), skip cgo static linking test.") 1096 } else { 1097 if goos != "android" { 1098 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", `-linkmode=external -extldflags "-static -pthread"`) 1099 } 1100 t.addCmd(dt, "misc/cgo/nocgo", t.goTest()) 1101 t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-ldflags", `-linkmode=external`) 1102 if goos != "android" { 1103 t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-ldflags", `-linkmode=external -extldflags "-static -pthread"`) 1104 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`) 1105 // -static in CGO_LDFLAGS triggers a different code path 1106 // than -static in -extldflags, so test both. 1107 // See issue #16651. 1108 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static") 1109 cmd.Env = append(os.Environ(), "CGO_LDFLAGS=-static -pthread") 1110 } 1111 } 1112 1113 if t.supportedBuildmode("pie") { 1114 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie") 1115 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-buildmode=pie") 1116 t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-buildmode=pie") 1117 } 1118 } 1119 } 1120 1121 return nil 1122 } 1123 1124 // run pending test commands, in parallel, emitting headers as appropriate. 1125 // When finished, emit header for nextTest, which is going to run after the 1126 // pending commands are done (and runPending returns). 1127 // A test should call runPending if it wants to make sure that it is not 1128 // running in parallel with earlier tests, or if it has some other reason 1129 // for needing the earlier tests to be done. 1130 func (t *tester) runPending(nextTest *distTest) { 1131 checkNotStale("go", "std") 1132 worklist := t.worklist 1133 t.worklist = nil 1134 for _, w := range worklist { 1135 w.start = make(chan bool) 1136 w.end = make(chan bool) 1137 go func(w *work) { 1138 if !<-w.start { 1139 timelog("skip", w.dt.name) 1140 w.out = []byte(fmt.Sprintf("skipped due to earlier error\n")) 1141 } else { 1142 timelog("start", w.dt.name) 1143 w.out, w.err = w.cmd.CombinedOutput() 1144 } 1145 timelog("end", w.dt.name) 1146 w.end <- true 1147 }(w) 1148 } 1149 1150 started := 0 1151 ended := 0 1152 var last *distTest 1153 for ended < len(worklist) { 1154 for started < len(worklist) && started-ended < maxbg { 1155 //println("start", started) 1156 w := worklist[started] 1157 started++ 1158 w.start <- !t.failed || t.keepGoing 1159 } 1160 w := worklist[ended] 1161 dt := w.dt 1162 if dt.heading != "" && t.lastHeading != dt.heading { 1163 t.lastHeading = dt.heading 1164 t.out(dt.heading) 1165 } 1166 if dt != last { 1167 // Assumes all the entries for a single dt are in one worklist. 1168 last = w.dt 1169 if vflag > 0 { 1170 fmt.Printf("# go tool dist test -run=^%s$\n", dt.name) 1171 } 1172 } 1173 if vflag > 1 { 1174 errprintf("%s\n", strings.Join(w.cmd.Args, " ")) 1175 } 1176 //println("wait", ended) 1177 ended++ 1178 <-w.end 1179 os.Stdout.Write(w.out) 1180 if w.err != nil { 1181 log.Printf("Failed: %v", w.err) 1182 t.failed = true 1183 } 1184 checkNotStale("go", "std") 1185 } 1186 if t.failed && !t.keepGoing { 1187 log.Fatal("FAILED") 1188 } 1189 1190 if dt := nextTest; dt != nil { 1191 if dt.heading != "" && t.lastHeading != dt.heading { 1192 t.lastHeading = dt.heading 1193 t.out(dt.heading) 1194 } 1195 if vflag > 0 { 1196 fmt.Printf("# go tool dist test -run=^%s$\n", dt.name) 1197 } 1198 } 1199 } 1200 1201 func (t *tester) cgoTestSOSupported() bool { 1202 if goos == "android" || t.iOS() { 1203 // No exec facility on Android or iOS. 1204 return false 1205 } 1206 if goarch == "ppc64" { 1207 // External linking not implemented on ppc64 (issue #8912). 1208 return false 1209 } 1210 if goarch == "mips64le" || goarch == "mips64" { 1211 // External linking not implemented on mips64. 1212 return false 1213 } 1214 return true 1215 } 1216 1217 func (t *tester) cgoTestSO(dt *distTest, testpath string) error { 1218 t.runPending(dt) 1219 1220 timelog("start", dt.name) 1221 defer timelog("end", dt.name) 1222 1223 dir := filepath.Join(goroot, testpath) 1224 1225 // build shared object 1226 output, err := exec.Command("go", "env", "CC").Output() 1227 if err != nil { 1228 return fmt.Errorf("Error running go env CC: %v", err) 1229 } 1230 cc := strings.TrimSuffix(string(output), "\n") 1231 if cc == "" { 1232 return errors.New("CC environment variable (go env CC) cannot be empty") 1233 } 1234 output, err = exec.Command("go", "env", "GOGCCFLAGS").Output() 1235 if err != nil { 1236 return fmt.Errorf("Error running go env GOGCCFLAGS: %v", err) 1237 } 1238 gogccflags := strings.Split(strings.TrimSuffix(string(output), "\n"), " ") 1239 1240 ext := "so" 1241 args := append(gogccflags, "-shared") 1242 switch goos { 1243 case "darwin": 1244 ext = "dylib" 1245 args = append(args, "-undefined", "suppress", "-flat_namespace") 1246 case "windows": 1247 ext = "dll" 1248 args = append(args, "-DEXPORT_DLL") 1249 } 1250 sofname := "libcgosotest." + ext 1251 args = append(args, "-o", sofname, "cgoso_c.c") 1252 1253 if err := t.dirCmd(dir, cc, args).Run(); err != nil { 1254 return err 1255 } 1256 defer os.Remove(filepath.Join(dir, sofname)) 1257 1258 if err := t.dirCmd(dir, "go", "build", "-o", "main.exe", "main.go").Run(); err != nil { 1259 return err 1260 } 1261 defer os.Remove(filepath.Join(dir, "main.exe")) 1262 1263 cmd := t.dirCmd(dir, "./main.exe") 1264 if goos != "windows" { 1265 s := "LD_LIBRARY_PATH" 1266 if goos == "darwin" { 1267 s = "DYLD_LIBRARY_PATH" 1268 } 1269 cmd.Env = append(os.Environ(), s+"=.") 1270 1271 // On FreeBSD 64-bit architectures, the 32-bit linker looks for 1272 // different environment variables. 1273 if goos == "freebsd" && gohostarch == "386" { 1274 cmd.Env = append(cmd.Env, "LD_32_LIBRARY_PATH=.") 1275 } 1276 } 1277 return cmd.Run() 1278 } 1279 1280 func (t *tester) hasBash() bool { 1281 switch gohostos { 1282 case "windows", "plan9": 1283 return false 1284 } 1285 return true 1286 } 1287 1288 func (t *tester) hasCxx() bool { 1289 cxx, _ := exec.LookPath(compilerEnvLookup(defaultcxx, goos, goarch)) 1290 return cxx != "" 1291 } 1292 1293 func (t *tester) hasSwig() bool { 1294 swig, err := exec.LookPath("swig") 1295 if err != nil { 1296 return false 1297 } 1298 1299 // Check that swig was installed with Go support by checking 1300 // that a go directory exists inside the swiglib directory. 1301 // See https://golang.org/issue/23469. 1302 output, err := exec.Command(swig, "-go", "-swiglib").Output() 1303 if err != nil { 1304 return false 1305 } 1306 swigDir := strings.TrimSpace(string(output)) 1307 1308 _, err = os.Stat(filepath.Join(swigDir, "go")) 1309 if err != nil { 1310 return false 1311 } 1312 1313 // Check that swig has a new enough version. 1314 // See https://golang.org/issue/22858. 1315 out, err := exec.Command(swig, "-version").CombinedOutput() 1316 if err != nil { 1317 return false 1318 } 1319 1320 re := regexp.MustCompile(`[vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)?`) 1321 matches := re.FindSubmatch(out) 1322 if matches == nil { 1323 // Can't find version number; hope for the best. 1324 return true 1325 } 1326 1327 major, err := strconv.Atoi(string(matches[1])) 1328 if err != nil { 1329 // Can't find version number; hope for the best. 1330 return true 1331 } 1332 if major < 3 { 1333 return false 1334 } 1335 if major > 3 { 1336 // 4.0 or later 1337 return true 1338 } 1339 1340 // We have SWIG version 3.x. 1341 if len(matches[2]) > 0 { 1342 minor, err := strconv.Atoi(string(matches[2][1:])) 1343 if err != nil { 1344 return true 1345 } 1346 if minor > 0 { 1347 // 3.1 or later 1348 return true 1349 } 1350 } 1351 1352 // We have SWIG version 3.0.x. 1353 if len(matches[3]) > 0 { 1354 patch, err := strconv.Atoi(string(matches[3][1:])) 1355 if err != nil { 1356 return true 1357 } 1358 if patch < 6 { 1359 // Before 3.0.6. 1360 return false 1361 } 1362 } 1363 1364 return true 1365 } 1366 1367 func (t *tester) raceDetectorSupported() bool { 1368 if gohostos != goos { 1369 return false 1370 } 1371 if !t.cgoEnabled { 1372 return false 1373 } 1374 if !raceDetectorSupported(goos, goarch) { 1375 return false 1376 } 1377 // The race detector doesn't work on Alpine Linux: 1378 // golang.org/issue/14481 1379 if isAlpineLinux() { 1380 return false 1381 } 1382 // NetBSD support is unfinished. 1383 // golang.org/issue/26403 1384 if goos == "netbsd" { 1385 return false 1386 } 1387 return true 1388 } 1389 1390 func isAlpineLinux() bool { 1391 if runtime.GOOS != "linux" { 1392 return false 1393 } 1394 fi, err := os.Lstat("/etc/alpine-release") 1395 return err == nil && fi.Mode().IsRegular() 1396 } 1397 1398 func (t *tester) runFlag(rx string) string { 1399 if t.compileOnly { 1400 return "-run=^$" 1401 } 1402 if rx == "" && goos == "js" && goarch == "wasm" { 1403 return "-run=^Test" // exclude examples; Issue 25913 1404 } 1405 return "-run=" + rx 1406 } 1407 1408 func (t *tester) raceTest(dt *distTest) error { 1409 t.addCmd(dt, "src", t.goTest(), "-race", "-i", "runtime/race", "flag", "os", "os/exec") 1410 t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("Output"), "runtime/race") 1411 t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace|TestTypeRace|TestFdRace|TestFdReadRace|TestFileCloseRace"), "flag", "net", "os", "os/exec", "encoding/gob") 1412 // We don't want the following line, because it 1413 // slows down all.bash (by 10 seconds on my laptop). 1414 // The race builder should catch any error here, but doesn't. 1415 // TODO(iant): Figure out how to catch this. 1416 // t.addCmd(dt, "src", t.goTest(), "-race", "-run=TestParallelTest", "cmd/go") 1417 if t.cgoEnabled { 1418 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-race") 1419 cmd.Env = append(os.Environ(), "GOTRACEBACK=2") 1420 } 1421 if t.extLink() { 1422 // Test with external linking; see issue 9133. 1423 t.addCmd(dt, "src", t.goTest(), "-race", "-ldflags=-linkmode=external", t.runFlag("TestParse|TestEcho|TestStdinCloseRace"), "flag", "os/exec") 1424 } 1425 return nil 1426 } 1427 1428 var runtest struct { 1429 sync.Once 1430 exe string 1431 err error 1432 } 1433 1434 func (t *tester) testDirTest(dt *distTest, shard, shards int) error { 1435 runtest.Do(func() { 1436 const exe = "runtest.exe" // named exe for Windows, but harmless elsewhere 1437 cmd := t.dirCmd("test", "go", "build", "-o", exe, "run.go") 1438 cmd.Env = append(os.Environ(), "GOOS="+gohostos, "GOARCH="+gohostarch) 1439 runtest.exe = filepath.Join(cmd.Dir, exe) 1440 if err := cmd.Run(); err != nil { 1441 runtest.err = err 1442 return 1443 } 1444 xatexit(func() { 1445 os.Remove(runtest.exe) 1446 }) 1447 }) 1448 if runtest.err != nil { 1449 return runtest.err 1450 } 1451 if t.compileOnly { 1452 return nil 1453 } 1454 t.addCmd(dt, "test", runtest.exe, 1455 fmt.Sprintf("--shard=%d", shard), 1456 fmt.Sprintf("--shards=%d", shards), 1457 ) 1458 return nil 1459 } 1460 1461 // cgoPackages is the standard packages that use cgo. 1462 var cgoPackages = []string{ 1463 "crypto/x509", 1464 "net", 1465 "os/user", 1466 } 1467 1468 var funcBenchmark = []byte("\nfunc Benchmark") 1469 1470 // packageHasBenchmarks reports whether pkg has benchmarks. 1471 // On any error, it conservatively returns true. 1472 // 1473 // This exists just to eliminate work on the builders, since compiling 1474 // a test in race mode just to discover it has no benchmarks costs a 1475 // second or two per package, and this function returns false for 1476 // about 100 packages. 1477 func (t *tester) packageHasBenchmarks(pkg string) bool { 1478 pkgDir := filepath.Join(goroot, "src", pkg) 1479 d, err := os.Open(pkgDir) 1480 if err != nil { 1481 return true // conservatively 1482 } 1483 defer d.Close() 1484 names, err := d.Readdirnames(-1) 1485 if err != nil { 1486 return true // conservatively 1487 } 1488 for _, name := range names { 1489 if !strings.HasSuffix(name, "_test.go") { 1490 continue 1491 } 1492 slurp, err := ioutil.ReadFile(filepath.Join(pkgDir, name)) 1493 if err != nil { 1494 return true // conservatively 1495 } 1496 if bytes.Contains(slurp, funcBenchmark) { 1497 return true 1498 } 1499 } 1500 return false 1501 } 1502 1503 // raceDetectorSupported is a copy of the function 1504 // cmd/internal/sys.RaceDetectorSupported, which can't be used here 1505 // because cmd/dist has to be buildable by Go 1.4. 1506 func raceDetectorSupported(goos, goarch string) bool { 1507 switch goos { 1508 case "linux": 1509 return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64" 1510 case "darwin", "freebsd", "netbsd", "windows": 1511 return goarch == "amd64" 1512 default: 1513 return false 1514 } 1515 } 1516 1517 // mSanSupported is a copy of the function cmd/internal/sys.MSanSupported, 1518 // which can't be used here because cmd/dist has to be buildable by Go 1.4. 1519 func mSanSupported(goos, goarch string) bool { 1520 switch goos { 1521 case "linux": 1522 return goarch == "amd64" || goarch == "arm64" 1523 default: 1524 return false 1525 } 1526 }