aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2023-05-08 16:31:23 -0400
committerAustin Clements <austin@google.com>2023-05-12 12:35:05 +0000
commit3943fc14d35c117f2256fb789743d9f075c9aba5 (patch)
treefc282062b14c176950da4f672202e9b922ea1395 /src/cmd
parentb26c3927bd9b250715a7f8652b3cd5c16475ff07 (diff)
downloadgo-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.go7
-rw-r--r--src/cmd/internal/bootstrap_test/experiment_toolid_test.go102
-rw-r--r--src/cmd/internal/bootstrap_test/overlaydir_test.go85
-rw-r--r--src/cmd/internal/bootstrap_test/reboot_test.go98
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)
+ }
+ })
+}