github.com/c12o16h1/go/src@v0.0.0-20200114212001-5a151c0f00ed/internal/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 "errors" 15 "flag" 16 "github.com/c12o16h1/go/src/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", "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 "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 "darwin": 139 if strings.HasPrefix(runtime.GOARCH, "arm") { 140 return false 141 } 142 } 143 return true 144 } 145 146 // MustHaveExec checks that the current system can start new processes 147 // using os.StartProcess or (more commonly) exec.Command. 148 // If not, MustHaveExec calls t.Skip with an explanation. 149 func MustHaveExec(t testing.TB) { 150 if !HasExec() { 151 t.Skipf("skipping test: cannot exec subprocess on %s/%s", runtime.GOOS, runtime.GOARCH) 152 } 153 } 154 155 var execPaths sync.Map // path -> error 156 157 // MustHaveExecPath checks that the current system can start the named executable 158 // using os.StartProcess or (more commonly) exec.Command. 159 // If not, MustHaveExecPath calls t.Skip with an explanation. 160 func MustHaveExecPath(t testing.TB, path string) { 161 MustHaveExec(t) 162 163 err, found := execPaths.Load(path) 164 if !found { 165 _, err = exec.LookPath(path) 166 err, _ = execPaths.LoadOrStore(path, err) 167 } 168 if err != nil { 169 t.Skipf("skipping test: %s: %s", path, err) 170 } 171 } 172 173 // HasExternalNetwork reports whether the current system can use 174 // external (non-localhost) networks. 175 func HasExternalNetwork() bool { 176 return !testing.Short() && runtime.GOOS != "js" 177 } 178 179 // MustHaveExternalNetwork checks that the current system can use 180 // external (non-localhost) networks. 181 // If not, MustHaveExternalNetwork calls t.Skip with an explanation. 182 func MustHaveExternalNetwork(t testing.TB) { 183 if runtime.GOOS == "js" { 184 t.Skipf("skipping test: no external network on %s", runtime.GOOS) 185 } 186 if testing.Short() { 187 t.Skipf("skipping test: no external network in -short mode") 188 } 189 } 190 191 var haveCGO bool 192 193 // HasCGO reports whether the current system can use cgo. 194 func HasCGO() bool { 195 return haveCGO 196 } 197 198 // MustHaveCGO calls t.Skip if cgo is not available. 199 func MustHaveCGO(t testing.TB) { 200 if !haveCGO { 201 t.Skipf("skipping test: no cgo") 202 } 203 } 204 205 // HasSymlink reports whether the current system can use os.Symlink. 206 func HasSymlink() bool { 207 ok, _ := hasSymlink() 208 return ok 209 } 210 211 // MustHaveSymlink reports whether the current system can use os.Symlink. 212 // If not, MustHaveSymlink calls t.Skip with an explanation. 213 func MustHaveSymlink(t testing.TB) { 214 ok, reason := hasSymlink() 215 if !ok { 216 t.Skipf("skipping test: cannot make symlinks on %s/%s%s", runtime.GOOS, runtime.GOARCH, reason) 217 } 218 } 219 220 // HasLink reports whether the current system can use os.Link. 221 func HasLink() bool { 222 // From Android release M (Marshmallow), hard linking files is blocked 223 // and an attempt to call link() on a file will return EACCES. 224 // - https://code.google.com/p/android-developer-preview/issues/detail?id=3150 225 return runtime.GOOS != "plan9" && runtime.GOOS != "android" 226 } 227 228 // MustHaveLink reports whether the current system can use os.Link. 229 // If not, MustHaveLink calls t.Skip with an explanation. 230 func MustHaveLink(t testing.TB) { 231 if !HasLink() { 232 t.Skipf("skipping test: hardlinks are not supported on %s/%s", runtime.GOOS, runtime.GOARCH) 233 } 234 } 235 236 var flaky = flag.Bool("flaky", false, "run known-flaky tests too") 237 238 func SkipFlaky(t testing.TB, issue int) { 239 t.Helper() 240 if !*flaky { 241 t.Skipf("skipping known flaky test without the -flaky flag; see golang.org/issue/%d", issue) 242 } 243 } 244 245 func SkipFlakyNet(t testing.TB) { 246 t.Helper() 247 if v, _ := strconv.ParseBool(os.Getenv("GO_BUILDER_FLAKY_NET")); v { 248 t.Skip("skipping test on builder known to have frequent network failures") 249 } 250 } 251 252 // CleanCmdEnv will fill cmd.Env with the environment, excluding certain 253 // variables that could modify the behavior of the Go tools such as 254 // GODEBUG and GOTRACEBACK. 255 func CleanCmdEnv(cmd *exec.Cmd) *exec.Cmd { 256 if cmd.Env != nil { 257 panic("environment already set") 258 } 259 for _, env := range os.Environ() { 260 // Exclude GODEBUG from the environment to prevent its output 261 // from breaking tests that are trying to parse other command output. 262 if strings.HasPrefix(env, "GODEBUG=") { 263 continue 264 } 265 // Exclude GOTRACEBACK for the same reason. 266 if strings.HasPrefix(env, "GOTRACEBACK=") { 267 continue 268 } 269 cmd.Env = append(cmd.Env, env) 270 } 271 return cmd 272 }