Source file src/cmd/internal/bootstrap_test/experiment_toolid_test.go

     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  //go:build explicit
     6  
     7  package bootstrap_test
     8  
     9  import (
    10  	"bytes"
    11  	"errors"
    12  	"internal/testenv"
    13  	"os"
    14  	"os/exec"
    15  	"path/filepath"
    16  	"runtime"
    17  	"testing"
    18  )
    19  
    20  // TestExperimentToolID verifies that GOEXPERIMENT settings built
    21  // into the toolchain influence tool ids in the Go command.
    22  // This test requires bootstrapping the toolchain twice, so it's very expensive.
    23  // It must be run explicitly with -tags=explicit.
    24  // Verifies go.dev/issue/33091.
    25  func TestExperimentToolID(t *testing.T) {
    26  	if testing.Short() {
    27  		t.Skip("skipping test that rebuilds the entire toolchain twice")
    28  	}
    29  	switch runtime.GOOS {
    30  	case "android", "ios", "js", "wasip1":
    31  		t.Skipf("skipping because the toolchain does not have to bootstrap on GOOS=%s", runtime.GOOS)
    32  	}
    33  
    34  	realGoroot := testenv.GOROOT(t)
    35  
    36  	// Set up GOROOT.
    37  	goroot := t.TempDir()
    38  	gorootSrc := filepath.Join(goroot, "src")
    39  	if err := overlayDir(gorootSrc, filepath.Join(realGoroot, "src")); err != nil {
    40  		t.Fatal(err)
    41  	}
    42  	gorootLib := filepath.Join(goroot, "lib")
    43  	if err := overlayDir(gorootLib, filepath.Join(realGoroot, "lib")); err != nil {
    44  		t.Fatal(err)
    45  	}
    46  	if err := os.WriteFile(filepath.Join(goroot, "VERSION"), []byte("go1.999"), 0666); err != nil {
    47  		t.Fatal(err)
    48  	}
    49  	env := append(os.Environ(), "GOROOT=", "GOROOT_BOOTSTRAP="+realGoroot)
    50  
    51  	// Use a clean cache.
    52  	gocache := t.TempDir()
    53  	env = append(env, "GOCACHE="+gocache)
    54  
    55  	// Build the toolchain without GOEXPERIMENT.
    56  	var makeScript string
    57  	switch runtime.GOOS {
    58  	case "windows":
    59  		makeScript = "make.bat"
    60  	case "plan9":
    61  		makeScript = "make.rc"
    62  	default:
    63  		makeScript = "make.bash"
    64  	}
    65  	makeScriptPath := filepath.Join(realGoroot, "src", makeScript)
    66  	runCmd(t, gorootSrc, env, makeScriptPath)
    67  
    68  	// Verify compiler version string.
    69  	goCmdPath := filepath.Join(goroot, "bin", "go")
    70  	gotVersion := bytes.TrimSpace(runCmd(t, gorootSrc, env, goCmdPath, "tool", "compile", "-V=full"))
    71  	wantVersion := []byte(`compile version go1.999`)
    72  	if !bytes.Equal(gotVersion, wantVersion) {
    73  		t.Errorf("compile version without experiment is unexpected:\ngot  %q\nwant %q", gotVersion, wantVersion)
    74  	}
    75  
    76  	// Build a package in a mode not handled by the make script.
    77  	runCmd(t, gorootSrc, env, goCmdPath, "build", "-race", "archive/tar")
    78  
    79  	// Rebuild the toolchain with GOEXPERIMENT.
    80  	env = append(env, "GOEXPERIMENT=fieldtrack")
    81  	runCmd(t, gorootSrc, env, makeScriptPath)
    82  
    83  	// Verify compiler version string.
    84  	gotVersion = bytes.TrimSpace(runCmd(t, gorootSrc, env, goCmdPath, "tool", "compile", "-V=full"))
    85  	wantVersion = []byte(`compile version go1.999 X:fieldtrack`)
    86  	if !bytes.Equal(gotVersion, wantVersion) {
    87  		t.Errorf("compile version with experiment is unexpected:\ngot  %q\nwant %q", gotVersion, wantVersion)
    88  	}
    89  
    90  	// Build the same package. We should not get a cache conflict.
    91  	runCmd(t, gorootSrc, env, goCmdPath, "build", "-race", "archive/tar")
    92  }
    93  
    94  func runCmd(t *testing.T, dir string, env []string, path string, args ...string) []byte {
    95  	cmd := exec.Command(path, args...)
    96  	cmd.Dir = dir
    97  	cmd.Env = env
    98  	out, err := cmd.Output()
    99  	if err != nil {
   100  		if ee := (*exec.ExitError)(nil); errors.As(err, &ee) {
   101  			out = append(out, ee.Stderr...)
   102  		}
   103  		t.Fatalf("%s failed:\n%s\n%s", cmd, out, err)
   104  	}
   105  	return out
   106  }
   107  

View as plain text