cgoEnabled bool
partial bool
+ goExe string // For host tests
+ goTmpDir string // For host tests
+
tests []distTest
timeoutScale int
os.Setenv("PATH", fmt.Sprintf("%s%c%s", gorootBin, os.PathListSeparator, os.Getenv("PATH")))
- cmd := exec.Command(gorootBinGo, "env", "CGO_ENABLED")
+ cmd := exec.Command(gorootBinGo, "env", "CGO_ENABLED", "GOEXE", "GOTMPDIR")
cmd.Stderr = new(bytes.Buffer)
slurp, err := cmd.Output()
if err != nil {
- fatalf("Error running go env CGO_ENABLED: %v\n%s", err, cmd.Stderr)
+ fatalf("Error running %s: %v\n%s", cmd, err, cmd.Stderr)
+ }
+ parts := strings.Split(string(slurp), "\n")
+ if len(parts) < 3 {
+ fatalf("Error running %s: output contains <3 lines\n%s", cmd, cmd.Stderr)
}
- t.cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(slurp)))
+ t.cgoEnabled, _ = strconv.ParseBool(parts[0])
+ t.goExe = parts[1]
+ t.goTmpDir = parts[2]
+
if flag.NArg() > 0 && t.runRxStr != "" {
fatalf("the -run regular expression flag is mutually exclusive with test name arguments")
}
return opts.command(t).Run()
}
+// runHostTest runs a test that should be built and run on the host GOOS/GOARCH,
+// but run with GOOS/GOARCH set to the target GOOS/GOARCH. This is for tests
+// that do nothing but compile and run other binaries. If the host and target
+// are different, then the assumption is that the target is running in an
+// emulator and does not have a Go toolchain at all, so the test needs to run on
+// the host, but its resulting binaries will be run through a go_exec wrapper
+// that runs them on the target.
+func (opts *goTest) runHostTest(t *tester) error {
+ goCmd, build, run, pkgs, setupCmd := opts.buildArgs(t)
+
+ // Build the host test binary
+ if len(pkgs) != 1 {
+ // We can't compile more than one package.
+ panic("host tests must have a single test package")
+ }
+ if len(opts.env) != 0 {
+ // It's not clear if these are for the host or the target.
+ panic("host tests must not have environment variables")
+ }
+
+ f, err := os.CreateTemp(t.goTmpDir, "test.test-*"+t.goExe)
+ if err != nil {
+ fatalf("failed to create temporary file: %s", err)
+ }
+ bin := f.Name()
+ f.Close()
+ xatexit(func() { os.Remove(bin) })
+
+ args := append([]string{"test", "-c", "-o", bin}, build...)
+ args = append(args, pkgs...)
+ cmd := exec.Command(goCmd, args...)
+ setupCmd(cmd)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ setEnv(cmd, "GOARCH", gohostarch)
+ setEnv(cmd, "GOOS", gohostos)
+ if vflag > 1 {
+ errprintf("%s\n", cmd)
+ }
+ if err := cmd.Run(); err != nil {
+ return err
+ }
+
+ if t.compileOnly {
+ return nil
+ }
+
+ // Transform run flags to be passed directly to a test binary.
+ for i, f := range run {
+ if !strings.HasPrefix(f, "-") {
+ panic("run flag does not start with -: " + f)
+ }
+ run[i] = "-test." + f[1:]
+ }
+
+ // Run the test
+ args = append(run, opts.testFlags...)
+ cmd = exec.Command(bin, args...)
+ setupCmd(cmd)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if vflag > 1 {
+ errprintf("%s\n", cmd)
+ }
+ return cmd.Run()
+}
+
// buildArgs is in internal helper for goTest that constructs the elements of
// the "go test" command line. goCmd is the path to the go command to use. build
// is the flags for building the test. run is the flags for running the test.
if t.cgoEnabled && !t.iOS() {
// Disabled on iOS. golang.org/issue/15919
- t.registerHostTest("cgo_stdio", "../misc/cgo/stdio", "misc/cgo/stdio", ".")
- t.registerHostTest("cgo_life", "../misc/cgo/life", "misc/cgo/life", ".")
+ t.registerTest("cgo_stdio", "", &goTest{dir: "../misc/cgo/stdio", timeout: 5 * time.Minute}, rtHostTest{})
+ t.registerTest("cgo_life", "", &goTest{dir: "../misc/cgo/life", timeout: 5 * time.Minute}, rtHostTest{})
if goos != "android" {
- t.registerHostTest("cgo_fortran", "../misc/cgo/fortran", "misc/cgo/fortran", ".")
+ t.registerTest("cgo_fortran", "", &goTest{dir: "../misc/cgo/fortran", timeout: 5 * time.Minute}, rtHostTest{})
}
if t.hasSwig() && goos != "android" {
t.registerTest("swig_stdio", "", &goTest{dir: "../misc/swig/stdio"})
// recompile the entire standard library. If make.bash ran with
// special -gcflags, that's not true.
if t.cgoEnabled && gogcflags == "" {
- t.registerHostTest("testgodefs", "../misc/cgo/testgodefs", "misc/cgo/testgodefs", ".")
+ t.registerTest("testgodefs", "", &goTest{dir: "../misc/cgo/testgodefs", timeout: 5 * time.Minute}, rtHostTest{})
t.registerTest("testso", "", &goTest{dir: "../misc/cgo/testso", timeout: 600 * time.Second})
t.registerTest("testsovar", "", &goTest{dir: "../misc/cgo/testsovar", timeout: 600 * time.Second})
if t.supportedBuildmode("c-archive") {
- t.registerHostTest("testcarchive", "../misc/cgo/testcarchive", "misc/cgo/testcarchive", ".")
+ t.registerTest("testcarchive", "", &goTest{dir: "../misc/cgo/testcarchive", timeout: 5 * time.Minute}, rtHostTest{})
}
if t.supportedBuildmode("c-shared") {
- t.registerHostTest("testcshared", "../misc/cgo/testcshared", "misc/cgo/testcshared", ".")
+ t.registerTest("testcshared", "", &goTest{dir: "../misc/cgo/testcshared", timeout: 5 * time.Minute}, rtHostTest{})
}
if t.supportedBuildmode("shared") {
t.registerTest("testshared", "", &goTest{dir: "../misc/cgo/testshared", timeout: 600 * time.Second})
if goos == "linux" || (goos == "freebsd" && goarch == "amd64") {
// because Pdeathsig of syscall.SysProcAttr struct used in misc/cgo/testsanitizers is only
// supported on Linux and FreeBSD.
- t.registerHostTest("testsanitizers", "../misc/cgo/testsanitizers", "misc/cgo/testsanitizers", ".")
+ t.registerTest("testsanitizers", "", &goTest{dir: "../misc/cgo/testsanitizers", timeout: 5 * time.Minute}, rtHostTest{})
}
if t.hasBash() && goos != "android" && !t.iOS() && gohostos != "windows" {
- t.registerHostTest("cgo_errors", "../misc/cgo/errors", "misc/cgo/errors", ".")
+ t.registerTest("cgo_errors", "", &goTest{dir: "../misc/cgo/errors", timeout: 5 * time.Minute}, rtHostTest{})
}
}
// Ensure that the toolchain can bootstrap itself.
// This test adds another ~45s to all.bash if run sequentially, so run it only on the builders.
if os.Getenv("GO_BUILDER_NAME") != "" && goos != "android" && !t.iOS() {
- t.registerHostTest("reboot", "../misc/reboot", "misc/reboot", ".")
+ t.registerTest("reboot", "", &goTest{dir: "../misc/reboot", timeout: 5 * time.Minute}, rtHostTest{})
}
}
func (rtPreFunc) isRegisterTestOpt() {}
+// rtHostTest is a registerTest option that indicates this is a host test that
+// should be run using goTest.runHostTest. It implies rtSequential.
+type rtHostTest struct{}
+
+func (rtHostTest) isRegisterTestOpt() {}
+
// registerTest registers a test that runs the given goTest.
//
// If heading is "", it uses test.dir as the heading.
func (t *tester) registerTest(name, heading string, test *goTest, opts ...registerTestOpt) {
seq := false
+ hostTest := false
var preFunc func(*distTest) bool
for _, opt := range opts {
switch opt := opt.(type) {
seq = true
case rtPreFunc:
preFunc = opt.pre
+ case rtHostTest:
+ seq, hostTest = true, true
}
}
if t.isRegisteredTestName(name) {
}
if seq {
t.runPending(dt)
+ if hostTest {
+ return test.runHostTest(t)
+ }
return test.run(t)
}
w := &work{
}
}
-func (t *tester) registerHostTest(name, heading, dir, pkg string) {
- t.tests = append(t.tests, distTest{
- name: name,
- heading: heading,
- fn: func(dt *distTest) error {
- t.runPending(dt)
- timelog("start", name)
- defer timelog("end", name)
- return t.runHostTest(dir, pkg)
- },
- })
-}
-
-func (t *tester) runHostTest(dir, pkg string) error {
- out, err := exec.Command(gorootBinGo, "env", "GOEXE", "GOTMPDIR").Output()
- if err != nil {
- return err
- }
-
- parts := strings.Split(string(out), "\n")
- if len(parts) < 2 {
- return fmt.Errorf("'go env GOEXE GOTMPDIR' output contains <2 lines")
- }
- GOEXE := strings.TrimSpace(parts[0])
- GOTMPDIR := strings.TrimSpace(parts[1])
-
- f, err := os.CreateTemp(GOTMPDIR, "test.test-*"+GOEXE)
- if err != nil {
- return err
- }
- f.Close()
- defer os.Remove(f.Name())
-
- cmd := t.dirCmd(dir, t.goTest(), "-c", "-o", f.Name(), pkg)
- setEnv(cmd, "GOARCH", gohostarch)
- setEnv(cmd, "GOOS", gohostos)
- if err := cmd.Run(); err != nil {
- return err
- }
- return t.dirCmd(dir, f.Name(), "-test.short="+short(), "-test.timeout="+t.timeoutDuration(300).String()).Run()
-}
-
func (t *tester) registerCgoTests() {
cgoTest := func(name string, subdir, linkmode, buildmode string, opts ...registerTestOpt) *goTest {
gt := &goTest{