...

Source file src/pkg/internal/testenv/testenv.go

     1	// Copyright 2015 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 testenv provides information about what functionality
     6	// is available in different testing environments run by the Go team.
     7	//
     8	// It is an internal package because these details are specific
     9	// to the Go team's test setup (on build.golang.org) and not
    10	// fundamental to tests in general.
    11	package testenv
    12	
    13	import (
    14		"errors"
    15		"flag"
    16		"internal/cfg"
    17		"os"
    18		"os/exec"
    19		"path/filepath"
    20		"runtime"
    21		"strconv"
    22		"strings"
    23		"sync"
    24		"testing"
    25	)
    26	
    27	// Builder reports the name of the builder running this test
    28	// (for example, "linux-amd64" or "windows-386-gce").
    29	// If the test is not running on the build infrastructure,
    30	// Builder returns the empty string.
    31	func Builder() string {
    32		return os.Getenv("GO_BUILDER_NAME")
    33	}
    34	
    35	// HasGoBuild reports whether the current system can build programs with ``go build''
    36	// and then run them with os.StartProcess or exec.Command.
    37	func HasGoBuild() bool {
    38		if os.Getenv("GO_GCFLAGS") != "" {
    39			// It's too much work to require every caller of the go command
    40			// to pass along "-gcflags="+os.Getenv("GO_GCFLAGS").
    41			// For now, if $GO_GCFLAGS is set, report that we simply can't
    42			// run go build.
    43			return false
    44		}
    45		switch runtime.GOOS {
    46		case "android", "nacl", "js":
    47			return false
    48		case "darwin":
    49			if strings.HasPrefix(runtime.GOARCH, "arm") {
    50				return false
    51			}
    52		}
    53		return true
    54	}
    55	
    56	// MustHaveGoBuild checks that the current system can build programs with ``go build''
    57	// and then run them with os.StartProcess or exec.Command.
    58	// If not, MustHaveGoBuild calls t.Skip with an explanation.
    59	func MustHaveGoBuild(t testing.TB) {
    60		if os.Getenv("GO_GCFLAGS") != "" {
    61			t.Skipf("skipping test: 'go build' not compatible with setting $GO_GCFLAGS")
    62		}
    63		if !HasGoBuild() {
    64			t.Skipf("skipping test: 'go build' not available on %s/%s", runtime.GOOS, runtime.GOARCH)
    65		}
    66	}
    67	
    68	// HasGoRun reports whether the current system can run programs with ``go run.''
    69	func HasGoRun() bool {
    70		// For now, having go run and having go build are the same.
    71		return HasGoBuild()
    72	}
    73	
    74	// MustHaveGoRun checks that the current system can run programs with ``go run.''
    75	// If not, MustHaveGoRun calls t.Skip with an explanation.
    76	func MustHaveGoRun(t testing.TB) {
    77		if !HasGoRun() {
    78			t.Skipf("skipping test: 'go run' not available on %s/%s", runtime.GOOS, runtime.GOARCH)
    79		}
    80	}
    81	
    82	// GoToolPath reports the path to the Go tool.
    83	// It is a convenience wrapper around GoTool.
    84	// If the tool is unavailable GoToolPath calls t.Skip.
    85	// If the tool should be available and isn't, GoToolPath calls t.Fatal.
    86	func GoToolPath(t testing.TB) string {
    87		MustHaveGoBuild(t)
    88		path, err := GoTool()
    89		if err != nil {
    90			t.Fatal(err)
    91		}
    92		// Add all environment variables that affect the Go command to test metadata.
    93		// Cached test results will be invalidate when these variables change.
    94		// See golang.org/issue/32285.
    95		for _, envVar := range strings.Fields(cfg.KnownEnv) {
    96			os.Getenv(envVar)
    97		}
    98		return path
    99	}
   100	
   101	// GoTool reports the path to the Go tool.
   102	func GoTool() (string, error) {
   103		if !HasGoBuild() {
   104			return "", errors.New("platform cannot run go tool")
   105		}
   106		var exeSuffix string
   107		if runtime.GOOS == "windows" {
   108			exeSuffix = ".exe"
   109		}
   110		path := filepath.Join(runtime.GOROOT(), "bin", "go"+exeSuffix)
   111		if _, err := os.Stat(path); err == nil {
   112			return path, nil
   113		}
   114		goBin, err := exec.LookPath("go" + exeSuffix)
   115		if err != nil {
   116			return "", errors.New("cannot find go tool: " + err.Error())
   117		}
   118		return goBin, nil
   119	}
   120	
   121	// HasExec reports whether the current system can start new processes
   122	// using os.StartProcess or (more commonly) exec.Command.
   123	func HasExec() bool {
   124		switch runtime.GOOS {
   125		case "nacl", "js":
   126			return false
   127		case "darwin":
   128			if strings.HasPrefix(runtime.GOARCH, "arm") {
   129				return false
   130			}
   131		}
   132		return true
   133	}
   134	
   135	// HasSrc reports whether the entire source tree is available under GOROOT.
   136	func HasSrc() bool {
   137		switch runtime.GOOS {
   138		case "nacl":
   139			return false
   140		case "darwin":
   141			if strings.HasPrefix(runtime.GOARCH, "arm") {
   142				return false
   143			}
   144		}
   145		return true
   146	}
   147	
   148	// MustHaveExec checks that the current system can start new processes
   149	// using os.StartProcess or (more commonly) exec.Command.
   150	// If not, MustHaveExec calls t.Skip with an explanation.
   151	func MustHaveExec(t testing.TB) {
   152		if !HasExec() {
   153			t.Skipf("skipping test: cannot exec subprocess on %s/%s", runtime.GOOS, runtime.GOARCH)
   154		}
   155	}
   156	
   157	var execPaths sync.Map // path -> error
   158	
   159	// MustHaveExecPath checks that the current system can start the named executable
   160	// using os.StartProcess or (more commonly) exec.Command.
   161	// If not, MustHaveExecPath calls t.Skip with an explanation.
   162	func MustHaveExecPath(t testing.TB, path string) {
   163		MustHaveExec(t)
   164	
   165		err, found := execPaths.Load(path)
   166		if !found {
   167			_, err = exec.LookPath(path)
   168			err, _ = execPaths.LoadOrStore(path, err)
   169		}
   170		if err != nil {
   171			t.Skipf("skipping test: %s: %s", path, err)
   172		}
   173	}
   174	
   175	// HasExternalNetwork reports whether the current system can use
   176	// external (non-localhost) networks.
   177	func HasExternalNetwork() bool {
   178		return !testing.Short() && runtime.GOOS != "nacl" && runtime.GOOS != "js"
   179	}
   180	
   181	// MustHaveExternalNetwork checks that the current system can use
   182	// external (non-localhost) networks.
   183	// If not, MustHaveExternalNetwork calls t.Skip with an explanation.
   184	func MustHaveExternalNetwork(t testing.TB) {
   185		if runtime.GOOS == "nacl" || runtime.GOOS == "js" {
   186			t.Skipf("skipping test: no external network on %s", runtime.GOOS)
   187		}
   188		if testing.Short() {
   189			t.Skipf("skipping test: no external network in -short mode")
   190		}
   191	}
   192	
   193	var haveCGO bool
   194	
   195	// HasCGO reports whether the current system can use cgo.
   196	func HasCGO() bool {
   197		return haveCGO
   198	}
   199	
   200	// MustHaveCGO calls t.Skip if cgo is not available.
   201	func MustHaveCGO(t testing.TB) {
   202		if !haveCGO {
   203			t.Skipf("skipping test: no cgo")
   204		}
   205	}
   206	
   207	// HasSymlink reports whether the current system can use os.Symlink.
   208	func HasSymlink() bool {
   209		ok, _ := hasSymlink()
   210		return ok
   211	}
   212	
   213	// MustHaveSymlink reports whether the current system can use os.Symlink.
   214	// If not, MustHaveSymlink calls t.Skip with an explanation.
   215	func MustHaveSymlink(t testing.TB) {
   216		ok, reason := hasSymlink()
   217		if !ok {
   218			t.Skipf("skipping test: cannot make symlinks on %s/%s%s", runtime.GOOS, runtime.GOARCH, reason)
   219		}
   220	}
   221	
   222	// HasLink reports whether the current system can use os.Link.
   223	func HasLink() bool {
   224		// From Android release M (Marshmallow), hard linking files is blocked
   225		// and an attempt to call link() on a file will return EACCES.
   226		// - https://code.google.com/p/android-developer-preview/issues/detail?id=3150
   227		return runtime.GOOS != "plan9" && runtime.GOOS != "android"
   228	}
   229	
   230	// MustHaveLink reports whether the current system can use os.Link.
   231	// If not, MustHaveLink calls t.Skip with an explanation.
   232	func MustHaveLink(t testing.TB) {
   233		if !HasLink() {
   234			t.Skipf("skipping test: hardlinks are not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   235		}
   236	}
   237	
   238	var flaky = flag.Bool("flaky", false, "run known-flaky tests too")
   239	
   240	func SkipFlaky(t testing.TB, issue int) {
   241		t.Helper()
   242		if !*flaky {
   243			t.Skipf("skipping known flaky test without the -flaky flag; see golang.org/issue/%d", issue)
   244		}
   245	}
   246	
   247	func SkipFlakyNet(t testing.TB) {
   248		t.Helper()
   249		if v, _ := strconv.ParseBool(os.Getenv("GO_BUILDER_FLAKY_NET")); v {
   250			t.Skip("skipping test on builder known to have frequent network failures")
   251		}
   252	}
   253	
   254	// CleanCmdEnv will fill cmd.Env with the environment, excluding certain
   255	// variables that could modify the behavior of the Go tools such as
   256	// GODEBUG and GOTRACEBACK.
   257	func CleanCmdEnv(cmd *exec.Cmd) *exec.Cmd {
   258		if cmd.Env != nil {
   259			panic("environment already set")
   260		}
   261		for _, env := range os.Environ() {
   262			// Exclude GODEBUG from the environment to prevent its output
   263			// from breaking tests that are trying to parse other command output.
   264			if strings.HasPrefix(env, "GODEBUG=") {
   265				continue
   266			}
   267			// Exclude GOTRACEBACK for the same reason.
   268			if strings.HasPrefix(env, "GOTRACEBACK=") {
   269				continue
   270			}
   271			cmd.Env = append(cmd.Env, env)
   272		}
   273		return cmd
   274	}
   275	

View as plain text