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 }