]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/dist,internal/testdir: more cooperative host test mechanism
authorAustin Clements <austin@google.com>
Fri, 5 May 2023 17:26:16 +0000 (13:26 -0400)
committerAustin Clements <austin@google.com>
Fri, 12 May 2023 12:35:01 +0000 (12:35 +0000)
On cross-compiling builder machines, we run internal/testdir on the
host, where it can access the Go toolchain to build binaries for the
guest and run them through an exec wrapper. Currently this uses dist
test's existing host test mechanism, which is quite complicated and we
are planning to eliminate (#59999).

Switch internal/testdir to use a more cooperative mechanism. With this
CL, dist still understands that it has to build and run the test using
the host GOOS/GOARCH, but rather than doing complicated manipulation
of environment variables itself, it passes the guest GOOS/GOARCH to
the test, which can easily inject it into its environment. This means
dist test can use "go test" directly, rather than having to split up
the build and run steps.

For #37486.

Change-Id: I556938c0b641960bb778b88b13f2b26256edc7c9
Reviewed-on: https://go-review.googlesource.com/c/go/+/492985
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/dist/test.go
src/internal/testdir/testdir_test.go

index 5a47b86bc681202f6098ec3f4920c9902a7c1859..bce1c7ccfd0a76bedd9a93f28c92614e1221f6ce 100644 (file)
@@ -301,6 +301,8 @@ type goTest struct {
        dir string   // If non-empty, run in GOROOT/src-relative directory dir
        env []string // Environment variables to add, as KEY=VAL. KEY= unsets a variable
 
+       runOnHost bool // When cross-compiling, run this test on the host instead of guest
+
        // We have both pkg and pkgs as a convenience. Both may be set, in which
        // case they will be combined. If both are empty, the default is ".".
        pkgs []string // Multiple packages to test
@@ -312,7 +314,7 @@ type goTest struct {
 // bgCommand returns a go test Cmd. The result has Stdout and Stderr set to nil
 // and is intended to be added to the work queue.
 func (opts *goTest) bgCommand(t *tester) *exec.Cmd {
-       goCmd, build, run, pkgs, setupCmd := opts.buildArgs(t)
+       goCmd, build, run, pkgs, testFlags, setupCmd := opts.buildArgs(t)
 
        // Combine the flags.
        args := append([]string{"test"}, build...)
@@ -323,7 +325,7 @@ func (opts *goTest) bgCommand(t *tester) *exec.Cmd {
        }
        args = append(args, pkgs...)
        if !t.compileOnly {
-               args = append(args, opts.testFlags...)
+               args = append(args, testFlags...)
        }
 
        cmd := exec.Command(goCmd, args...)
@@ -352,7 +354,7 @@ func (opts *goTest) run(t *tester) error {
 // 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)
+       goCmd, build, run, pkgs, testFlags, setupCmd := opts.buildArgs(t)
 
        // Build the host test binary
        if len(pkgs) != 1 {
@@ -400,7 +402,7 @@ func (opts *goTest) runHostTest(t *tester) error {
        }
 
        // Run the test
-       args = append(run, opts.testFlags...)
+       args = append(run, testFlags...)
        cmd = exec.Command(bin, args...)
        setupCmd(cmd)
        cmd.Stdout = os.Stdout
@@ -414,11 +416,12 @@ func (opts *goTest) runHostTest(t *tester) error {
 // 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.
-// pkgs is the list of packages to build and run.
+// pkgs is the list of packages to build and run. testFlags is the list of flags
+// to pass to the test package.
 //
-// The caller is responsible for adding opts.testFlags, and must call setupCmd
-// on the resulting exec.Cmd to set its directory and environment.
-func (opts *goTest) buildArgs(t *tester) (goCmd string, build, run, pkgs []string, setupCmd func(*exec.Cmd)) {
+// The caller must call setupCmd on the resulting exec.Cmd to set its directory
+// and environment.
+func (opts *goTest) buildArgs(t *tester) (goCmd string, build, run, pkgs, testFlags []string, setupCmd func(*exec.Cmd)) {
        goCmd = gorootBinGo
        if opts.goroot != "" {
                goCmd = filepath.Join(opts.goroot, "bin", "go")
@@ -482,6 +485,16 @@ func (opts *goTest) buildArgs(t *tester) (goCmd string, build, run, pkgs []strin
                pkgs = []string{"."}
        }
 
+       runOnHost := opts.runOnHost && (goarch != gohostarch || goos != gohostos)
+       needTestFlags := len(opts.testFlags) > 0 || runOnHost
+       if needTestFlags {
+               testFlags = append([]string{"-args"}, opts.testFlags...)
+       }
+       if runOnHost {
+               // -target is a special flag understood by tests that can run on the host
+               testFlags = append(testFlags, "-target="+goos+"/"+goarch)
+       }
+
        thisGoroot := goroot
        if opts.goroot != "" {
                thisGoroot = opts.goroot
@@ -506,6 +519,10 @@ func (opts *goTest) buildArgs(t *tester) (goCmd string, build, run, pkgs []strin
                                }
                        }
                }
+               if runOnHost {
+                       setEnv(cmd, "GOARCH", gohostarch)
+                       setEnv(cmd, "GOOS", gohostos)
+               }
        }
 
        return
@@ -929,8 +946,8 @@ func (t *tester) registerTests() {
                                &goTest{
                                        dir:       "internal/testdir",
                                        testFlags: []string{fmt.Sprintf("-shard=%d", shard), fmt.Sprintf("-shards=%d", nShards)},
+                                       runOnHost: true,
                                },
-                               rtHostTest{},
                        )
                }
        }
index 8ad2353e9fcd844c039722699ec9c0ffbc0f6743..c86cc20a9cab81d2d85c0983712da9a2320cf022 100644 (file)
@@ -40,6 +40,7 @@ var (
        updateErrors   = flag.Bool("update_errors", false, "update error messages in test file based on compiler output")
        runoutputLimit = flag.Int("l", defaultRunOutputLimit(), "number of parallel runoutput tests to run")
        force          = flag.Bool("f", false, "ignore expected-failure test lists")
+       target         = flag.String("target", "", "cross-compile tests for `goos/goarch`")
 
        shard  = flag.Int("shard", 0, "shard index to run. Only applicable if -shards is non-zero.")
        shards = flag.Int("shards", 0, "number of shards. If 0, all tests are run. This is used by the continuous build.")
@@ -56,8 +57,8 @@ func defaultAllCodeGen() bool {
 var (
        // Package-scoped variables that are initialized at the start of Test.
        goTool       string
-       goos         string
-       goarch       string
+       goos         string // Target GOOS
+       goarch       string // Target GOARCH
        cgoEnabled   bool
        goExperiment string
 
@@ -71,6 +72,20 @@ var (
 // Each .go file test case in GOROOT/test is registered as a subtest with a
 // a full name like "Test/fixedbugs/bug000.go" ('/'-separated relative path).
 func Test(t *testing.T) {
+       if *target != "" {
+               // When -target is set, propagate it to GOOS/GOARCH in our environment
+               // so that all commands run with the target GOOS/GOARCH.
+               //
+               // We do this before even calling "go env", because GOOS/GOARCH can
+               // affect other settings we get from go env (notably CGO_ENABLED).
+               goos, goarch, ok := strings.Cut(*target, "/")
+               if !ok {
+                       t.Fatalf("bad -target flag %q, expected goos/goarch", *target)
+               }
+               t.Setenv("GOOS", goos)
+               t.Setenv("GOARCH", goarch)
+       }
+
        goTool = testenv.GoToolPath(t)
        cmd := exec.Command(goTool, "env", "-json")
        stdout, err := cmd.StdoutPipe()