diff options
author | Austin Clements <austin@google.com> | 2023-05-08 16:31:23 -0400 |
---|---|---|
committer | Austin Clements <austin@google.com> | 2023-05-12 12:35:05 +0000 |
commit | 3943fc14d35c117f2256fb789743d9f075c9aba5 (patch) | |
tree | fc282062b14c176950da4f672202e9b922ea1395 /src/cmd | |
parent | b26c3927bd9b250715a7f8652b3cd5c16475ff07 (diff) | |
download | go-3943fc14d35c117f2256fb789743d9f075c9aba5.tar.gz go-3943fc14d35c117f2256fb789743d9f075c9aba5.zip |
misc/reboot: move to cmd/internal/bootstrap_test
This is the last test run from misc by dist.
For #37486.
Change-Id: I1a70ded29ba0de548c9a16611ba987a258121e80
Reviewed-on: https://go-review.googlesource.com/c/go/+/493606
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
Diffstat (limited to 'src/cmd')
-rw-r--r-- | src/cmd/dist/test.go | 7 | ||||
-rw-r--r-- | src/cmd/internal/bootstrap_test/experiment_toolid_test.go | 102 | ||||
-rw-r--r-- | src/cmd/internal/bootstrap_test/overlaydir_test.go | 85 | ||||
-rw-r--r-- | src/cmd/internal/bootstrap_test/reboot_test.go | 98 |
4 files changed, 285 insertions, 7 deletions
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 6e77c7e07e..7ec10aecac 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -887,13 +887,6 @@ func (t *tester) registerTests() { if goos == "darwin" || ((goos == "linux" || goos == "windows") && goarch == "amd64") { t.registerTest("api", "", &goTest{dir: "cmd/api", timeout: 5 * time.Minute, testFlags: []string{"-check"}}) } - - // 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. - // Not meaningful on wasm/js or wasm/wasip1. - if os.Getenv("GO_BUILDER_NAME") != "" && goos != "android" && !t.iOS() && goos != "js" && goos != "wasip1" { - t.registerTest("reboot", "", &goTest{dir: "../misc/reboot", timeout: 5 * time.Minute}) - } } // isRegisteredTestName reports whether a test named testName has already diff --git a/src/cmd/internal/bootstrap_test/experiment_toolid_test.go b/src/cmd/internal/bootstrap_test/experiment_toolid_test.go new file mode 100644 index 0000000000..cc60509ecb --- /dev/null +++ b/src/cmd/internal/bootstrap_test/experiment_toolid_test.go @@ -0,0 +1,102 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build explicit +// +build explicit + +// This test verifies that GOEXPERIMENT settings built +// into the toolchain influence tool ids in the Go command. +// This test requires bootstrapping the toolchain twice, so it's very expensive. +// It must be run explicitly with -tags=explicit. +// Verifies golang.org/issue/33091. + +package bootstrap_test + +import ( + "bytes" + "os" + "os/exec" + "path/filepath" + "runtime" + "testing" +) + +func TestExperimentToolID(t *testing.T) { + // Set up GOROOT + goroot, err := os.MkdirTemp("", "experiment-goroot") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(goroot) + + gorootSrc := filepath.Join(goroot, "src") + if err := overlayDir(gorootSrc, filepath.Join(runtime.GOROOT(), "src")); err != nil { + t.Fatal(err) + } + + if err := os.WriteFile(filepath.Join(goroot, "VERSION"), []byte("go1.999"), 0666); err != nil { + t.Fatal(err) + } + env := append(os.Environ(), "GOROOT=", "GOROOT_BOOTSTRAP="+runtime.GOROOT()) + + // Use a clean cache. + gocache, err := os.MkdirTemp("", "experiment-gocache") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(gocache) + env = append(env, "GOCACHE="+gocache) + + // Build the toolchain without GOEXPERIMENT. + var makeScript string + switch runtime.GOOS { + case "windows": + makeScript = "make.bat" + case "plan9": + makeScript = "make.rc" + default: + makeScript = "make.bash" + } + makeScriptPath := filepath.Join(runtime.GOROOT(), "src", makeScript) + runCmd(t, gorootSrc, env, makeScriptPath) + + // Verify compiler version string. + goCmdPath := filepath.Join(goroot, "bin", "go") + if runtime.GOOS == "windows" { + goCmdPath += ".exe" + } + gotVersion := bytes.TrimSpace(runCmd(t, gorootSrc, env, goCmdPath, "tool", "compile", "-V=full")) + wantVersion := []byte(`compile version go1.999`) + if !bytes.Equal(gotVersion, wantVersion) { + t.Errorf("compile version without experiment: got %q, want %q", gotVersion, wantVersion) + } + + // Build a package in a mode not handled by the make script. + runCmd(t, gorootSrc, env, goCmdPath, "build", "-race", "archive/tar") + + // Rebuild the toolchain with GOEXPERIMENT. + env = append(env, "GOEXPERIMENT=fieldtrack") + runCmd(t, gorootSrc, env, makeScriptPath) + + // Verify compiler version string. + gotVersion = bytes.TrimSpace(runCmd(t, gorootSrc, env, goCmdPath, "tool", "compile", "-V=full")) + wantVersion = []byte(`compile version go1.999 X:fieldtrack,framepointer`) + if !bytes.Equal(gotVersion, wantVersion) { + t.Errorf("compile version with experiment: got %q, want %q", gotVersion, wantVersion) + } + + // Build the same package. We should not get a cache conflict. + runCmd(t, gorootSrc, env, goCmdPath, "build", "-race", "archive/tar") +} + +func runCmd(t *testing.T, dir string, env []string, path string, args ...string) []byte { + cmd := exec.Command(path, args...) + cmd.Dir = dir + cmd.Env = env + out, err := cmd.Output() + if err != nil { + t.Fatal(err) + } + return out +} diff --git a/src/cmd/internal/bootstrap_test/overlaydir_test.go b/src/cmd/internal/bootstrap_test/overlaydir_test.go new file mode 100644 index 0000000000..5812c453ac --- /dev/null +++ b/src/cmd/internal/bootstrap_test/overlaydir_test.go @@ -0,0 +1,85 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bootstrap_test + +import ( + "io" + "io/fs" + "os" + "path/filepath" + "strings" +) + +// overlayDir makes a minimal-overhead copy of srcRoot in which new files may be added. +// +// TODO: Once we no longer need to support the misc module in GOPATH mode, +// factor this function out into a package to reduce duplication. +func overlayDir(dstRoot, srcRoot string) error { + dstRoot = filepath.Clean(dstRoot) + if err := os.MkdirAll(dstRoot, 0777); err != nil { + return err + } + + srcRoot, err := filepath.Abs(srcRoot) + if err != nil { + return err + } + + return filepath.WalkDir(srcRoot, func(srcPath string, entry fs.DirEntry, err error) error { + if err != nil || srcPath == srcRoot { + return err + } + if filepath.Base(srcPath) == "testdata" { + // We're just building, so no need to copy those. + return fs.SkipDir + } + + suffix := strings.TrimPrefix(srcPath, srcRoot) + for len(suffix) > 0 && suffix[0] == filepath.Separator { + suffix = suffix[1:] + } + dstPath := filepath.Join(dstRoot, suffix) + + info, err := entry.Info() + perm := info.Mode() & os.ModePerm + if info.Mode()&os.ModeSymlink != 0 { + info, err = os.Stat(srcPath) + if err != nil { + return err + } + perm = info.Mode() & os.ModePerm + } + + // Always make copies of directories. + // If we add a file in the overlay, we don't want to add it in the original. + if info.IsDir() { + return os.MkdirAll(dstPath, perm|0200) + } + + // If we can use a hard link, do that instead of copying bytes. + // Go builds don't like symlinks in some cases, such as go:embed. + if err := os.Link(srcPath, dstPath); err == nil { + return nil + } + + // Otherwise, copy the bytes. + src, err := os.Open(srcPath) + if err != nil { + return err + } + defer src.Close() + + dst, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm) + if err != nil { + return err + } + + _, err = io.Copy(dst, src) + if closeErr := dst.Close(); err == nil { + err = closeErr + } + return err + }) +} diff --git a/src/cmd/internal/bootstrap_test/reboot_test.go b/src/cmd/internal/bootstrap_test/reboot_test.go new file mode 100644 index 0000000000..eca024fa89 --- /dev/null +++ b/src/cmd/internal/bootstrap_test/reboot_test.go @@ -0,0 +1,98 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package bootstrap_test verifies that the current GOROOT can be used to bootstrap +// itself. +package bootstrap_test + +import ( + "fmt" + "internal/testenv" + "io" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" + "time" +) + +func TestRepeatBootstrap(t *testing.T) { + if testing.Short() { + t.Skipf("skipping test that rebuilds the entire toolchain") + } + switch runtime.GOOS { + case "android", "ios", "js", "wasip1": + t.Skipf("skipping because the toolchain does not have to bootstrap on GOOS=%s", runtime.GOOS) + } + + realGoroot := testenv.GOROOT(t) + + // To ensure that bootstrapping doesn't unexpectedly depend + // on the Go repo's git metadata, add a fake (unreadable) git + // directory above the simulated GOROOT. + // This mimics the configuration one much have when + // building from distro-packaged source code + // (see https://go.dev/issue/54852). + parent := t.TempDir() + dotGit := filepath.Join(parent, ".git") + if err := os.Mkdir(dotGit, 000); err != nil { + t.Fatal(err) + } + + overlayStart := time.Now() + + goroot := filepath.Join(parent, "goroot") + + gorootSrc := filepath.Join(goroot, "src") + if err := overlayDir(gorootSrc, filepath.Join(realGoroot, "src")); err != nil { + t.Fatal(err) + } + + gorootLib := filepath.Join(goroot, "lib") + if err := overlayDir(gorootLib, filepath.Join(realGoroot, "lib")); err != nil { + t.Fatal(err) + } + + t.Logf("GOROOT overlay set up in %s", time.Since(overlayStart)) + + if err := os.WriteFile(filepath.Join(goroot, "VERSION"), []byte(runtime.Version()), 0666); err != nil { + t.Fatal(err) + } + + var makeScript string + switch runtime.GOOS { + case "windows": + makeScript = "make.bat" + case "plan9": + makeScript = "make.rc" + default: + makeScript = "make.bash" + } + + var stdout strings.Builder + cmd := exec.Command(filepath.Join(goroot, "src", makeScript)) + cmd.Dir = gorootSrc + cmd.Env = append(cmd.Environ(), "GOROOT=", "GOROOT_FINAL=", "GOROOT_BOOTSTRAP="+realGoroot) + cmd.Stderr = os.Stderr + cmd.Stdout = io.MultiWriter(os.Stdout, &stdout) + if err := cmd.Run(); err != nil { + t.Fatal(err) + } + + // Test that go.dev/issue/42563 hasn't regressed. + t.Run("PATH reminder", func(t *testing.T) { + var want string + switch gorootBin := filepath.Join(goroot, "bin"); runtime.GOOS { + default: + want = fmt.Sprintf("*** You need to add %s to your PATH.", gorootBin) + case "plan9": + want = fmt.Sprintf("*** You need to bind %s before /bin.", gorootBin) + } + if got := stdout.String(); !strings.Contains(got, want) { + t.Errorf("reminder %q is missing from %s stdout:\n%s", want, makeScript, got) + } + }) +} |