1// Copyright 2019 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// Package bootstrap_test verifies that the current GOROOT can be used to bootstrap 6// itself. 7package bootstrap_test 8 9import ( 10 "fmt" 11 "internal/testenv" 12 "io" 13 "os" 14 "os/exec" 15 "path/filepath" 16 "runtime" 17 "strings" 18 "testing" 19 "time" 20) 21 22func TestRepeatBootstrap(t *testing.T) { 23 if testing.Short() { 24 t.Skip("skipping test that rebuilds the entire toolchain") 25 } 26 switch runtime.GOOS { 27 case "android", "ios", "js", "wasip1": 28 t.Skipf("skipping because the toolchain does not have to bootstrap on GOOS=%s", runtime.GOOS) 29 } 30 31 realGoroot := testenv.GOROOT(t) 32 33 // To ensure that bootstrapping doesn't unexpectedly depend 34 // on the Go repo's git metadata, add a fake (unreadable) git 35 // directory above the simulated GOROOT. 36 // This mimics the configuration one much have when 37 // building from distro-packaged source code 38 // (see https://go.dev/issue/54852). 39 parent := t.TempDir() 40 dotGit := filepath.Join(parent, ".git") 41 if err := os.Mkdir(dotGit, 000); err != nil { 42 t.Fatal(err) 43 } 44 45 overlayStart := time.Now() 46 47 goroot := filepath.Join(parent, "goroot") 48 49 gorootSrc := filepath.Join(goroot, "src") 50 if err := overlayDir(gorootSrc, filepath.Join(realGoroot, "src")); err != nil { 51 t.Fatal(err) 52 } 53 54 gorootLib := filepath.Join(goroot, "lib") 55 if err := overlayDir(gorootLib, filepath.Join(realGoroot, "lib")); err != nil { 56 t.Fatal(err) 57 } 58 59 t.Logf("GOROOT overlay set up in %s", time.Since(overlayStart)) 60 61 if err := os.WriteFile(filepath.Join(goroot, "VERSION"), []byte(runtime.Version()), 0666); err != nil { 62 t.Fatal(err) 63 } 64 65 var makeScript string 66 switch runtime.GOOS { 67 case "windows": 68 makeScript = "make.bat" 69 case "plan9": 70 makeScript = "make.rc" 71 default: 72 makeScript = "make.bash" 73 } 74 75 var stdout strings.Builder 76 cmd := exec.Command(filepath.Join(goroot, "src", makeScript)) 77 cmd.Dir = gorootSrc 78 cmd.Env = append(cmd.Environ(), "GOROOT=", "GOROOT_BOOTSTRAP="+realGoroot) 79 cmd.Stderr = os.Stderr 80 cmd.Stdout = io.MultiWriter(os.Stdout, &stdout) 81 if err := cmd.Run(); err != nil { 82 t.Fatal(err) 83 } 84 85 // Test that go.dev/issue/42563 hasn't regressed. 86 t.Run("PATH reminder", func(t *testing.T) { 87 var want string 88 switch gorootBin := filepath.Join(goroot, "bin"); runtime.GOOS { 89 default: 90 want = fmt.Sprintf("*** You need to add %s to your PATH.", gorootBin) 91 case "plan9": 92 want = fmt.Sprintf("*** You need to bind %s before /bin.", gorootBin) 93 } 94 if got := stdout.String(); !strings.Contains(got, want) { 95 t.Errorf("reminder %q is missing from %s stdout:\n%s", want, makeScript, got) 96 } 97 }) 98} 99