]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/cmd/go/go_test.go
[dev.boringcrypto] all: merge master into dev.boringcrypto
[gostls13.git] / src / cmd / go / go_test.go
index 11ba733b38166eed11f9c73c42fb5cddb1acd0fb..84fef6db7720d2a6f5d9ae1bf059dcf767f431e2 100644 (file)
@@ -14,7 +14,6 @@ import (
        "fmt"
        "go/format"
        "internal/godebug"
-       "internal/race"
        "internal/testenv"
        "io"
        "io/fs"
@@ -32,7 +31,11 @@ import (
        "cmd/go/internal/cache"
        "cmd/go/internal/cfg"
        "cmd/go/internal/robustio"
+       "cmd/go/internal/search"
+       "cmd/go/internal/work"
        "cmd/internal/sys"
+
+       cmdgo "cmd/go"
 )
 
 func init() {
@@ -84,6 +87,43 @@ var testBin string
 // The TestMain function creates a go command for testing purposes and
 // deletes it after the tests have been run.
 func TestMain(m *testing.M) {
+       // When CMDGO_TEST_RUN_MAIN is set, we're reusing the test binary as cmd/go.
+       // Enable the special behavior needed in cmd/go/internal/work,
+       // run the main func exported via export_test.go, and exit.
+       // We set CMDGO_TEST_RUN_MAIN via os.Setenv and testScript.setup.
+       if os.Getenv("CMDGO_TEST_RUN_MAIN") != "" {
+               if v := os.Getenv("TESTGO_VERSION"); v != "" {
+                       work.RuntimeVersion = v
+               }
+
+               if testGOROOT := os.Getenv("TESTGO_GOROOT"); testGOROOT != "" {
+                       // Disallow installs to the GOROOT from which testgo was built.
+                       // Installs to other GOROOTs — such as one set explicitly within a test — are ok.
+                       work.AllowInstall = func(a *work.Action) error {
+                               if cfg.BuildN {
+                                       return nil
+                               }
+
+                               rel := search.InDir(a.Target, testGOROOT)
+                               if rel == "" {
+                                       return nil
+                               }
+
+                               callerPos := ""
+                               if _, file, line, ok := runtime.Caller(1); ok {
+                                       if shortFile := search.InDir(file, filepath.Join(testGOROOT, "src")); shortFile != "" {
+                                               file = shortFile
+                                       }
+                                       callerPos = fmt.Sprintf("%s:%d: ", file, line)
+                               }
+                               return fmt.Errorf("%stestgo must not write to GOROOT (installing to %s)", callerPos, filepath.Join("GOROOT", rel))
+                       }
+               }
+               cmdgo.Main()
+               os.Exit(0)
+       }
+       os.Setenv("CMDGO_TEST_RUN_MAIN", "true")
+
        // $GO_GCFLAGS a compiler debug flag known to cmd/dist, make.bash, etc.
        // It is not a standard go command flag; use os.Getenv, not cfg.Getenv.
        if os.Getenv("GO_GCFLAGS") != "" {
@@ -127,10 +167,6 @@ func TestMain(m *testing.M) {
                        log.Fatal(err)
                }
                testGo = filepath.Join(testBin, "go"+exeSuffix)
-               args := []string{"build", "-tags", "testgo", "-o", testGo}
-               if race.Enabled {
-                       args = append(args, "-race")
-               }
                gotool, err := testenv.GoTool()
                if err != nil {
                        fmt.Fprintln(os.Stderr, "locating go tool: ", err)
@@ -173,12 +209,32 @@ func TestMain(m *testing.M) {
                        return
                }
 
-               buildCmd := exec.Command(gotool, args...)
-               buildCmd.Env = append(os.Environ(), "GOFLAGS=-mod=vendor")
-               out, err := buildCmd.CombinedOutput()
+               // Duplicate the test executable into the path at testGo, for $PATH.
+               // If the OS supports symlinks, use them instead of copying bytes.
+               testExe, err := os.Executable()
                if err != nil {
-                       fmt.Fprintf(os.Stderr, "building testgo failed: %v\n%s", err, out)
-                       os.Exit(2)
+                       log.Fatal(err)
+               }
+               if err := os.Symlink(testExe, testGo); err != nil {
+                       // Otherwise, copy the bytes.
+                       src, err := os.Open(testExe)
+                       if err != nil {
+                               log.Fatal(err)
+                       }
+                       defer src.Close()
+
+                       dst, err := os.OpenFile(testGo, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o777)
+                       if err != nil {
+                               log.Fatal(err)
+                       }
+
+                       _, err = io.Copy(dst, src)
+                       if closeErr := dst.Close(); err == nil {
+                               err = closeErr
+                       }
+                       if err != nil {
+                               log.Fatal(err)
+                       }
                }
 
                cmd := exec.Command(testGo, "env", "CGO_ENABLED")
@@ -193,7 +249,7 @@ func TestMain(m *testing.M) {
                        }
                }
 
-               out, err = exec.Command(gotool, "env", "GOCACHE").CombinedOutput()
+               out, err := exec.Command(gotool, "env", "GOCACHE").CombinedOutput()
                if err != nil {
                        fmt.Fprintf(os.Stderr, "could not find testing GOCACHE: %v\n%s", err, out)
                        os.Exit(2)
@@ -1575,7 +1631,7 @@ func TestListTemplateContextFunction(t *testing.T) {
        }{
                {"GOARCH", runtime.GOARCH},
                {"GOOS", runtime.GOOS},
-               {"GOROOT", filepath.Clean(runtime.GOROOT())},
+               {"GOROOT", testGOROOT},
                {"GOPATH", os.Getenv("GOPATH")},
                {"CgoEnabled", ""},
                {"UseAllFiles", ""},