github.com/3andne/restls-client-go@v0.1.6/testenv/testenv.go (about)

     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  	"bytes"
    15  	"errors"
    16  	"flag"
    17  	"os"
    18  	"os/exec"
    19  	"path/filepath"
    20  	"runtime"
    21  	"strconv"
    22  	"strings"
    23  	"sync"
    24  	"testing"
    25  	"time"
    26  )
    27  
    28  const KnownEnv = `
    29  	AR
    30  	CC
    31  	CGO_CFLAGS
    32  	CGO_CFLAGS_ALLOW
    33  	CGO_CFLAGS_DISALLOW
    34  	CGO_CPPFLAGS
    35  	CGO_CPPFLAGS_ALLOW
    36  	CGO_CPPFLAGS_DISALLOW
    37  	CGO_CXXFLAGS
    38  	CGO_CXXFLAGS_ALLOW
    39  	CGO_CXXFLAGS_DISALLOW
    40  	CGO_ENABLED
    41  	CGO_FFLAGS
    42  	CGO_FFLAGS_ALLOW
    43  	CGO_FFLAGS_DISALLOW
    44  	CGO_LDFLAGS
    45  	CGO_LDFLAGS_ALLOW
    46  	CGO_LDFLAGS_DISALLOW
    47  	CXX
    48  	FC
    49  	GCCGO
    50  	GO111MODULE
    51  	GO386
    52  	GOAMD64
    53  	GOARCH
    54  	GOARM
    55  	GOBIN
    56  	GOCACHE
    57  	GOENV
    58  	GOEXE
    59  	GOEXPERIMENT
    60  	GOFLAGS
    61  	GOGCCFLAGS
    62  	GOHOSTARCH
    63  	GOHOSTOS
    64  	GOINSECURE
    65  	GOMIPS
    66  	GOMIPS64
    67  	GOMODCACHE
    68  	GONOPROXY
    69  	GONOSUMDB
    70  	GOOS
    71  	GOPATH
    72  	GOPPC64
    73  	GOPRIVATE
    74  	GOPROXY
    75  	GOROOT
    76  	GOSUMDB
    77  	GOTMPDIR
    78  	GOTOOLDIR
    79  	GOVCS
    80  	GOWASM
    81  	GOWORK
    82  	GO_EXTLINK_ENABLED
    83  	PKG_CONFIG
    84  `
    85  
    86  // Builder reports the name of the builder running this test
    87  // (for example, "linux-amd64" or "windows-386-gce").
    88  // If the test is not running on the build infrastructure,
    89  // Builder returns the empty string.
    90  func Builder() string {
    91  	return os.Getenv("GO_BUILDER_NAME")
    92  }
    93  
    94  // HasGoBuild reports whether the current system can build programs with ``go build''
    95  // and then run them with os.StartProcess or exec.Command.
    96  func HasGoBuild() bool {
    97  	if os.Getenv("GO_GCFLAGS") != "" {
    98  		// It's too much work to require every caller of the go command
    99  		// to pass along "-gcflags="+os.Getenv("GO_GCFLAGS").
   100  		// For now, if $GO_GCFLAGS is set, report that we simply can't
   101  		// run go build.
   102  		return false
   103  	}
   104  	switch runtime.GOOS {
   105  	case "android", "js", "ios":
   106  		return false
   107  	}
   108  	return true
   109  }
   110  
   111  // MustHaveGoBuild checks that the current system can build programs with ``go build''
   112  // and then run them with os.StartProcess or exec.Command.
   113  // If not, MustHaveGoBuild calls t.Skip with an explanation.
   114  func MustHaveGoBuild(t testing.TB) {
   115  	if os.Getenv("GO_GCFLAGS") != "" {
   116  		t.Skipf("skipping test: 'go build' not compatible with setting $GO_GCFLAGS")
   117  	}
   118  	if !HasGoBuild() {
   119  		t.Skipf("skipping test: 'go build' not available on %s/%s", runtime.GOOS, runtime.GOARCH)
   120  	}
   121  }
   122  
   123  // HasGoRun reports whether the current system can run programs with ``go run.''
   124  func HasGoRun() bool {
   125  	// For now, having go run and having go build are the same.
   126  	return HasGoBuild()
   127  }
   128  
   129  // MustHaveGoRun checks that the current system can run programs with ``go run.''
   130  // If not, MustHaveGoRun calls t.Skip with an explanation.
   131  func MustHaveGoRun(t testing.TB) {
   132  	if !HasGoRun() {
   133  		t.Skipf("skipping test: 'go run' not available on %s/%s", runtime.GOOS, runtime.GOARCH)
   134  	}
   135  }
   136  
   137  // GoToolPath reports the path to the Go tool.
   138  // It is a convenience wrapper around GoTool.
   139  // If the tool is unavailable GoToolPath calls t.Skip.
   140  // If the tool should be available and isn't, GoToolPath calls t.Fatal.
   141  func GoToolPath(t testing.TB) string {
   142  	MustHaveGoBuild(t)
   143  	path, err := GoTool()
   144  	if err != nil {
   145  		t.Fatal(err)
   146  	}
   147  	// Add all environment variables that affect the Go command to test metadata.
   148  	// Cached test results will be invalidate when these variables change.
   149  	// See golang.org/issue/32285.
   150  	for _, envVar := range strings.Fields(KnownEnv) {
   151  		os.Getenv(envVar)
   152  	}
   153  	return path
   154  }
   155  
   156  // GoTool reports the path to the Go tool.
   157  func GoTool() (string, error) {
   158  	if !HasGoBuild() {
   159  		return "", errors.New("platform cannot run go tool")
   160  	}
   161  	var exeSuffix string
   162  	if runtime.GOOS == "windows" {
   163  		exeSuffix = ".exe"
   164  	}
   165  	path := filepath.Join(runtime.GOROOT(), "bin", "go"+exeSuffix)
   166  	if _, err := os.Stat(path); err == nil {
   167  		return path, nil
   168  	}
   169  	goBin, err := exec.LookPath("go" + exeSuffix)
   170  	if err != nil {
   171  		return "", errors.New("cannot find go tool: " + err.Error())
   172  	}
   173  	return goBin, nil
   174  }
   175  
   176  // HasExec reports whether the current system can start new processes
   177  // using os.StartProcess or (more commonly) exec.Command.
   178  func HasExec() bool {
   179  	switch runtime.GOOS {
   180  	case "js", "ios":
   181  		return false
   182  	}
   183  	return true
   184  }
   185  
   186  // HasSrc reports whether the entire source tree is available under GOROOT.
   187  func HasSrc() bool {
   188  	switch runtime.GOOS {
   189  	case "ios":
   190  		return false
   191  	}
   192  	return true
   193  }
   194  
   195  // MustHaveExec checks that the current system can start new processes
   196  // using os.StartProcess or (more commonly) exec.Command.
   197  // If not, MustHaveExec calls t.Skip with an explanation.
   198  func MustHaveExec(t testing.TB) {
   199  	if !HasExec() {
   200  		t.Skipf("skipping test: cannot exec subprocess on %s/%s", runtime.GOOS, runtime.GOARCH)
   201  	}
   202  }
   203  
   204  var execPaths sync.Map // path -> error
   205  
   206  // MustHaveExecPath checks that the current system can start the named executable
   207  // using os.StartProcess or (more commonly) exec.Command.
   208  // If not, MustHaveExecPath calls t.Skip with an explanation.
   209  func MustHaveExecPath(t testing.TB, path string) {
   210  	MustHaveExec(t)
   211  
   212  	err, found := execPaths.Load(path)
   213  	if !found {
   214  		_, err = exec.LookPath(path)
   215  		err, _ = execPaths.LoadOrStore(path, err)
   216  	}
   217  	if err != nil {
   218  		t.Skipf("skipping test: %s: %s", path, err)
   219  	}
   220  }
   221  
   222  // HasExternalNetwork reports whether the current system can use
   223  // external (non-localhost) networks.
   224  func HasExternalNetwork() bool {
   225  	return !testing.Short() && runtime.GOOS != "js"
   226  }
   227  
   228  // MustHaveExternalNetwork checks that the current system can use
   229  // external (non-localhost) networks.
   230  // If not, MustHaveExternalNetwork calls t.Skip with an explanation.
   231  func MustHaveExternalNetwork(t testing.TB) {
   232  	if runtime.GOOS == "js" {
   233  		t.Skipf("skipping test: no external network on %s", runtime.GOOS)
   234  	}
   235  	if testing.Short() {
   236  		t.Skipf("skipping test: no external network in -short mode")
   237  	}
   238  }
   239  
   240  var haveCGO bool
   241  
   242  // HasCGO reports whether the current system can use cgo.
   243  func HasCGO() bool {
   244  	return haveCGO
   245  }
   246  
   247  // MustHaveCGO calls t.Skip if cgo is not available.
   248  func MustHaveCGO(t testing.TB) {
   249  	if !haveCGO {
   250  		t.Skipf("skipping test: no cgo")
   251  	}
   252  }
   253  
   254  // CanInternalLink reports whether the current system can link programs with
   255  // internal linking.
   256  // (This is the opposite of cmd/internal/sys.MustLinkExternal. Keep them in sync.)
   257  func CanInternalLink() bool {
   258  	switch runtime.GOOS {
   259  	case "android":
   260  		if runtime.GOARCH != "arm64" {
   261  			return false
   262  		}
   263  	case "ios":
   264  		if runtime.GOARCH == "arm64" {
   265  			return false
   266  		}
   267  	}
   268  	return true
   269  }
   270  
   271  // MustInternalLink checks that the current system can link programs with internal
   272  // linking.
   273  // If not, MustInternalLink calls t.Skip with an explanation.
   274  func MustInternalLink(t testing.TB) {
   275  	if !CanInternalLink() {
   276  		t.Skipf("skipping test: internal linking on %s/%s is not supported", runtime.GOOS, runtime.GOARCH)
   277  	}
   278  }
   279  
   280  // HasSymlink reports whether the current system can use os.Symlink.
   281  func HasSymlink() bool {
   282  	ok, _ := hasSymlink()
   283  	return ok
   284  }
   285  
   286  // MustHaveSymlink reports whether the current system can use os.Symlink.
   287  // If not, MustHaveSymlink calls t.Skip with an explanation.
   288  func MustHaveSymlink(t testing.TB) {
   289  	ok, reason := hasSymlink()
   290  	if !ok {
   291  		t.Skipf("skipping test: cannot make symlinks on %s/%s%s", runtime.GOOS, runtime.GOARCH, reason)
   292  	}
   293  }
   294  
   295  // HasLink reports whether the current system can use os.Link.
   296  func HasLink() bool {
   297  	// From Android release M (Marshmallow), hard linking files is blocked
   298  	// and an attempt to call link() on a file will return EACCES.
   299  	// - https://code.google.com/p/android-developer-preview/issues/detail?id=3150
   300  	return runtime.GOOS != "plan9" && runtime.GOOS != "android"
   301  }
   302  
   303  // MustHaveLink reports whether the current system can use os.Link.
   304  // If not, MustHaveLink calls t.Skip with an explanation.
   305  func MustHaveLink(t testing.TB) {
   306  	if !HasLink() {
   307  		t.Skipf("skipping test: hardlinks are not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   308  	}
   309  }
   310  
   311  var flaky = flag.Bool("flaky", false, "run known-flaky tests too")
   312  
   313  func SkipFlaky(t testing.TB, issue int) {
   314  	t.Helper()
   315  	if !*flaky {
   316  		t.Skipf("skipping known flaky test without the -flaky flag; see golang.org/issue/%d", issue)
   317  	}
   318  }
   319  
   320  func SkipFlakyNet(t testing.TB) {
   321  	t.Helper()
   322  	if v, _ := strconv.ParseBool(os.Getenv("GO_BUILDER_FLAKY_NET")); v {
   323  		t.Skip("skipping test on builder known to have frequent network failures")
   324  	}
   325  }
   326  
   327  // CleanCmdEnv will fill cmd.Env with the environment, excluding certain
   328  // variables that could modify the behavior of the Go tools such as
   329  // GODEBUG and GOTRACEBACK.
   330  func CleanCmdEnv(cmd *exec.Cmd) *exec.Cmd {
   331  	if cmd.Env != nil {
   332  		panic("environment already set")
   333  	}
   334  	for _, env := range os.Environ() {
   335  		// Exclude GODEBUG from the environment to prevent its output
   336  		// from breaking tests that are trying to parse other command output.
   337  		if strings.HasPrefix(env, "GODEBUG=") {
   338  			continue
   339  		}
   340  		// Exclude GOTRACEBACK for the same reason.
   341  		if strings.HasPrefix(env, "GOTRACEBACK=") {
   342  			continue
   343  		}
   344  		cmd.Env = append(cmd.Env, env)
   345  	}
   346  	return cmd
   347  }
   348  
   349  // CPUIsSlow reports whether the CPU running the test is suspected to be slow.
   350  func CPUIsSlow() bool {
   351  	switch runtime.GOARCH {
   352  	case "arm", "mips", "mipsle", "mips64", "mips64le":
   353  		return true
   354  	}
   355  	return false
   356  }
   357  
   358  // SkipIfShortAndSlow skips t if -short is set and the CPU running the test is
   359  // suspected to be slow.
   360  //
   361  // (This is useful for CPU-intensive tests that otherwise complete quickly.)
   362  func SkipIfShortAndSlow(t testing.TB) {
   363  	if testing.Short() && CPUIsSlow() {
   364  		t.Helper()
   365  		t.Skipf("skipping test in -short mode on %s", runtime.GOARCH)
   366  	}
   367  }
   368  
   369  // RunWithTimeout runs cmd and returns its combined output. If the
   370  // subprocess exits with a non-zero status, it will log that status
   371  // and return a non-nil error, but this is not considered fatal.
   372  func RunWithTimeout(t testing.TB, cmd *exec.Cmd) ([]byte, error) {
   373  	args := cmd.Args
   374  	if args == nil {
   375  		args = []string{cmd.Path}
   376  	}
   377  
   378  	var b bytes.Buffer
   379  	cmd.Stdout = &b
   380  	cmd.Stderr = &b
   381  	if err := cmd.Start(); err != nil {
   382  		t.Fatalf("starting %s: %v", args, err)
   383  	}
   384  
   385  	// If the process doesn't complete within 1 minute,
   386  	// assume it is hanging and kill it to get a stack trace.
   387  	p := cmd.Process
   388  	done := make(chan bool)
   389  	go func() {
   390  		scale := 1
   391  		// This GOARCH/GOOS test is copied from cmd/dist/test.go.
   392  		// TODO(iant): Have cmd/dist update the environment variable.
   393  		if runtime.GOARCH == "arm" || runtime.GOOS == "windows" {
   394  			scale = 2
   395  		}
   396  		if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
   397  			if sc, err := strconv.Atoi(s); err == nil {
   398  				scale = sc
   399  			}
   400  		}
   401  
   402  		select {
   403  		case <-done:
   404  		case <-time.After(time.Duration(scale) * time.Minute):
   405  			p.Signal(Sigquit)
   406  			// If SIGQUIT doesn't do it after a little
   407  			// while, kill the process.
   408  			select {
   409  			case <-done:
   410  			case <-time.After(time.Duration(scale) * 30 * time.Second):
   411  				p.Signal(os.Kill)
   412  			}
   413  		}
   414  	}()
   415  
   416  	err := cmd.Wait()
   417  	if err != nil {
   418  		t.Logf("%s exit status: %v", args, err)
   419  	}
   420  	close(done)
   421  
   422  	return b.Bytes(), err
   423  }