2016-03-01 15:57:46 -07:00
// Copyright 2015 The Go Authors. All rights reserved.
2015-03-02 18:07:11 -07:00
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"errors"
"flag"
"fmt"
2016-09-14 10:34:27 -06:00
"io/ioutil"
2015-03-02 18:07:11 -07:00
"log"
"os"
"os/exec"
"path/filepath"
2017-11-29 12:16:25 -07:00
"reflect"
2015-03-02 18:07:11 -07:00
"regexp"
2017-04-25 00:11:09 -06:00
"runtime"
2015-03-02 18:07:11 -07:00
"strconv"
"strings"
2015-12-21 18:42:40 -07:00
"sync"
2015-03-02 18:07:11 -07:00
"time"
)
func cmdtest ( ) {
cmd/go: switch to entirely content-based staleness determination
This CL changes the go command to base all its rebuilding decisions
on the content of the files being processed and not their file system
modification times. It also eliminates the special handling of release
toolchains, which were previously considered always up-to-date
because modification time order could not be trusted when unpacking
a pre-built release.
The go command previously tracked "build IDs" as a backup to
modification times, to catch changes not reflected in modification times.
For example, if you remove one .go file in a package with multiple .go
files, there is no modification time remaining in the system that indicates
that the installed package is out of date. The old build ID was the hash
of a list of file names and a few other factors, expected to change if
those factors changed.
This CL moves to using this kind of build ID as the only way to
detect staleness, making sure that the build ID hash includes all
possible factors that need to influence the rebuild decision.
One such factor is the compiler flags. As of this CL, if you run
go build -gcflags -N cmd/gofmt
you will get a gofmt where every package is built with -N,
regardless of what may or may not be installed already.
Another such factor is the linker flags. As of this CL, if you run
go install myprog
go install -ldflags=-s myprog
the second go install will now correctly build a new myprog with
the updated linker flags. (Previously the installed myprog appeared
up-to-date, because the ldflags were not included in the build ID.)
Because we have more precise information we can also validate whether
the target of a "go test -c" operation is already the right binary and
therefore can avoid a rebuild.
This CL sets us up for having a more general build artifact cache,
maybe even a step toward not having a pkg directory with .a files,
but this CL does not take that step. For now the result of go install
is the same as it ever was; we just do a better job of what needs to
be installed.
This CL does slow down builds a small amount by reading all the
dependent source files in full. (The go command already read the
beginning of every dependent source file to discover build tags
and imports.) On my MacBook Pro, before this CL all.bash takes
3m58s, while after this CL and a few optimizations stacked above it
all.bash takes 4m28s. Given that CL 73850 cut 1m43s off the all.bash
time earlier today, we can afford adding 30s back for now.
More optimizations are planned that should make the go command
more efficient than it was even before this CL.
Fixes #15799.
Fixes #18369.
Fixes #19340.
Fixes #21477.
Change-Id: I10d7ca0e31ca3f58aabb9b1f11e2e3d9d18f0bc9
Reviewed-on: https://go-review.googlesource.com/73212
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
2017-10-11 18:39:28 -06:00
gogcflags = os . Getenv ( "GO_GCFLAGS" )
2015-03-02 18:07:11 -07:00
var t tester
2015-12-20 12:29:20 -07:00
var noRebuild bool
2015-03-02 18:07:11 -07:00
flag . BoolVar ( & t . listMode , "list" , false , "list available tests" )
2015-12-20 12:29:20 -07:00
flag . BoolVar ( & t . rebuild , "rebuild" , false , "rebuild everything first" )
flag . BoolVar ( & noRebuild , "no-rebuild" , false , "overrides -rebuild (historical dreg)" )
2015-05-01 20:23:04 -06:00
flag . BoolVar ( & t . keepGoing , "k" , false , "keep going even when error occurred" )
2015-06-08 18:56:27 -06:00
flag . BoolVar ( & t . race , "race" , false , "run in race builder mode (different set of tests)" )
2016-05-04 10:08:27 -06:00
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." )
2015-03-02 18:07:11 -07:00
flag . StringVar ( & t . banner , "banner" , "##### " , "banner prefix; blank means no section banners" )
2015-05-14 14:03:02 -06:00
flag . StringVar ( & t . runRxStr , "run" , os . Getenv ( "GOTESTONLY" ) ,
"run only those tests matching the regular expression; empty means to run all. " +
"Special exception: if the string begins with '!', the match is inverted." )
2015-06-04 00:21:30 -06:00
xflagparse ( - 1 ) // any number of args
2015-12-20 12:29:20 -07:00
if noRebuild {
t . rebuild = false
}
2015-03-02 18:07:11 -07:00
t . run ( )
}
// tester executes cmdtest.
type tester struct {
2015-12-21 14:08:57 -07:00
race bool
listMode bool
rebuild bool
failed bool
keepGoing bool
2016-05-04 10:08:27 -06:00
compileOnly bool // just try to compile all tests, but no need to run
2015-12-21 14:08:57 -07:00
runRxStr string
runRx * regexp . Regexp
runRxWant bool // want runRx to match (true) or not match (false)
runNames [ ] string // tests to run, exclusive with runRx; empty means all
banner string // prefix, or "" for none
lastHeading string // last dir heading printed
2015-03-02 18:07:11 -07:00
cgoEnabled bool
partial bool
haveTime bool // the 'time' binary is available
tests [ ] distTest
timeoutScale int
2015-12-21 14:08:57 -07:00
worklist [ ] * work
}
type work struct {
dt * distTest
cmd * exec . Cmd
start chan bool
out [ ] byte
err error
end chan bool
2015-03-02 18:07:11 -07:00
}
// A distTest is a test run by dist test.
// Each test has a unique name and belongs to a group (heading)
type distTest struct {
name string // unique test name; may be filtered with -run flag
heading string // group section; this header is printed before the test is run.
2015-12-21 14:08:57 -07:00
fn func ( * distTest ) error
2015-03-02 18:07:11 -07:00
}
func ( t * tester ) run ( ) {
2017-10-27 11:07:38 -06:00
timelog ( "start" , "dist test" )
2017-09-19 03:18:09 -06:00
var exeSuffix string
if goos == "windows" {
exeSuffix = ".exe"
}
if _ , err := os . Stat ( filepath . Join ( gobin , "go" + exeSuffix ) ) ; err == nil {
os . Setenv ( "PATH" , fmt . Sprintf ( "%s%c%s" , gobin , os . PathListSeparator , os . Getenv ( "PATH" ) ) )
}
2015-03-02 18:07:11 -07:00
slurp , err := exec . Command ( "go" , "env" , "CGO_ENABLED" ) . Output ( )
if err != nil {
log . Fatalf ( "Error running go env CGO_ENABLED: %v" , err )
}
t . cgoEnabled , _ = strconv . ParseBool ( strings . TrimSpace ( string ( slurp ) ) )
2015-06-04 00:21:30 -06:00
if flag . NArg ( ) > 0 && t . runRxStr != "" {
log . Fatalf ( "the -run regular expression flag is mutually exclusive with test name arguments" )
}
2017-09-19 07:13:22 -06:00
2015-06-04 00:21:30 -06:00
t . runNames = flag . Args ( )
2015-03-02 18:07:11 -07:00
if t . hasBash ( ) {
if _ , err := exec . LookPath ( "time" ) ; err == nil {
t . haveTime = true
}
}
2015-12-20 12:29:20 -07:00
if t . rebuild {
2015-03-02 18:07:11 -07:00
t . out ( "Building packages and commands." )
cmd/go: do not install dependencies during "go install"
This CL makes "go install" behave the way many users expect:
install only the things named on the command line.
Future builds still run as fast, thanks to the new build cache (CL 75473).
To install dependencies as well (the old behavior), use "go install -i".
Actual definitions aside, what most users know and expect of "go install"
is that (1) it installs what you asked, and (2) it's fast, unlike "go build".
It was fast because it installed dependencies, but installing dependencies
confused users repeatedly (see for example #5065, #6424, #10998, #12329,
"go build" and "go test" so that they could be "fast" too, but that only
created new opportunities for confusion. We also had to add -installsuffix
and then -pkgdir, to allow "fast" even when dependencies could not be
installed in the usual place.
The recent introduction of precise content-based staleness logic means that
the go command detects the need for rebuilding packages more often than it
used to, with the consequence that "go install" rebuilds and reinstalls
dependencies more than it used to. This will create more new opportunities
for confusion and will certainly lead to more issues filed like the ones
listed above.
CL 75743 introduced a build cache, separate from the install locations.
That cache makes all operations equally incremental and fast, whether or
not the operation is "install" or "build", and whether or not "-i" is used.
Installing dependencies is no longer necessary for speed, it has confused
users in the past, and the more accurate rebuilds mean that it will confuse
users even more often in the future. This CL aims to end all that confusion
by not installing dependencies by default.
By analogy with "go build -i" and "go test -i", which still install
dependencies, this CL introduces "go install -i", which installs
dependencies in addition to the things named on the command line.
Fixes #5065.
Fixes #6424.
Fixes #10998.
Fixes #12329.
Fixes #18981.
Fixes #22469.
Another step toward #4719.
Change-Id: I3d7bc145c3a680e2f26416e182fa0dcf1e2a15e5
Reviewed-on: https://go-review.googlesource.com/75850
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
2017-11-02 23:24:19 -06:00
// Force rebuild the whole toolchain.
goInstall ( "go" , append ( [ ] string { "-a" , "-i" } , toolchain ... ) ... )
}
// Complete rebuild bootstrap, even with -no-rebuild.
// If everything is up-to-date, this is a no-op.
// If everything is not up-to-date, the first checkNotStale
// during the test process will kill the tests, so we might
// as well install the world.
// Now that for example "go install cmd/compile" does not
// also install runtime (you need "go install -i cmd/compile"
// for that), it's easy for previous workflows like
// "rebuild the compiler and then run run.bash"
// to break if we don't automatically refresh things here.
// Rebuilding is a shortened bootstrap.
// See cmdbootstrap for a description of the overall process.
if ! t . listMode {
goInstall ( "go" , append ( [ ] string { "-i" } , toolchain ... ) ... )
goInstall ( "go" , append ( [ ] string { "-i" } , toolchain ... ) ... )
2017-10-31 13:15:22 -06:00
goInstall ( "go" , "std" , "cmd" )
checkNotStale ( "go" , "std" , "cmd" )
2015-03-02 18:07:11 -07:00
}
t . timeoutScale = 1
2017-09-19 07:13:22 -06:00
switch goarch {
2016-12-02 16:30:09 -07:00
case "arm" :
2015-03-02 18:07:11 -07:00
t . timeoutScale = 2
2016-12-01 16:27:25 -07:00
case "mips" , "mipsle" , "mips64" , "mips64le" :
t . timeoutScale = 4
2015-03-02 18:07:11 -07:00
}
2015-04-23 00:16:31 -06:00
if s := os . Getenv ( "GO_TEST_TIMEOUT_SCALE" ) ; s != "" {
t . timeoutScale , err = strconv . Atoi ( s )
if err != nil {
log . Fatalf ( "failed to parse $GO_TEST_TIMEOUT_SCALE = %q as integer: %v" , s , err )
}
}
2015-03-02 18:07:11 -07:00
if t . runRxStr != "" {
2015-05-14 14:03:02 -06:00
if t . runRxStr [ 0 ] == '!' {
t . runRxWant = false
t . runRxStr = t . runRxStr [ 1 : ]
} else {
t . runRxWant = true
}
2015-03-02 18:07:11 -07:00
t . runRx = regexp . MustCompile ( t . runRxStr )
}
t . registerTests ( )
if t . listMode {
for _ , tt := range t . tests {
fmt . Println ( tt . name )
}
return
}
// we must unset GOROOT_FINAL before tests, because runtime/debug requires
// correct access to source code, so if we have GOROOT_FINAL in effect,
// at least runtime/debug test will fail.
os . Unsetenv ( "GOROOT_FINAL" )
2015-06-04 00:21:30 -06:00
for _ , name := range t . runNames {
if ! t . isRegisteredTestName ( name ) {
log . Fatalf ( "unknown test %q" , name )
}
}
2015-03-02 18:07:11 -07:00
for _ , dt := range t . tests {
2015-06-04 00:21:30 -06:00
if ! t . shouldRunTest ( dt . name ) {
2015-03-02 18:07:11 -07:00
t . partial = true
continue
}
2015-12-21 14:08:57 -07:00
dt := dt // dt used in background after this iteration
if err := dt . fn ( & dt ) ; err != nil {
2015-12-21 18:42:40 -07:00
t . runPending ( & dt ) // in case that hasn't been done yet
2015-12-21 14:08:57 -07:00
t . failed = true
2015-05-01 20:23:04 -06:00
if t . keepGoing {
log . Printf ( "Failed: %v" , err )
} else {
log . Fatalf ( "Failed: %v" , err )
}
2015-03-02 18:07:11 -07:00
}
}
2015-12-21 14:08:57 -07:00
t . runPending ( nil )
2017-10-27 11:07:38 -06:00
timelog ( "end" , "dist test" )
2015-12-21 14:08:57 -07:00
if t . failed {
2015-05-01 20:23:04 -06:00
fmt . Println ( "\nFAILED" )
os . Exit ( 1 )
} else if t . partial {
2015-03-02 18:07:11 -07:00
fmt . Println ( "\nALL TESTS PASSED (some were excluded)" )
} else {
fmt . Println ( "\nALL TESTS PASSED" )
}
}
2015-06-04 00:21:30 -06:00
func ( t * tester ) shouldRunTest ( name string ) bool {
if t . runRx != nil {
return t . runRx . MatchString ( name ) == t . runRxWant
}
if len ( t . runNames ) == 0 {
return true
}
for _ , runName := range t . runNames {
if runName == name {
return true
}
}
return false
}
2017-11-29 12:16:25 -07:00
// goTest returns the beginning of the go test command line.
// Callers should use goTest and then pass flags overriding these
// defaults as later arguments in the command line.
func ( t * tester ) goTest ( ) [ ] string {
return [ ] string {
"go" , "test" , "-short" , "-count=1" , t . tags ( ) , t . runFlag ( "" ) ,
}
}
2015-06-04 13:03:38 -06:00
func ( t * tester ) tags ( ) string {
if t . iOS ( ) {
return "-tags=lldb"
}
return "-tags="
}
2015-03-02 18:07:11 -07:00
func ( t * tester ) timeout ( sec int ) string {
return "-timeout=" + fmt . Sprint ( time . Duration ( sec ) * time . Second * time . Duration ( t . timeoutScale ) )
}
2015-05-27 17:33:03 -06:00
// ranGoTest and stdMatches are state closed over by the stdlib
// testing func in registerStdTest below. The tests are run
// sequentially, so there's no need for locks.
2015-06-08 18:56:27 -06:00
//
// ranGoBench and benchMatches are the same, but are only used
// in -race mode.
2015-05-27 17:33:03 -06:00
var (
ranGoTest bool
stdMatches [ ] string
2015-06-08 18:56:27 -06:00
ranGoBench bool
benchMatches [ ] string
2015-05-27 17:33:03 -06:00
)
func ( t * tester ) registerStdTest ( pkg string ) {
testName := "go_test:" + pkg
2017-02-21 18:00:10 -07:00
if t . runRx == nil || t . runRx . MatchString ( testName ) == t . runRxWant {
2015-05-27 17:33:03 -06:00
stdMatches = append ( stdMatches , pkg )
}
t . tests = append ( t . tests , distTest {
name : testName ,
heading : "Testing packages." ,
2015-12-21 14:08:57 -07:00
fn : func ( dt * distTest ) error {
2015-05-27 17:33:03 -06:00
if ranGoTest {
return nil
}
2015-12-21 14:08:57 -07:00
t . runPending ( dt )
2017-10-27 11:07:38 -06:00
timelog ( "start" , dt . name )
defer timelog ( "end" , dt . name )
2015-05-27 17:33:03 -06:00
ranGoTest = true
2015-06-08 18:56:27 -06:00
args := [ ] string {
2015-05-27 17:33:03 -06:00
"test" ,
"-short" ,
2015-06-04 13:03:38 -06:00
t . tags ( ) ,
2015-07-20 11:18:26 -06:00
t . timeout ( 180 ) ,
2017-11-08 08:58:58 -07:00
"-gcflags=all=" + gogcflags ,
2015-06-08 18:56:27 -06:00
}
if t . race {
args = append ( args , "-race" )
}
2016-05-04 10:08:27 -06:00
if t . compileOnly {
args = append ( args , "-run=^$" )
}
2015-06-08 18:56:27 -06:00
args = append ( args , stdMatches ... )
cmd := exec . Command ( "go" , args ... )
cmd . Stdout = os . Stdout
cmd . Stderr = os . Stderr
return cmd . Run ( )
} ,
} )
}
func ( t * tester ) registerRaceBenchTest ( pkg string ) {
testName := "go_test_bench:" + pkg
2017-02-21 18:00:10 -07:00
if t . runRx == nil || t . runRx . MatchString ( testName ) == t . runRxWant {
2015-06-08 18:56:27 -06:00
benchMatches = append ( benchMatches , pkg )
}
t . tests = append ( t . tests , distTest {
name : testName ,
heading : "Running benchmarks briefly." ,
2015-12-21 14:08:57 -07:00
fn : func ( dt * distTest ) error {
2015-06-08 18:56:27 -06:00
if ranGoBench {
return nil
}
2015-12-21 14:08:57 -07:00
t . runPending ( dt )
2017-10-27 11:07:38 -06:00
timelog ( "start" , dt . name )
defer timelog ( "end" , dt . name )
2015-06-08 18:56:27 -06:00
ranGoBench = true
args := [ ] string {
"test" ,
"-short" ,
"-race" ,
"-run=^$" , // nothing. only benchmarks.
"-benchtime=.1s" ,
"-cpu=4" ,
}
2016-05-04 10:08:27 -06:00
if ! t . compileOnly {
args = append ( args , "-bench=.*" )
}
2015-06-08 18:56:27 -06:00
args = append ( args , benchMatches ... )
cmd := exec . Command ( "go" , args ... )
2015-05-27 17:33:03 -06:00
cmd . Stdout = os . Stdout
cmd . Stderr = os . Stderr
return cmd . Run ( )
} ,
} )
}
2016-12-06 11:22:42 -07:00
// stdOutErrAreTerminals is defined in test_linux.go, to report
// whether stdout & stderr are terminals.
var stdOutErrAreTerminals func ( ) bool
2015-05-27 17:33:03 -06:00
func ( t * tester ) registerTests ( ) {
2016-09-10 19:53:30 -06:00
if strings . HasSuffix ( os . Getenv ( "GO_BUILDER_NAME" ) , "-vetall" ) {
// Run vet over std and cmd and call it quits.
2017-04-13 00:06:43 -06:00
for k := range cgoEnabled {
osarch := k
2017-02-28 11:12:32 -07:00
t . tests = append ( t . tests , distTest {
name : "vet/" + osarch ,
cmd/vet: tighten printf format error messages
Every time I see an error that begins `missing argument for Fprintf("%s")`
my mental type-checker goes off, since obviously "%s" is not a valid first
argument to Fprintf. Writing Printf("%s") to report an error in Printf("hello %s")
is almost as confusing.
This CL rewords the errors reported by vet's printf check to be more
consistent with each other, avoid placing context like "in printf call"
in the middle of the message, and to avoid the imprecisions above by
not quoting the format string at all.
Before:
bad.go:9: no formatting directive in Printf call
bad.go:10: missing argument for Printf("%s"): format reads arg 1, have only 0 args
bad.go:11: wrong number of args for format in Printf call: 1 needed but 2 args
bad.go:12: bad syntax for printf argument index: [1]
bad.go:13: index value [0] for Printf("%[0]s"); indexes start at 1
bad.go:14: missing argument for Printf("%[2]s"): format reads arg 2, have only 1 args
bad.go:15: bad syntax for printf argument index: [abc]
bad.go:16: unrecognized printf verb 'z'
bad.go:17: arg "hello" for * in printf format not of type int
bad.go:18: arg fmt.Sprint in printf call is a function value, not a function call
bad.go:19: arg fmt.Sprint in Print call is a function value, not a function call
bad.go:20: arg "world" for printf verb %d of wrong type: string
bad.go:21: missing argument for Printf("%q"): format reads arg 2, have only 1 args
bad.go:22: first argument to Print is os.Stderr
bad.go:23: Println call ends with newline
bad.go:32: arg r in Sprint call causes recursive call to String method
bad.go:34: arg r for printf causes recursive call to String method
After:
bad.go:9: Printf call has arguments but no formatting directives
bad.go:10: Printf format %s reads arg #1, but have only 0 args
bad.go:11: Printf call needs 1 args but has 2 args
bad.go:12: Printf format %[1 is missing closing ]
bad.go:13: Printf format has invalid argument index [0]
bad.go:14: Printf format has invalid argument index [2]
bad.go:15: Printf format has invalid argument index [abc]
bad.go:16: Printf format %.234z has unknown verb z
bad.go:17: Printf format %.*s uses non-int "hello" as argument of *
bad.go:18: Printf format %s arg fmt.Sprint is a func value, not called
bad.go:19: Print arg fmt.Sprint is a func value, not called
bad.go:20: Printf format %d has arg "world" of wrong type string
bad.go:21: Printf format %q reads arg #2, but have only 1 args
bad.go:22: Print does not take io.Writer but has first arg os.Stderr
bad.go:23: Println args end with redundant newline
bad.go:32: Sprint arg r causes recursive call to String method
bad.go:34: Sprintf format %s with arg r causes recursive String method call
Change-Id: I5719f0fb9f2cd84df8ad4c7754ab9b79c691b060
Reviewed-on: https://go-review.googlesource.com/74352
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2017-10-29 13:18:52 -06:00
heading : "cmd/vet/all" ,
2017-02-28 11:12:32 -07:00
fn : func ( dt * distTest ) error {
t . addCmd ( dt , "src/cmd/vet/all" , "go" , "run" , "main.go" , "-p=" + osarch )
return nil
} ,
} )
}
2016-09-10 19:53:30 -06:00
return
}
2015-05-27 17:33:03 -06:00
// Fast path to avoid the ~1 second of `go list std cmd` when
2015-06-04 00:21:30 -06:00
// the caller lists specific tests to run. (as the continuous
2015-05-27 17:33:03 -06:00
// build coordinator does).
2015-06-04 00:21:30 -06:00
if len ( t . runNames ) > 0 {
for _ , name := range t . runNames {
if strings . HasPrefix ( name , "go_test:" ) {
t . registerStdTest ( strings . TrimPrefix ( name , "go_test:" ) )
}
2015-06-08 18:56:27 -06:00
if strings . HasPrefix ( name , "go_test_bench:" ) {
t . registerRaceBenchTest ( strings . TrimPrefix ( name , "go_test_bench:" ) )
}
2015-06-04 00:21:30 -06:00
}
} else {
// Use a format string to only list packages and commands that have tests.
const format = "{{if (or .TestGoFiles .XTestGoFiles)}}{{.ImportPath}}{{end}}"
2016-01-18 20:42:40 -07:00
cmd := exec . Command ( "go" , "list" , "-f" , format )
if t . race {
2017-11-29 12:16:25 -07:00
cmd . Args = append ( cmd . Args , "-tags=race" )
2016-01-18 20:42:40 -07:00
}
cmd . Args = append ( cmd . Args , "std" )
2015-06-08 18:56:27 -06:00
if ! t . race {
cmd . Args = append ( cmd . Args , "cmd" )
}
2016-10-25 20:09:36 -06:00
all , err := cmd . Output ( )
2015-06-04 00:21:30 -06:00
if err != nil {
2015-06-05 09:11:34 -06:00
log . Fatalf ( "Error running go list std cmd: %v, %s" , err , all )
2015-06-04 00:21:30 -06:00
}
2015-06-08 18:56:27 -06:00
pkgs := strings . Fields ( string ( all ) )
for _ , pkg := range pkgs {
2015-05-27 17:33:03 -06:00
t . registerStdTest ( pkg )
2015-03-02 18:07:11 -07:00
}
2015-06-08 18:56:27 -06:00
if t . race {
for _ , pkg := range pkgs {
2016-09-14 10:34:27 -06:00
if t . packageHasBenchmarks ( pkg ) {
t . registerRaceBenchTest ( pkg )
}
2015-06-08 18:56:27 -06:00
}
}
}
if t . race {
return
2015-03-02 18:07:11 -07:00
}
// Runtime CPU tests.
2016-05-04 10:08:27 -06:00
if ! t . compileOnly {
testName := "runtime:cpu124"
t . tests = append ( t . tests , distTest {
name : testName ,
2017-10-27 11:30:09 -06:00
heading : "GOMAXPROCS=2 runtime -cpu=1,2,4 -quick" ,
2016-05-04 10:08:27 -06:00
fn : func ( dt * distTest ) error {
2017-11-29 12:16:25 -07:00
cmd := t . addCmd ( dt , "src" , t . goTest ( ) , t . timeout ( 300 ) , "runtime" , "-cpu=1,2,4" , "-quick" )
2016-05-04 10:08:27 -06:00
// We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
// creation of first goroutines and first garbage collections in the parallel setting.
2017-03-02 15:12:09 -07:00
cmd . Env = append ( os . Environ ( ) , "GOMAXPROCS=2" )
2016-05-04 10:08:27 -06:00
return nil
} ,
} )
}
2015-03-02 18:07:11 -07:00
2017-08-18 18:43:33 -06:00
// This test needs its stdout/stderr to be terminals, so we don't run it from cmd/go's tests.
// See issue 18153.
2017-09-19 07:13:22 -06:00
if goos == "linux" {
2017-08-18 18:43:33 -06:00
t . tests = append ( t . tests , distTest {
name : "cmd_go_test_terminal" ,
heading : "cmd/go terminal test" ,
fn : func ( dt * distTest ) error {
t . runPending ( dt )
2017-10-27 11:07:38 -06:00
timelog ( "start" , dt . name )
defer timelog ( "end" , dt . name )
2017-08-18 18:43:33 -06:00
if ! stdOutErrAreTerminals ( ) {
fmt . Println ( "skipping terminal test; stdout/stderr not terminals" )
return nil
}
cmd := exec . Command ( "go" , "test" )
cmd . Dir = filepath . Join ( os . Getenv ( "GOROOT" ) , "src/cmd/go/testdata/testterminal18153" )
cmd . Stdout = os . Stdout
cmd . Stderr = os . Stderr
return cmd . Run ( )
} ,
} )
}
2017-07-14 09:22:30 -06:00
// On the builders only, test that a moved GOROOT still works.
2017-07-15 07:33:24 -06:00
// Fails on iOS because CC_FOR_TARGET refers to clangwrap.sh
// in the unmoved GOROOT.
// Fails on Android with an exec format error.
// Fails on plan9 with "cannot find GOROOT" (issue #21016).
2017-09-19 07:13:22 -06:00
if os . Getenv ( "GO_BUILDER_NAME" ) != "" && goos != "android" && ! t . iOS ( ) && goos != "plan9" {
2017-07-14 09:22:30 -06:00
t . tests = append ( t . tests , distTest {
name : "moved_goroot" ,
heading : "moved GOROOT" ,
fn : func ( dt * distTest ) error {
t . runPending ( dt )
2017-10-27 11:07:38 -06:00
timelog ( "start" , dt . name )
defer timelog ( "end" , dt . name )
2017-09-19 07:13:22 -06:00
moved := goroot + "-moved"
if err := os . Rename ( goroot , moved ) ; err != nil {
if goos == "windows" {
2017-07-26 22:33:18 -06:00
// Fails on Windows (with "Access is denied") if a process
// or binary is in this directory. For instance, using all.bat
// when run from c:\workdir\go\src fails here
// if GO_BUILDER_NAME is set. Our builders invoke tests
// a different way which happens to work when sharding
// tests, but we should be tolerant of the non-sharded
// all.bat case.
log . Printf ( "skipping test on Windows" )
return nil
}
2017-07-14 09:22:30 -06:00
return err
}
// Run `go test fmt` in the moved GOROOT.
2017-10-31 19:50:48 -06:00
// Disable GOCACHE because it points back at the old GOROOT.
2017-07-14 09:22:30 -06:00
cmd := exec . Command ( filepath . Join ( moved , "bin" , "go" ) , "test" , "fmt" )
cmd . Stdout = os . Stdout
cmd . Stderr = os . Stderr
// Don't set GOROOT in the environment.
for _ , e := range os . Environ ( ) {
2017-10-31 19:50:48 -06:00
if ! strings . HasPrefix ( e , "GOROOT=" ) && ! strings . HasPrefix ( e , "GOCACHE=" ) {
2017-07-14 09:22:30 -06:00
cmd . Env = append ( cmd . Env , e )
}
}
2017-10-31 19:50:48 -06:00
cmd . Env = append ( cmd . Env , "GOCACHE=off" )
2017-07-14 09:22:30 -06:00
err := cmd . Run ( )
2017-09-19 07:13:22 -06:00
if rerr := os . Rename ( moved , goroot ) ; rerr != nil {
2017-07-14 09:22:30 -06:00
log . Fatalf ( "failed to restore GOROOT: %v" , rerr )
}
return err
} ,
} )
}
2015-11-16 19:11:35 -07:00
// Test that internal linking of standard packages does not
2016-03-01 16:21:55 -07:00
// require libgcc. This ensures that we can install a Go
2015-11-16 19:11:35 -07:00
// release on a system that does not have a C compiler
// installed and still build Go programs (that don't use cgo).
for _ , pkg := range cgoPackages {
2016-09-16 16:25:52 -06:00
if ! t . internalLink ( ) {
2015-11-16 19:11:35 -07:00
break
}
2015-11-18 10:28:24 -07:00
// ARM libgcc may be Thumb, which internal linking does not support.
2017-09-19 07:13:22 -06:00
if goarch == "arm" {
2015-11-18 10:28:24 -07:00
break
}
2015-11-16 19:11:35 -07:00
pkg := pkg
2015-12-21 11:49:12 -07:00
var run string
if pkg == "net" {
run = "TestTCPStress"
}
2015-11-16 19:11:35 -07:00
t . tests = append ( t . tests , distTest {
name : "nolibgcc:" + pkg ,
heading : "Testing without libgcc." ,
2015-12-21 14:08:57 -07:00
fn : func ( dt * distTest ) error {
2017-11-29 12:16:25 -07:00
t . addCmd ( dt , "src" , t . goTest ( ) , "-ldflags=-linkmode=internal -libgcc=none" , pkg , t . runFlag ( run ) )
2015-12-21 14:08:57 -07:00
return nil
2015-11-16 19:11:35 -07:00
} ,
} )
}
2016-09-06 07:16:48 -06:00
// Test internal linking of PIE binaries where it is supported.
2017-09-19 07:13:22 -06:00
if goos == "linux" && goarch == "amd64" && ! isAlpineLinux ( ) {
2017-04-25 00:11:09 -06:00
// Issue 18243: We don't have a way to set the default
// dynamic linker used in internal linking mode. So
// this test is skipped on Alpine.
2016-09-06 07:16:48 -06:00
t . tests = append ( t . tests , distTest {
name : "pie_internal" ,
heading : "internal linking of -buildmode=pie" ,
fn : func ( dt * distTest ) error {
2017-11-29 12:16:25 -07:00
t . addCmd ( dt , "src" , t . goTest ( ) , "reflect" , "-buildmode=pie" , "-ldflags=-linkmode=internal" , t . timeout ( 60 ) )
2016-09-06 07:16:48 -06:00
return nil
} ,
} )
}
2015-03-02 18:07:11 -07:00
// sync tests
t . tests = append ( t . tests , distTest {
name : "sync_cpu" ,
heading : "sync -cpu=10" ,
2015-12-21 14:08:57 -07:00
fn : func ( dt * distTest ) error {
2017-11-29 12:16:25 -07:00
t . addCmd ( dt , "src" , t . goTest ( ) , "sync" , t . timeout ( 120 ) , "-cpu=10" , t . runFlag ( "" ) )
2015-12-21 14:08:57 -07:00
return nil
2015-03-02 18:07:11 -07:00
} ,
} )
2017-08-18 18:43:33 -06:00
if t . raceDetectorSupported ( ) {
t . tests = append ( t . tests , distTest {
name : "race" ,
heading : "Testing race detector" ,
fn : t . raceTest ,
} )
}
2016-06-01 12:58:02 -06:00
if t . cgoEnabled && ! t . iOS ( ) {
// Disabled on iOS. golang.org/issue/15919
2015-03-02 18:07:11 -07:00
t . tests = append ( t . tests , distTest {
name : "cgo_stdio" ,
heading : "../misc/cgo/stdio" ,
2015-12-21 14:08:57 -07:00
fn : func ( dt * distTest ) error {
t . addCmd ( dt , "misc/cgo/stdio" , "go" , "run" , filepath . Join ( os . Getenv ( "GOROOT" ) , "test/run.go" ) , "-" , "." )
return nil
2015-03-02 18:07:11 -07:00
} ,
} )
t . tests = append ( t . tests , distTest {
name : "cgo_life" ,
heading : "../misc/cgo/life" ,
2015-12-21 14:08:57 -07:00
fn : func ( dt * distTest ) error {
t . addCmd ( dt , "misc/cgo/life" , "go" , "run" , filepath . Join ( os . Getenv ( "GOROOT" ) , "test/run.go" ) , "-" , "." )
return nil
2015-03-02 18:07:11 -07:00
} ,
} )
2016-02-18 03:49:03 -07:00
fortran := os . Getenv ( "FC" )
if fortran == "" {
fortran , _ = exec . LookPath ( "gfortran" )
}
2016-05-03 03:10:26 -06:00
if t . hasBash ( ) && fortran != "" {
2016-02-18 03:49:03 -07:00
t . tests = append ( t . tests , distTest {
name : "cgo_fortran" ,
heading : "../misc/cgo/fortran" ,
fn : func ( dt * distTest ) error {
2016-02-25 00:09:45 -07:00
t . addCmd ( dt , "misc/cgo/fortran" , "./test.bash" , fortran )
2016-02-18 03:49:03 -07:00
return nil
} ,
} )
}
2017-12-06 19:09:11 -07:00
if t . hasSwig ( ) && goos != "android" {
2017-11-15 19:14:21 -07:00
t . tests = append ( t . tests , distTest {
name : "swig_stdio" ,
heading : "../misc/swig/stdio" ,
fn : func ( dt * distTest ) error {
2017-11-29 12:16:25 -07:00
t . addCmd ( dt , "misc/swig/stdio" , t . goTest ( ) )
2017-11-15 19:14:21 -07:00
return nil
} ,
} )
if cxx , _ := exec . LookPath ( compilerEnvLookup ( defaultcxx , goos , goarch ) ) ; cxx != "" {
t . tests = append ( t . tests , distTest {
name : "swig_callback" ,
heading : "../misc/swig/callback" ,
fn : func ( dt * distTest ) error {
2017-11-29 12:16:25 -07:00
t . addCmd ( dt , "misc/swig/callback" , t . goTest ( ) )
2017-11-15 19:14:21 -07:00
return nil
} ,
} )
}
}
2015-03-19 11:15:56 -06:00
}
2016-06-01 14:51:30 -06:00
if t . cgoEnabled {
2015-03-02 18:07:11 -07:00
t . tests = append ( t . tests , distTest {
name : "cgo_test" ,
heading : "../misc/cgo/test" ,
fn : t . cgoTest ,
} )
}
2017-09-19 07:13:22 -06:00
if t . hasBash ( ) && t . cgoEnabled && goos != "android" && goos != "darwin" {
2015-03-02 18:07:11 -07:00
t . registerTest ( "testgodefs" , "../misc/cgo/testgodefs" , "./test.bash" )
}
2017-10-30 13:28:11 -06:00
// Don't run these tests with $GO_GCFLAGS because most of them
// assume that they can run "go install" with no -gcflags and not
// recompile the entire standard library. If make.bash ran with
// special -gcflags, that's not true.
if t . cgoEnabled && gogcflags == "" {
2015-06-01 21:46:28 -06:00
if t . cgoTestSOSupported ( ) {
2015-03-02 18:07:11 -07:00
t . tests = append ( t . tests , distTest {
name : "testso" ,
heading : "../misc/cgo/testso" ,
2015-12-21 14:08:57 -07:00
fn : func ( dt * distTest ) error {
return t . cgoTestSO ( dt , "misc/cgo/testso" )
2015-06-15 23:36:06 -06:00
} ,
2015-03-02 18:07:11 -07:00
} )
2015-07-27 11:30:26 -06:00
t . tests = append ( t . tests , distTest {
name : "testsovar" ,
heading : "../misc/cgo/testsovar" ,
2015-12-21 14:08:57 -07:00
fn : func ( dt * distTest ) error {
return t . cgoTestSO ( dt , "misc/cgo/testsovar" )
2015-07-27 11:30:26 -06:00
} ,
} )
2015-03-02 18:07:11 -07:00
}
2016-03-24 14:47:02 -06:00
if t . supportedBuildmode ( "c-archive" ) {
2016-08-30 19:11:10 -06:00
t . registerHostTest ( "testcarchive" , "../misc/cgo/testcarchive" , "misc/cgo/testcarchive" , "carchive_test.go" )
2015-04-13 09:31:14 -06:00
}
2015-04-29 18:30:56 -06:00
if t . supportedBuildmode ( "c-shared" ) {
2016-11-27 17:05:01 -07:00
t . registerHostTest ( "testcshared" , "../misc/cgo/testcshared" , "misc/cgo/testcshared" , "cshared_test.go" )
2015-04-17 12:50:07 -06:00
}
2015-04-29 18:30:56 -06:00
if t . supportedBuildmode ( "shared" ) {
2017-11-29 12:16:25 -07:00
t . registerTest ( "testshared" , "../misc/cgo/testshared" , t . goTest ( ) )
2015-04-26 21:00:48 -06:00
}
2016-08-26 07:04:27 -06:00
if t . supportedBuildmode ( "plugin" ) {
t . registerTest ( "testplugin" , "../misc/cgo/testplugin" , "./test.bash" )
}
2017-09-19 07:13:22 -06:00
if gohostos == "linux" && goarch == "amd64" {
2015-03-03 16:50:32 -07:00
t . registerTest ( "testasan" , "../misc/cgo/testasan" , "go" , "run" , "main.go" )
}
2017-09-19 07:13:22 -06:00
if goos == "linux" && goarch == "amd64" {
2017-08-01 17:30:57 -06:00
t . registerHostTest ( "testsanitizers/msan" , "../misc/cgo/testsanitizers" , "misc/cgo/testsanitizers" , "." )
2015-09-29 22:24:13 -06:00
}
2017-09-19 07:13:22 -06:00
if t . hasBash ( ) && goos != "android" && ! t . iOS ( ) && gohostos != "windows" {
2017-09-12 16:28:02 -06:00
t . registerHostTest ( "cgo_errors" , "../misc/cgo/errors" , "misc/cgo/errors" , "." )
2015-03-03 16:50:32 -07:00
}
2017-09-19 07:13:22 -06:00
if gohostos == "linux" && t . extLink ( ) {
runtime: signal forwarding
Forward signals to signal handlers installed before Go installs its own,
under certain circumstances. In particular, as iant@ suggests, signals are
forwarded iff:
(1) a non-SIG_DFL signal handler existed before Go, and
(2) signal is synchronous (i.e., one of SIGSEGV, SIGBUS, SIGFPE), and
(3a) signal occured on a non-Go thread, or
(3b) signal occurred on a Go thread but in CGo code.
Supported only on Linux, for now.
Change-Id: I403219ee47b26cf65da819fb86cf1ec04d3e25f5
Reviewed-on: https://go-review.googlesource.com/8712
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2015-04-09 12:12:12 -06:00
t . registerTest ( "testsigfwd" , "../misc/cgo/testsigfwd" , "go" , "run" , "main.go" )
}
2015-03-02 18:07:11 -07:00
}
2015-12-21 14:15:36 -07:00
2016-01-06 10:29:10 -07:00
// Doc tests only run on builders.
2015-12-21 14:15:36 -07:00
// They find problems approximately never.
2017-09-19 07:13:22 -06:00
if t . hasBash ( ) && goos != "nacl" && goos != "android" && ! t . iOS ( ) && os . Getenv ( "GO_BUILDER_NAME" ) != "" {
2015-04-02 09:53:27 -06:00
t . registerTest ( "doc_progs" , "../doc/progs" , "time" , "go" , "run" , "run.go" )
2015-03-02 18:07:11 -07:00
t . registerTest ( "wiki" , "../doc/articles/wiki" , "./test.bash" )
t . registerTest ( "codewalk" , "../doc/codewalk" , "time" , "./run" )
}
2015-12-21 14:15:36 -07:00
2017-09-19 07:13:22 -06:00
if goos != "android" && ! t . iOS ( ) {
2017-11-29 12:16:25 -07:00
t . registerTest ( "bench_go1" , "../test/bench/go1" , t . goTest ( ) , t . timeout ( 600 ) )
2015-03-02 18:07:11 -07:00
}
2017-09-19 07:13:22 -06:00
if goos != "android" && ! t . iOS ( ) {
2017-05-02 06:35:55 -06:00
// Only start multiple test dir shards on builders,
// where they get distributed to multiple machines.
// See issue 20141.
nShards := 1
if os . Getenv ( "GO_BUILDER_NAME" ) != "" {
nShards = 10
}
2015-06-04 00:21:30 -06:00
for shard := 0 ; shard < nShards ; shard ++ {
shard := shard
t . tests = append ( t . tests , distTest {
name : fmt . Sprintf ( "test:%d_%d" , shard , nShards ) ,
heading : "../test" ,
2015-12-21 14:08:57 -07:00
fn : func ( dt * distTest ) error { return t . testDirTest ( dt , shard , nShards ) } ,
2015-06-04 00:21:30 -06:00
} )
}
2015-03-02 18:07:11 -07:00
}
2017-09-19 07:13:22 -06:00
if goos != "nacl" && goos != "android" && ! t . iOS ( ) {
2015-03-02 18:07:11 -07:00
t . tests = append ( t . tests , distTest {
name : "api" ,
heading : "API check" ,
2015-12-21 14:08:57 -07:00
fn : func ( dt * distTest ) error {
2016-05-04 10:08:27 -06:00
if t . compileOnly {
2017-09-19 07:13:22 -06:00
t . addCmd ( dt , "src" , "go" , "build" , filepath . Join ( goroot , "src/cmd/api/run.go" ) )
2016-05-04 10:08:27 -06:00
return nil
}
2017-09-19 07:13:22 -06:00
t . addCmd ( dt , "src" , "go" , "run" , filepath . Join ( goroot , "src/cmd/api/run.go" ) )
2015-12-21 14:08:57 -07:00
return nil
2015-03-02 18:07:11 -07:00
} ,
} )
}
2015-05-27 17:33:03 -06:00
}
// isRegisteredTestName reports whether a test named testName has already
// been registered.
func ( t * tester ) isRegisteredTestName ( testName string ) bool {
for _ , tt := range t . tests {
if tt . name == testName {
return true
}
}
return false
2015-03-02 18:07:11 -07:00
}
2017-11-29 12:16:25 -07:00
func ( t * tester ) registerTest1 ( seq bool , name , dirBanner string , cmdline ... interface { } ) {
bin , args := flattenCmdline ( cmdline )
2015-03-02 18:07:11 -07:00
if bin == "time" && ! t . haveTime {
bin , args = args [ 0 ] , args [ 1 : ]
}
2015-06-04 00:21:30 -06:00
if t . isRegisteredTestName ( name ) {
panic ( "duplicate registered test name " + name )
}
2015-03-02 18:07:11 -07:00
t . tests = append ( t . tests , distTest {
name : name ,
heading : dirBanner ,
2015-12-21 14:08:57 -07:00
fn : func ( dt * distTest ) error {
if seq {
t . runPending ( dt )
2017-10-27 11:07:38 -06:00
timelog ( "start" , name )
defer timelog ( "end" , name )
2017-11-29 12:16:25 -07:00
return t . dirCmd ( filepath . Join ( goroot , "src" , dirBanner ) , bin , args ) . Run ( )
2015-12-21 14:08:57 -07:00
}
2017-11-29 12:16:25 -07:00
t . addCmd ( dt , filepath . Join ( goroot , "src" , dirBanner ) , bin , args )
2015-12-21 14:08:57 -07:00
return nil
2015-03-02 18:07:11 -07:00
} ,
} )
}
2017-11-29 12:16:25 -07:00
func ( t * tester ) registerTest ( name , dirBanner string , cmdline ... interface { } ) {
t . registerTest1 ( false , name , dirBanner , cmdline ... )
2015-12-21 14:08:57 -07:00
}
2017-11-29 12:16:25 -07:00
func ( t * tester ) registerSeqTest ( name , dirBanner string , cmdline ... interface { } ) {
t . registerTest1 ( true , name , dirBanner , cmdline ... )
2015-12-21 14:08:57 -07:00
}
func ( t * tester ) bgDirCmd ( dir , bin string , args ... string ) * exec . Cmd {
2015-03-02 18:07:11 -07:00
cmd := exec . Command ( bin , args ... )
if filepath . IsAbs ( dir ) {
cmd . Dir = dir
} else {
2017-09-19 07:13:22 -06:00
cmd . Dir = filepath . Join ( goroot , dir )
2015-03-02 18:07:11 -07:00
}
2015-12-21 14:08:57 -07:00
return cmd
}
2017-11-29 12:16:25 -07:00
func ( t * tester ) dirCmd ( dir string , cmdline ... interface { } ) * exec . Cmd {
bin , args := flattenCmdline ( cmdline )
2015-12-21 14:08:57 -07:00
cmd := t . bgDirCmd ( dir , bin , args ... )
2015-03-02 18:07:11 -07:00
cmd . Stdout = os . Stdout
cmd . Stderr = os . Stderr
2015-07-22 01:23:21 -06:00
if vflag > 1 {
errprintf ( "%s\n" , strings . Join ( cmd . Args , " " ) )
}
2015-03-02 18:07:11 -07:00
return cmd
}
2017-11-29 12:16:25 -07:00
// flattenCmdline flattens a mixture of string and []string as single list
// and then interprets it as a command line: first element is binary, then args.
func flattenCmdline ( cmdline [ ] interface { } ) ( bin string , args [ ] string ) {
var list [ ] string
for _ , x := range cmdline {
switch x := x . ( type ) {
case string :
list = append ( list , x )
case [ ] string :
list = append ( list , x ... )
default :
panic ( "invalid addCmd argument type: " + reflect . TypeOf ( x ) . String ( ) )
}
}
// The go command is too picky about duplicated flags.
// Drop all but the last of the allowed duplicated flags.
drop := make ( [ ] bool , len ( list ) )
have := map [ string ] int { }
for i := 1 ; i < len ( list ) ; i ++ {
j := strings . Index ( list [ i ] , "=" )
if j < 0 {
continue
}
flag := list [ i ] [ : j ]
switch flag {
case "-run" , "-tags" :
if have [ flag ] != 0 {
drop [ have [ flag ] ] = true
}
have [ flag ] = i
}
}
out := list [ : 0 ]
for i , x := range list {
if ! drop [ i ] {
out = append ( out , x )
}
}
list = out
return list [ 0 ] , list [ 1 : ]
}
func ( t * tester ) addCmd ( dt * distTest , dir string , cmdline ... interface { } ) * exec . Cmd {
bin , args := flattenCmdline ( cmdline )
2015-12-21 14:08:57 -07:00
w := & work {
dt : dt ,
cmd : t . bgDirCmd ( dir , bin , args ... ) ,
}
t . worklist = append ( t . worklist , w )
return w . cmd
}
2015-04-30 14:38:10 -06:00
func ( t * tester ) iOS ( ) bool {
2017-09-19 07:13:22 -06:00
return goos == "darwin" && ( goarch == "arm" || goarch == "arm64" )
2015-04-30 14:38:10 -06:00
}
2015-03-02 18:07:11 -07:00
func ( t * tester ) out ( v string ) {
if t . banner == "" {
return
}
fmt . Println ( "\n" + t . banner + v )
}
func ( t * tester ) extLink ( ) bool {
2017-09-19 07:13:22 -06:00
pair := gohostos + "-" + goarch
2015-03-02 18:07:11 -07:00
switch pair {
case "android-arm" ,
2015-04-20 07:33:25 -06:00
"darwin-arm" , "darwin-arm64" ,
2017-11-23 02:16:02 -07:00
"dragonfly-amd64" ,
2015-03-02 18:07:11 -07:00
"freebsd-386" , "freebsd-amd64" , "freebsd-arm" ,
2017-01-03 10:41:18 -07:00
"linux-386" , "linux-amd64" , "linux-arm" , "linux-arm64" , "linux-ppc64le" , "linux-mips64" , "linux-mips64le" , "linux-mips" , "linux-mipsle" , "linux-s390x" ,
2015-03-02 18:07:11 -07:00
"netbsd-386" , "netbsd-amd64" ,
2015-03-10 02:11:30 -06:00
"openbsd-386" , "openbsd-amd64" ,
2015-03-13 20:12:09 -06:00
"windows-386" , "windows-amd64" :
2015-03-02 18:07:11 -07:00
return true
case "darwin-386" , "darwin-amd64" :
// linkmode=external fails on OS X 10.6 and earlier == Darwin
// 10.8 and earlier.
unameR , err := exec . Command ( "uname" , "-r" ) . Output ( )
if err != nil {
log . Fatalf ( "uname -r: %v" , err )
}
major , _ := strconv . Atoi ( string ( unameR [ : bytes . IndexByte ( unameR , '.' ) ] ) )
return major > 10
}
return false
}
2016-09-16 16:25:52 -06:00
func ( t * tester ) internalLink ( ) bool {
2017-09-19 07:13:22 -06:00
if gohostos == "dragonfly" {
2016-09-16 16:25:52 -06:00
// linkmode=internal fails on dragonfly since errno is a TLS relocation.
return false
}
2017-09-19 07:13:22 -06:00
if gohostarch == "ppc64le" {
2016-09-16 16:25:52 -06:00
// linkmode=internal fails on ppc64le because cmd/link doesn't
// handle the TOC correctly (issue 15409).
return false
}
2017-09-19 07:13:22 -06:00
if goos == "android" {
2016-09-16 16:25:52 -06:00
return false
}
2017-09-19 07:13:22 -06:00
if goos == "darwin" && ( goarch == "arm" || goarch == "arm64" ) {
2016-09-16 16:25:52 -06:00
return false
}
// Internally linking cgo is incomplete on some architectures.
// https://golang.org/issue/10373
// https://golang.org/issue/14449
2017-09-19 07:13:22 -06:00
if goarch == "arm64" || goarch == "mips64" || goarch == "mips64le" || goarch == "mips" || goarch == "mipsle" {
2016-09-16 16:25:52 -06:00
return false
}
2017-04-25 17:13:05 -06:00
if isAlpineLinux ( ) {
// Issue 18243.
return false
}
2016-09-16 16:25:52 -06:00
return true
}
2015-04-29 18:30:56 -06:00
func ( t * tester ) supportedBuildmode ( mode string ) bool {
2017-09-19 07:13:22 -06:00
pair := goos + "-" + goarch
2015-04-16 11:08:20 -06:00
switch mode {
case "c-archive" :
2015-04-23 15:27:38 -06:00
if ! t . extLink ( ) {
2015-04-16 11:08:20 -06:00
return false
2015-04-23 15:27:38 -06:00
}
switch pair {
2015-07-20 10:33:39 -06:00
case "darwin-386" , "darwin-amd64" , "darwin-arm" , "darwin-arm64" ,
2017-10-31 17:18:48 -06:00
"linux-amd64" , "linux-386" , "linux-ppc64le" , "linux-s390x" ,
2017-05-24 16:01:49 -06:00
"windows-amd64" , "windows-386" :
2015-04-16 11:08:20 -06:00
return true
}
2015-04-23 15:27:38 -06:00
return false
2015-04-17 12:50:07 -06:00
case "c-shared" :
2015-04-23 15:27:38 -06:00
switch pair {
2017-10-31 17:18:48 -06:00
case "linux-386" , "linux-amd64" , "linux-arm" , "linux-arm64" , "linux-ppc64le" , "linux-s390x" ,
2016-01-10 22:23:51 -07:00
"darwin-amd64" , "darwin-386" ,
2017-10-05 00:36:13 -06:00
"android-arm" , "android-arm64" , "android-386" ,
"windows-amd64" , "windows-386" :
2015-04-23 15:27:38 -06:00
return true
}
return false
2015-04-26 21:00:48 -06:00
case "shared" :
switch pair {
2016-03-20 21:00:40 -06:00
case "linux-386" , "linux-amd64" , "linux-arm" , "linux-arm64" , "linux-ppc64le" , "linux-s390x" :
2016-08-26 07:04:27 -06:00
return true
}
return false
case "plugin" :
2016-09-16 16:53:46 -06:00
// linux-arm64 is missing because it causes the external linker
// to crash, see https://golang.org/issue/17138
2016-08-26 07:04:27 -06:00
switch pair {
2017-08-15 12:34:53 -06:00
case "linux-386" , "linux-amd64" , "linux-arm" , "linux-s390x" , "linux-ppc64le" :
2015-04-26 21:00:48 -06:00
return true
2017-09-04 06:23:29 -06:00
case "darwin-amd64" :
return true
2015-04-26 21:00:48 -06:00
}
return false
2017-09-28 08:26:39 -06:00
case "pie" :
switch pair {
case "linux-386" , "linux-amd64" , "linux-arm" , "linux-arm64" , "linux-ppc64le" , "linux-s390x" ,
"android-amd64" , "android-arm" , "android-arm64" , "android-386" :
return true
case "darwin-amd64" :
return true
}
return false
2015-04-16 11:08:20 -06:00
default :
2016-05-12 06:13:22 -06:00
log . Fatalf ( "internal error: unknown buildmode %s" , mode )
2015-04-16 11:08:20 -06:00
return false
}
}
2016-08-30 19:11:10 -06:00
func ( t * tester ) registerHostTest ( name , heading , dir , pkg string ) {
2016-03-24 14:47:02 -06:00
t . tests = append ( t . tests , distTest {
name : name ,
2016-08-30 19:11:10 -06:00
heading : heading ,
2016-03-24 14:47:02 -06:00
fn : func ( dt * distTest ) error {
2016-03-24 18:27:34 -06:00
t . runPending ( dt )
2017-10-27 11:07:38 -06:00
timelog ( "start" , name )
defer timelog ( "end" , name )
2016-08-30 19:11:10 -06:00
return t . runHostTest ( dir , pkg )
2016-03-24 14:47:02 -06:00
} ,
} )
}
2016-08-30 19:11:10 -06:00
func ( t * tester ) runHostTest ( dir , pkg string ) error {
2017-09-19 07:13:22 -06:00
defer os . Remove ( filepath . Join ( goroot , dir , "test.test" ) )
2017-11-29 12:16:25 -07:00
cmd := t . dirCmd ( dir , t . goTest ( ) , "-c" , "-o" , "test.test" , pkg )
2017-09-19 07:13:22 -06:00
cmd . Env = append ( os . Environ ( ) , "GOARCH=" + gohostarch , "GOOS=" + gohostos )
2016-03-24 14:47:02 -06:00
if err := cmd . Run ( ) ; err != nil {
return err
}
2016-08-30 19:11:10 -06:00
return t . dirCmd ( dir , "./test.test" ) . Run ( )
2016-03-24 14:47:02 -06:00
}
2015-12-21 14:08:57 -07:00
func ( t * tester ) cgoTest ( dt * distTest ) error {
2017-11-29 12:16:25 -07:00
t . addCmd ( dt , "misc/cgo/test" , t . goTest ( ) , "-ldflags" , "-linkmode=auto" )
2015-04-07 00:43:11 -06:00
2016-09-16 16:25:52 -06:00
if t . internalLink ( ) {
2017-11-29 12:16:25 -07:00
t . addCmd ( dt , "misc/cgo/test" , t . goTest ( ) , "-tags=internal" , "-ldflags" , "-linkmode=internal" )
2015-03-02 18:07:11 -07:00
}
2017-09-19 07:13:22 -06:00
pair := gohostos + "-" + goarch
2015-03-02 18:07:11 -07:00
switch pair {
2015-06-29 11:12:10 -06:00
case "darwin-386" , "darwin-amd64" ,
"openbsd-386" , "openbsd-amd64" ,
"windows-386" , "windows-amd64" :
2015-03-02 18:07:11 -07:00
// test linkmode=external, but __thread not supported, so skip testtls.
2015-06-29 11:12:10 -06:00
if ! t . extLink ( ) {
break
}
2017-11-29 12:16:25 -07:00
t . addCmd ( dt , "misc/cgo/test" , t . goTest ( ) , "-ldflags" , "-linkmode=external" )
t . addCmd ( dt , "misc/cgo/test" , t . goTest ( ) , "-ldflags" , "-linkmode=external -s" )
2015-03-02 18:07:11 -07:00
case "android-arm" ,
2017-11-23 02:16:02 -07:00
"dragonfly-amd64" ,
2015-03-02 18:07:11 -07:00
"freebsd-386" , "freebsd-amd64" , "freebsd-arm" ,
2016-11-07 09:50:48 -07:00
"linux-386" , "linux-amd64" , "linux-arm" , "linux-ppc64le" , "linux-s390x" ,
2015-03-02 18:07:11 -07:00
"netbsd-386" , "netbsd-amd64" :
2017-11-29 12:16:25 -07:00
t . addCmd ( dt , "misc/cgo/test" , t . goTest ( ) , "-ldflags" , "-linkmode=external" )
t . addCmd ( dt , "misc/cgo/testtls" , t . goTest ( ) , "-ldflags" , "-linkmode=auto" )
t . addCmd ( dt , "misc/cgo/testtls" , t . goTest ( ) , "-ldflags" , "-linkmode=external" )
2015-03-02 18:07:11 -07:00
switch pair {
case "netbsd-386" , "netbsd-amd64" :
// no static linking
case "freebsd-arm" :
// -fPIC compiled tls code will use __tls_get_addr instead
// of __aeabi_read_tp, however, on FreeBSD/ARM, __tls_get_addr
// is implemented in rtld-elf, so -fPIC isn't compatible with
// static linking on FreeBSD/ARM with clang. (cgo depends on
// -fPIC fundamentally.)
default :
2017-11-14 13:50:38 -07:00
cmd := t . dirCmd ( "misc/cgo/test" ,
compilerEnvLookup ( defaultcc , goos , goarch ) , "-xc" , "-o" , "/dev/null" , "-static" , "-" )
cmd . Stdin = strings . NewReader ( "int main() {}" )
if err := cmd . Run ( ) ; err != nil {
fmt . Println ( "No support for static linking found (lacks libc.a?), skip cgo static linking test." )
} else {
if goos != "android" {
2017-11-29 12:16:25 -07:00
t . addCmd ( dt , "misc/cgo/testtls" , t . goTest ( ) , "-ldflags" , ` -linkmode=external -extldflags "-static -pthread" ` )
2017-11-14 13:50:38 -07:00
}
2017-11-29 12:16:25 -07:00
t . addCmd ( dt , "misc/cgo/nocgo" , t . goTest ( ) )
t . addCmd ( dt , "misc/cgo/nocgo" , t . goTest ( ) , "-ldflags" , ` -linkmode=external ` )
2017-11-14 13:50:38 -07:00
if goos != "android" {
2017-11-29 12:16:25 -07:00
t . addCmd ( dt , "misc/cgo/nocgo" , t . goTest ( ) , "-ldflags" , ` -linkmode=external -extldflags "-static -pthread" ` )
2017-11-14 13:50:38 -07:00
}
}
2017-09-28 08:26:39 -06:00
if t . supportedBuildmode ( "pie" ) {
2017-11-29 12:16:25 -07:00
t . addCmd ( dt , "misc/cgo/test" , t . goTest ( ) , "-buildmode=pie" )
t . addCmd ( dt , "misc/cgo/testtls" , t . goTest ( ) , "-buildmode=pie" )
t . addCmd ( dt , "misc/cgo/nocgo" , t . goTest ( ) , "-buildmode=pie" )
2015-03-02 18:07:11 -07:00
}
}
}
return nil
}
2015-12-21 14:08:57 -07:00
// run pending test commands, in parallel, emitting headers as appropriate.
2015-12-21 18:42:40 -07:00
// When finished, emit header for nextTest, which is going to run after the
2015-12-21 14:08:57 -07:00
// pending commands are done (and runPending returns).
2015-12-21 18:42:40 -07:00
// A test should call runPending if it wants to make sure that it is not
// running in parallel with earlier tests, or if it has some other reason
// for needing the earlier tests to be done.
2015-12-21 14:08:57 -07:00
func ( t * tester ) runPending ( nextTest * distTest ) {
cmd/go: switch to entirely content-based staleness determination
This CL changes the go command to base all its rebuilding decisions
on the content of the files being processed and not their file system
modification times. It also eliminates the special handling of release
toolchains, which were previously considered always up-to-date
because modification time order could not be trusted when unpacking
a pre-built release.
The go command previously tracked "build IDs" as a backup to
modification times, to catch changes not reflected in modification times.
For example, if you remove one .go file in a package with multiple .go
files, there is no modification time remaining in the system that indicates
that the installed package is out of date. The old build ID was the hash
of a list of file names and a few other factors, expected to change if
those factors changed.
This CL moves to using this kind of build ID as the only way to
detect staleness, making sure that the build ID hash includes all
possible factors that need to influence the rebuild decision.
One such factor is the compiler flags. As of this CL, if you run
go build -gcflags -N cmd/gofmt
you will get a gofmt where every package is built with -N,
regardless of what may or may not be installed already.
Another such factor is the linker flags. As of this CL, if you run
go install myprog
go install -ldflags=-s myprog
the second go install will now correctly build a new myprog with
the updated linker flags. (Previously the installed myprog appeared
up-to-date, because the ldflags were not included in the build ID.)
Because we have more precise information we can also validate whether
the target of a "go test -c" operation is already the right binary and
therefore can avoid a rebuild.
This CL sets us up for having a more general build artifact cache,
maybe even a step toward not having a pkg directory with .a files,
but this CL does not take that step. For now the result of go install
is the same as it ever was; we just do a better job of what needs to
be installed.
This CL does slow down builds a small amount by reading all the
dependent source files in full. (The go command already read the
beginning of every dependent source file to discover build tags
and imports.) On my MacBook Pro, before this CL all.bash takes
3m58s, while after this CL and a few optimizations stacked above it
all.bash takes 4m28s. Given that CL 73850 cut 1m43s off the all.bash
time earlier today, we can afford adding 30s back for now.
More optimizations are planned that should make the go command
more efficient than it was even before this CL.
Fixes #15799.
Fixes #18369.
Fixes #19340.
Fixes #21477.
Change-Id: I10d7ca0e31ca3f58aabb9b1f11e2e3d9d18f0bc9
Reviewed-on: https://go-review.googlesource.com/73212
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
2017-10-11 18:39:28 -06:00
checkNotStale ( "go" , "std" , "cmd" )
2015-12-21 14:08:57 -07:00
worklist := t . worklist
t . worklist = nil
for _ , w := range worklist {
w . start = make ( chan bool )
w . end = make ( chan bool )
go func ( w * work ) {
if ! <- w . start {
2017-10-27 11:07:38 -06:00
timelog ( "skip" , w . dt . name )
2015-12-21 14:08:57 -07:00
w . out = [ ] byte ( fmt . Sprintf ( "skipped due to earlier error\n" ) )
} else {
2017-10-27 11:07:38 -06:00
timelog ( "start" , w . dt . name )
2015-12-21 14:08:57 -07:00
w . out , w . err = w . cmd . CombinedOutput ( )
}
2017-10-27 11:07:38 -06:00
timelog ( "end" , w . dt . name )
2015-12-21 14:08:57 -07:00
w . end <- true
} ( w )
}
started := 0
ended := 0
var last * distTest
for ended < len ( worklist ) {
for started < len ( worklist ) && started - ended < maxbg {
//println("start", started)
w := worklist [ started ]
started ++
w . start <- ! t . failed || t . keepGoing
}
w := worklist [ ended ]
dt := w . dt
if dt . heading != "" && t . lastHeading != dt . heading {
t . lastHeading = dt . heading
t . out ( dt . heading )
}
if dt != last {
// Assumes all the entries for a single dt are in one worklist.
last = w . dt
if vflag > 0 {
fmt . Printf ( "# go tool dist test -run=^%s$\n" , dt . name )
}
}
if vflag > 1 {
errprintf ( "%s\n" , strings . Join ( w . cmd . Args , " " ) )
}
//println("wait", ended)
ended ++
<- w . end
os . Stdout . Write ( w . out )
if w . err != nil {
log . Printf ( "Failed: %v" , w . err )
t . failed = true
}
cmd/go: switch to entirely content-based staleness determination
This CL changes the go command to base all its rebuilding decisions
on the content of the files being processed and not their file system
modification times. It also eliminates the special handling of release
toolchains, which were previously considered always up-to-date
because modification time order could not be trusted when unpacking
a pre-built release.
The go command previously tracked "build IDs" as a backup to
modification times, to catch changes not reflected in modification times.
For example, if you remove one .go file in a package with multiple .go
files, there is no modification time remaining in the system that indicates
that the installed package is out of date. The old build ID was the hash
of a list of file names and a few other factors, expected to change if
those factors changed.
This CL moves to using this kind of build ID as the only way to
detect staleness, making sure that the build ID hash includes all
possible factors that need to influence the rebuild decision.
One such factor is the compiler flags. As of this CL, if you run
go build -gcflags -N cmd/gofmt
you will get a gofmt where every package is built with -N,
regardless of what may or may not be installed already.
Another such factor is the linker flags. As of this CL, if you run
go install myprog
go install -ldflags=-s myprog
the second go install will now correctly build a new myprog with
the updated linker flags. (Previously the installed myprog appeared
up-to-date, because the ldflags were not included in the build ID.)
Because we have more precise information we can also validate whether
the target of a "go test -c" operation is already the right binary and
therefore can avoid a rebuild.
This CL sets us up for having a more general build artifact cache,
maybe even a step toward not having a pkg directory with .a files,
but this CL does not take that step. For now the result of go install
is the same as it ever was; we just do a better job of what needs to
be installed.
This CL does slow down builds a small amount by reading all the
dependent source files in full. (The go command already read the
beginning of every dependent source file to discover build tags
and imports.) On my MacBook Pro, before this CL all.bash takes
3m58s, while after this CL and a few optimizations stacked above it
all.bash takes 4m28s. Given that CL 73850 cut 1m43s off the all.bash
time earlier today, we can afford adding 30s back for now.
More optimizations are planned that should make the go command
more efficient than it was even before this CL.
Fixes #15799.
Fixes #18369.
Fixes #19340.
Fixes #21477.
Change-Id: I10d7ca0e31ca3f58aabb9b1f11e2e3d9d18f0bc9
Reviewed-on: https://go-review.googlesource.com/73212
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
2017-10-11 18:39:28 -06:00
checkNotStale ( "go" , "std" , "cmd" )
2015-12-21 14:08:57 -07:00
}
if t . failed && ! t . keepGoing {
log . Fatal ( "FAILED" )
}
if dt := nextTest ; dt != nil {
if dt . heading != "" && t . lastHeading != dt . heading {
t . lastHeading = dt . heading
t . out ( dt . heading )
}
if vflag > 0 {
fmt . Printf ( "# go tool dist test -run=^%s$\n" , dt . name )
}
}
}
2015-06-01 21:46:28 -06:00
func ( t * tester ) cgoTestSOSupported ( ) bool {
2017-09-19 07:13:22 -06:00
if goos == "android" || t . iOS ( ) {
2015-06-01 21:46:28 -06:00
// No exec facility on Android or iOS.
return false
}
2017-09-19 07:13:22 -06:00
if goarch == "ppc64" {
2015-06-01 21:46:28 -06:00
// External linking not implemented on ppc64 (issue #8912).
return false
}
2017-09-19 07:13:22 -06:00
if goarch == "mips64le" || goarch == "mips64" {
2015-09-10 08:16:45 -06:00
// External linking not implemented on mips64.
return false
}
2015-06-01 21:46:28 -06:00
return true
}
2015-12-21 14:08:57 -07:00
func ( t * tester ) cgoTestSO ( dt * distTest , testpath string ) error {
t . runPending ( dt )
2017-10-27 11:07:38 -06:00
timelog ( "start" , dt . name )
defer timelog ( "end" , dt . name )
2017-09-19 07:13:22 -06:00
dir := filepath . Join ( goroot , testpath )
2015-06-01 21:46:28 -06:00
// build shared object
output , err := exec . Command ( "go" , "env" , "CC" ) . Output ( )
if err != nil {
return fmt . Errorf ( "Error running go env CC: %v" , err )
}
cc := strings . TrimSuffix ( string ( output ) , "\n" )
if cc == "" {
return errors . New ( "CC environment variable (go env CC) cannot be empty" )
}
output , err = exec . Command ( "go" , "env" , "GOGCCFLAGS" ) . Output ( )
2015-03-03 22:16:26 -07:00
if err != nil {
2015-06-01 21:46:28 -06:00
return fmt . Errorf ( "Error running go env GOGCCFLAGS: %v" , err )
}
gogccflags := strings . Split ( strings . TrimSuffix ( string ( output ) , "\n" ) , " " )
ext := "so"
args := append ( gogccflags , "-shared" )
2017-09-19 07:13:22 -06:00
switch goos {
2015-06-01 21:46:28 -06:00
case "darwin" :
ext = "dylib"
args = append ( args , "-undefined" , "suppress" , "-flat_namespace" )
case "windows" :
ext = "dll"
2015-06-15 23:36:06 -06:00
args = append ( args , "-DEXPORT_DLL" )
2015-06-01 21:46:28 -06:00
}
sofname := "libcgosotest." + ext
args = append ( args , "-o" , sofname , "cgoso_c.c" )
2017-11-29 12:16:25 -07:00
if err := t . dirCmd ( dir , cc , args ) . Run ( ) ; err != nil {
2015-03-03 22:16:26 -07:00
return err
}
2015-06-01 21:46:28 -06:00
defer os . Remove ( filepath . Join ( dir , sofname ) )
if err := t . dirCmd ( dir , "go" , "build" , "-o" , "main.exe" , "main.go" ) . Run ( ) ; err != nil {
return err
2015-03-03 22:16:26 -07:00
}
2015-06-01 21:46:28 -06:00
defer os . Remove ( filepath . Join ( dir , "main.exe" ) )
cmd := t . dirCmd ( dir , "./main.exe" )
2017-09-19 07:13:22 -06:00
if goos != "windows" {
2015-06-01 21:46:28 -06:00
s := "LD_LIBRARY_PATH"
2017-09-19 07:13:22 -06:00
if goos == "darwin" {
2015-06-01 21:46:28 -06:00
s = "DYLD_LIBRARY_PATH"
}
2017-03-02 15:12:09 -07:00
cmd . Env = append ( os . Environ ( ) , s + "=." )
2016-01-08 05:22:12 -07:00
// On FreeBSD 64-bit architectures, the 32-bit linker looks for
// different environment variables.
2017-09-19 07:13:22 -06:00
if goos == "freebsd" && gohostarch == "386" {
2017-03-02 15:12:09 -07:00
cmd . Env = append ( cmd . Env , "LD_32_LIBRARY_PATH=." )
2016-01-08 05:22:12 -07:00
}
2015-06-01 21:46:28 -06:00
}
return cmd . Run ( )
2015-03-03 22:16:26 -07:00
}
2015-03-02 18:07:11 -07:00
func ( t * tester ) hasBash ( ) bool {
2017-09-19 07:13:22 -06:00
switch gohostos {
2015-03-02 18:07:11 -07:00
case "windows" , "plan9" :
return false
}
return true
}
2017-12-06 19:09:11 -07:00
func ( t * tester ) hasSwig ( ) bool {
swig , err := exec . LookPath ( "swig" )
if err != nil {
return false
}
out , err := exec . Command ( swig , "-version" ) . CombinedOutput ( )
if err != nil {
return false
}
re := regexp . MustCompile ( ` [vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)? ` )
matches := re . FindSubmatch ( out )
if matches == nil {
// Can't find version number; hope for the best.
return true
}
major , err := strconv . Atoi ( string ( matches [ 1 ] ) )
if err != nil {
// Can't find version number; hope for the best.
return true
}
if major < 3 {
return false
}
if major > 3 {
// 4.0 or later
return true
}
// We have SWIG version 3.x.
if len ( matches [ 2 ] ) > 0 {
minor , err := strconv . Atoi ( string ( matches [ 2 ] [ 1 : ] ) )
if err != nil {
return true
}
if minor > 0 {
// 3.1 or later
return true
}
}
// We have SWIG version 3.0.x.
if len ( matches [ 3 ] ) > 0 {
patch , err := strconv . Atoi ( string ( matches [ 3 ] [ 1 : ] ) )
if err != nil {
return true
}
if patch < 6 {
// Before 3.0.6.
return false
}
}
return true
}
2015-03-02 18:07:11 -07:00
func ( t * tester ) raceDetectorSupported ( ) bool {
2017-09-19 07:13:22 -06:00
switch gohostos {
2015-03-02 18:07:11 -07:00
case "linux" , "darwin" , "freebsd" , "windows" :
2017-04-25 00:11:09 -06:00
// The race detector doesn't work on Alpine Linux:
// golang.org/issue/14481
2017-09-19 07:13:22 -06:00
return t . cgoEnabled && goarch == "amd64" && gohostos == goos && ! isAlpineLinux ( )
2015-03-02 18:07:11 -07:00
}
return false
}
2017-04-25 00:11:09 -06:00
func isAlpineLinux ( ) bool {
if runtime . GOOS != "linux" {
return false
}
fi , err := os . Lstat ( "/etc/alpine-release" )
return err == nil && fi . Mode ( ) . IsRegular ( )
}
2016-05-04 10:08:27 -06:00
func ( t * tester ) runFlag ( rx string ) string {
if t . compileOnly {
return "-run=^$"
}
return "-run=" + rx
}
2015-12-21 14:08:57 -07:00
func ( t * tester ) raceTest ( dt * distTest ) error {
2017-11-29 12:16:25 -07:00
t . addCmd ( dt , "src" , t . goTest ( ) , "-race" , "-i" , "runtime/race" , "flag" , "os" , "os/exec" )
t . addCmd ( dt , "src" , t . goTest ( ) , "-race" , t . runFlag ( "Output" ) , "runtime/race" )
t . addCmd ( dt , "src" , t . goTest ( ) , "-race" , t . runFlag ( "TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace" ) , "flag" , "os" , "os/exec" )
2016-02-16 08:13:10 -07:00
// We don't want the following line, because it
// slows down all.bash (by 10 seconds on my laptop).
// The race builder should catch any error here, but doesn't.
// TODO(iant): Figure out how to catch this.
2017-11-29 12:16:25 -07:00
// t.addCmd(dt, "src", t.goTest(), "-race", "-run=TestParallelTest", "cmd/go")
2016-10-28 09:12:39 -06:00
if t . cgoEnabled {
2017-11-29 12:16:25 -07:00
cmd := t . addCmd ( dt , "misc/cgo/test" , t . goTest ( ) , "-race" )
2017-03-02 15:12:09 -07:00
cmd . Env = append ( os . Environ ( ) , "GOTRACEBACK=2" )
2015-07-22 13:31:54 -06:00
}
2015-03-02 18:07:11 -07:00
if t . extLink ( ) {
// Test with external linking; see issue 9133.
2017-11-29 12:16:25 -07:00
t . addCmd ( dt , "src" , t . goTest ( ) , "-race" , "-ldflags=-linkmode=external" , t . runFlag ( "TestParse|TestEcho|TestStdinCloseRace" ) , "flag" , "os/exec" )
2015-03-02 18:07:11 -07:00
}
return nil
}
2015-12-21 18:42:40 -07:00
var runtest struct {
sync . Once
exe string
err error
}
2015-12-21 14:08:57 -07:00
func ( t * tester ) testDirTest ( dt * distTest , shard , shards int ) error {
2015-12-21 18:42:40 -07:00
runtest . Do ( func ( ) {
const exe = "runtest.exe" // named exe for Windows, but harmless elsewhere
cmd := t . dirCmd ( "test" , "go" , "build" , "-o" , exe , "run.go" )
2017-09-19 07:13:22 -06:00
cmd . Env = append ( os . Environ ( ) , "GOOS=" + gohostos , "GOARCH=" + gohostarch )
2015-12-21 18:42:40 -07:00
runtest . exe = filepath . Join ( cmd . Dir , exe )
if err := cmd . Run ( ) ; err != nil {
runtest . err = err
return
}
xatexit ( func ( ) {
os . Remove ( runtest . exe )
} )
} )
if runtest . err != nil {
return runtest . err
2015-03-02 18:07:11 -07:00
}
2016-05-04 10:08:27 -06:00
if t . compileOnly {
return nil
}
2015-12-21 18:42:40 -07:00
t . addCmd ( dt , "test" , runtest . exe ,
2015-06-04 00:21:30 -06:00
fmt . Sprintf ( "--shard=%d" , shard ) ,
fmt . Sprintf ( "--shards=%d" , shards ) ,
2015-12-21 18:42:40 -07:00
)
return nil
2015-03-02 18:07:11 -07:00
}
2015-11-16 19:11:35 -07:00
// cgoPackages is the standard packages that use cgo.
var cgoPackages = [ ] string {
"crypto/x509" ,
"net" ,
"os/user" ,
}
2016-09-14 10:34:27 -06:00
var funcBenchmark = [ ] byte ( "\nfunc Benchmark" )
// packageHasBenchmarks reports whether pkg has benchmarks.
// On any error, it conservatively returns true.
//
// This exists just to eliminate work on the builders, since compiling
// a test in race mode just to discover it has no benchmarks costs a
// second or two per package, and this function returns false for
// about 100 packages.
func ( t * tester ) packageHasBenchmarks ( pkg string ) bool {
2017-09-19 07:13:22 -06:00
pkgDir := filepath . Join ( goroot , "src" , pkg )
2016-09-14 10:34:27 -06:00
d , err := os . Open ( pkgDir )
if err != nil {
return true // conservatively
}
defer d . Close ( )
names , err := d . Readdirnames ( - 1 )
if err != nil {
return true // conservatively
}
for _ , name := range names {
if ! strings . HasSuffix ( name , "_test.go" ) {
continue
}
slurp , err := ioutil . ReadFile ( filepath . Join ( pkgDir , name ) )
if err != nil {
return true // conservatively
}
if bytes . Contains ( slurp , funcBenchmark ) {
return true
}
}
return false
}