1
2
3
4
5
6
7
8
9
10
11 package testenv
12
13 import (
14 "bytes"
15 "errors"
16 "flag"
17 "internal/cfg"
18 "os"
19 "os/exec"
20 "path/filepath"
21 "runtime"
22 "strconv"
23 "strings"
24 "sync"
25 "testing"
26 "time"
27 )
28
29
30
31
32
33 func Builder() string {
34 return os.Getenv("GO_BUILDER_NAME")
35 }
36
37
38
39 func HasGoBuild() bool {
40 if os.Getenv("GO_GCFLAGS") != "" {
41
42
43
44
45 return false
46 }
47 switch runtime.GOOS {
48 case "android", "js", "ios":
49 return false
50 }
51 return true
52 }
53
54
55
56
57 func MustHaveGoBuild(t testing.TB) {
58 if os.Getenv("GO_GCFLAGS") != "" {
59 t.Skipf("skipping test: 'go build' not compatible with setting $GO_GCFLAGS")
60 }
61 if !HasGoBuild() {
62 t.Skipf("skipping test: 'go build' not available on %s/%s", runtime.GOOS, runtime.GOARCH)
63 }
64 }
65
66
67 func HasGoRun() bool {
68
69 return HasGoBuild()
70 }
71
72
73
74 func MustHaveGoRun(t testing.TB) {
75 if !HasGoRun() {
76 t.Skipf("skipping test: 'go run' not available on %s/%s", runtime.GOOS, runtime.GOARCH)
77 }
78 }
79
80
81
82
83
84 func GoToolPath(t testing.TB) string {
85 MustHaveGoBuild(t)
86 path, err := GoTool()
87 if err != nil {
88 t.Fatal(err)
89 }
90
91
92
93 for _, envVar := range strings.Fields(cfg.KnownEnv) {
94 os.Getenv(envVar)
95 }
96 return path
97 }
98
99
100 func GoTool() (string, error) {
101 if !HasGoBuild() {
102 return "", errors.New("platform cannot run go tool")
103 }
104 var exeSuffix string
105 if runtime.GOOS == "windows" {
106 exeSuffix = ".exe"
107 }
108 path := filepath.Join(runtime.GOROOT(), "bin", "go"+exeSuffix)
109 if _, err := os.Stat(path); err == nil {
110 return path, nil
111 }
112 goBin, err := exec.LookPath("go" + exeSuffix)
113 if err != nil {
114 return "", errors.New("cannot find go tool: " + err.Error())
115 }
116 return goBin, nil
117 }
118
119
120
121 func HasExec() bool {
122 switch runtime.GOOS {
123 case "js", "ios":
124 return false
125 }
126 return true
127 }
128
129
130 func HasSrc() bool {
131 switch runtime.GOOS {
132 case "ios":
133 return false
134 }
135 return true
136 }
137
138
139
140
141 func MustHaveExec(t testing.TB) {
142 if !HasExec() {
143 t.Skipf("skipping test: cannot exec subprocess on %s/%s", runtime.GOOS, runtime.GOARCH)
144 }
145 }
146
147 var execPaths sync.Map
148
149
150
151
152 func MustHaveExecPath(t testing.TB, path string) {
153 MustHaveExec(t)
154
155 err, found := execPaths.Load(path)
156 if !found {
157 _, err = exec.LookPath(path)
158 err, _ = execPaths.LoadOrStore(path, err)
159 }
160 if err != nil {
161 t.Skipf("skipping test: %s: %s", path, err)
162 }
163 }
164
165
166
167 func HasExternalNetwork() bool {
168 return !testing.Short() && runtime.GOOS != "js"
169 }
170
171
172
173
174 func MustHaveExternalNetwork(t testing.TB) {
175 if runtime.GOOS == "js" {
176 t.Skipf("skipping test: no external network on %s", runtime.GOOS)
177 }
178 if testing.Short() {
179 t.Skipf("skipping test: no external network in -short mode")
180 }
181 }
182
183 var haveCGO bool
184
185
186 func HasCGO() bool {
187 return haveCGO
188 }
189
190
191 func MustHaveCGO(t testing.TB) {
192 if !haveCGO {
193 t.Skipf("skipping test: no cgo")
194 }
195 }
196
197
198
199
200 func CanInternalLink() bool {
201 switch runtime.GOOS {
202 case "android":
203 if runtime.GOARCH != "arm64" {
204 return false
205 }
206 case "ios":
207 if runtime.GOARCH == "arm64" {
208 return false
209 }
210 }
211 return true
212 }
213
214
215
216
217 func MustInternalLink(t testing.TB) {
218 if !CanInternalLink() {
219 t.Skipf("skipping test: internal linking on %s/%s is not supported", runtime.GOOS, runtime.GOARCH)
220 }
221 }
222
223
224 func HasSymlink() bool {
225 ok, _ := hasSymlink()
226 return ok
227 }
228
229
230
231 func MustHaveSymlink(t testing.TB) {
232 ok, reason := hasSymlink()
233 if !ok {
234 t.Skipf("skipping test: cannot make symlinks on %s/%s%s", runtime.GOOS, runtime.GOARCH, reason)
235 }
236 }
237
238
239 func HasLink() bool {
240
241
242
243 return runtime.GOOS != "plan9" && runtime.GOOS != "android"
244 }
245
246
247
248 func MustHaveLink(t testing.TB) {
249 if !HasLink() {
250 t.Skipf("skipping test: hardlinks are not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
251 }
252 }
253
254 var flaky = flag.Bool("flaky", false, "run known-flaky tests too")
255
256 func SkipFlaky(t testing.TB, issue int) {
257 t.Helper()
258 if !*flaky {
259 t.Skipf("skipping known flaky test without the -flaky flag; see golang.org/issue/%d", issue)
260 }
261 }
262
263 func SkipFlakyNet(t testing.TB) {
264 t.Helper()
265 if v, _ := strconv.ParseBool(os.Getenv("GO_BUILDER_FLAKY_NET")); v {
266 t.Skip("skipping test on builder known to have frequent network failures")
267 }
268 }
269
270
271
272
273 func CleanCmdEnv(cmd *exec.Cmd) *exec.Cmd {
274 if cmd.Env != nil {
275 panic("environment already set")
276 }
277 for _, env := range os.Environ() {
278
279
280 if strings.HasPrefix(env, "GODEBUG=") {
281 continue
282 }
283
284 if strings.HasPrefix(env, "GOTRACEBACK=") {
285 continue
286 }
287 cmd.Env = append(cmd.Env, env)
288 }
289 return cmd
290 }
291
292
293 func CPUIsSlow() bool {
294 switch runtime.GOARCH {
295 case "arm", "mips", "mipsle", "mips64", "mips64le":
296 return true
297 }
298 return false
299 }
300
301
302
303
304
305 func SkipIfShortAndSlow(t testing.TB) {
306 if testing.Short() && CPUIsSlow() {
307 t.Helper()
308 t.Skipf("skipping test in -short mode on %s", runtime.GOARCH)
309 }
310 }
311
312
313
314
315 func RunWithTimeout(t testing.TB, cmd *exec.Cmd) ([]byte, error) {
316 args := cmd.Args
317 if args == nil {
318 args = []string{cmd.Path}
319 }
320
321 var b bytes.Buffer
322 cmd.Stdout = &b
323 cmd.Stderr = &b
324 if err := cmd.Start(); err != nil {
325 t.Fatalf("starting %s: %v", args, err)
326 }
327
328
329
330 p := cmd.Process
331 done := make(chan bool)
332 go func() {
333 scale := 1
334
335
336 if runtime.GOARCH == "arm" || runtime.GOOS == "windows" {
337 scale = 2
338 }
339 if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
340 if sc, err := strconv.Atoi(s); err == nil {
341 scale = sc
342 }
343 }
344
345 select {
346 case <-done:
347 case <-time.After(time.Duration(scale) * time.Minute):
348 p.Signal(Sigquit)
349
350
351 select {
352 case <-done:
353 case <-time.After(time.Duration(scale) * 30 * time.Second):
354 p.Signal(os.Kill)
355 }
356 }
357 }()
358
359 err := cmd.Wait()
360 if err != nil {
361 t.Logf("%s exit status: %v", args, err)
362 }
363 close(done)
364
365 return b.Bytes(), err
366 }
367
View as plain text