Source file
src/cmd/go/script_test.go
Documentation: cmd/go
1
2
3
4
5
6
7
8
9
10 package main_test
11
12 import (
13 "bufio"
14 "bytes"
15 "context"
16 "flag"
17 "internal/testenv"
18 "internal/txtar"
19 "net/url"
20 "os"
21 "path/filepath"
22 "runtime"
23 "strings"
24 "testing"
25 "time"
26
27 "cmd/go/internal/cfg"
28 "cmd/go/internal/gover"
29 "cmd/go/internal/script"
30 "cmd/go/internal/script/scripttest"
31 "cmd/go/internal/vcweb/vcstest"
32 )
33
34 var testSum = flag.String("testsum", "", `may be tidy, listm, or listall. If set, TestScript generates a go.sum file at the beginning of each test and updates test files if they pass.`)
35
36
37 func TestScript(t *testing.T) {
38 testenv.MustHaveGoBuild(t)
39 testenv.SkipIfShortAndSlow(t)
40
41 srv, err := vcstest.NewServer()
42 if err != nil {
43 t.Fatal(err)
44 }
45 t.Cleanup(func() {
46 if err := srv.Close(); err != nil {
47 t.Fatal(err)
48 }
49 })
50 certFile, err := srv.WriteCertificateFile()
51 if err != nil {
52 t.Fatal(err)
53 }
54
55 StartProxy()
56
57 var (
58 ctx = context.Background()
59 gracePeriod = 100 * time.Millisecond
60 )
61 if deadline, ok := t.Deadline(); ok {
62 timeout := time.Until(deadline)
63
64
65
66 if gp := timeout / 20; gp > gracePeriod {
67 gracePeriod = gp
68 }
69
70
71
72
73
74
75
76
77 timeout -= 2 * gracePeriod
78
79 var cancel context.CancelFunc
80 ctx, cancel = context.WithTimeout(ctx, timeout)
81 t.Cleanup(cancel)
82 }
83
84 env, err := scriptEnv(srv, certFile)
85 if err != nil {
86 t.Fatal(err)
87 }
88 engine := &script.Engine{
89 Conds: scriptConditions(),
90 Cmds: scriptCommands(quitSignal(), gracePeriod),
91 Quiet: !testing.Verbose(),
92 }
93
94 t.Run("README", func(t *testing.T) {
95 checkScriptReadme(t, engine, env)
96 })
97
98 files, err := filepath.Glob("testdata/script/*.txt")
99 if err != nil {
100 t.Fatal(err)
101 }
102 for _, file := range files {
103 file := file
104 name := strings.TrimSuffix(filepath.Base(file), ".txt")
105 t.Run(name, func(t *testing.T) {
106 t.Parallel()
107 StartProxy()
108
109 workdir, err := os.MkdirTemp(testTmpDir, name)
110 if err != nil {
111 t.Fatal(err)
112 }
113 if !*testWork {
114 defer removeAll(workdir)
115 }
116
117 s, err := script.NewState(tbContext(ctx, t), workdir, env)
118 if err != nil {
119 t.Fatal(err)
120 }
121
122
123 a, err := txtar.ParseFile(file)
124 if err != nil {
125 t.Fatal(err)
126 }
127 initScriptDirs(t, s)
128 if err := s.ExtractFiles(a); err != nil {
129 t.Fatal(err)
130 }
131
132 t.Log(time.Now().UTC().Format(time.RFC3339))
133 work, _ := s.LookupEnv("WORK")
134 t.Logf("$WORK=%s", work)
135
136
137
138 if *testSum != "" {
139 if updateSum(t, engine, s, a) {
140 defer func() {
141 if t.Failed() {
142 return
143 }
144 data := txtar.Format(a)
145 if err := os.WriteFile(file, data, 0666); err != nil {
146 t.Errorf("rewriting test file: %v", err)
147 }
148 }()
149 }
150 }
151
152
153
154
155
156 scripttest.Run(t, engine, s, file, bytes.NewReader(a.Comment))
157 })
158 }
159 }
160
161
162 type testingTBKey struct{}
163
164
165 func tbContext(ctx context.Context, t testing.TB) context.Context {
166 return context.WithValue(ctx, testingTBKey{}, t)
167 }
168
169
170 func tbFromContext(ctx context.Context) (testing.TB, bool) {
171 t := ctx.Value(testingTBKey{})
172 if t == nil {
173 return nil, false
174 }
175 return t.(testing.TB), true
176 }
177
178
179
180 func initScriptDirs(t testing.TB, s *script.State) {
181 must := func(err error) {
182 if err != nil {
183 t.Helper()
184 t.Fatal(err)
185 }
186 }
187
188 work := s.Getwd()
189 must(s.Setenv("WORK", work))
190
191 must(os.MkdirAll(filepath.Join(work, "tmp"), 0777))
192 must(s.Setenv(tempEnvName(), filepath.Join(work, "tmp")))
193
194 gopath := filepath.Join(work, "gopath")
195 must(s.Setenv("GOPATH", gopath))
196 gopathSrc := filepath.Join(gopath, "src")
197 must(os.MkdirAll(gopathSrc, 0777))
198 must(s.Chdir(gopathSrc))
199 }
200
201 func scriptEnv(srv *vcstest.Server, srvCertFile string) ([]string, error) {
202 httpURL, err := url.Parse(srv.HTTP.URL)
203 if err != nil {
204 return nil, err
205 }
206 httpsURL, err := url.Parse(srv.HTTPS.URL)
207 if err != nil {
208 return nil, err
209 }
210 env := []string{
211 pathEnvName() + "=" + testBin + string(filepath.ListSeparator) + os.Getenv(pathEnvName()),
212 homeEnvName() + "=/no-home",
213 "CCACHE_DISABLE=1",
214 "GOARCH=" + runtime.GOARCH,
215 "TESTGO_GOHOSTARCH=" + goHostArch,
216 "GOCACHE=" + testGOCACHE,
217 "GOCOVERDIR=" + os.Getenv("GOCOVERDIR"),
218 "GODEBUG=" + os.Getenv("GODEBUG"),
219 "GOEXE=" + cfg.ExeSuffix,
220 "GOEXPERIMENT=" + os.Getenv("GOEXPERIMENT"),
221 "GOOS=" + runtime.GOOS,
222 "TESTGO_GOHOSTOS=" + goHostOS,
223 "GOPROXY=" + proxyURL,
224 "GOPRIVATE=",
225 "GOROOT=" + testGOROOT,
226 "GOROOT_FINAL=" + testGOROOT_FINAL,
227 "GOTRACEBACK=system",
228 "TESTGONETWORK=panic",
229 "TESTGO_GOROOT=" + testGOROOT,
230 "TESTGO_EXE=" + testGo,
231 "TESTGO_VCSTEST_HOST=" + httpURL.Host,
232 "TESTGO_VCSTEST_TLS_HOST=" + httpsURL.Host,
233 "TESTGO_VCSTEST_CERT=" + srvCertFile,
234 "TESTGONETWORK=panic",
235 "GOSUMDB=" + testSumDBVerifierKey,
236 "GONOPROXY=",
237 "GONOSUMDB=",
238 "GOVCS=*:all",
239 "devnull=" + os.DevNull,
240 "goversion=" + gover.Local(),
241 "CMDGO_TEST_RUN_MAIN=true",
242 "HGRCPATH=",
243 "GOTOOLCHAIN=auto",
244 "newline=\n",
245 }
246
247 if testenv.Builder() != "" || os.Getenv("GIT_TRACE_CURL") == "1" {
248
249
250 env = append(env,
251 "GIT_TRACE_CURL=1",
252 "GIT_TRACE_CURL_NO_DATA=1",
253 "GIT_REDACT_COOKIES=o,SSO,GSSO_Uberproxy")
254 }
255 if testing.Short() {
256
257
258
259 env = append(env, "TESTGOVCS=panic")
260 }
261
262 if os.Getenv("CGO_ENABLED") != "" || runtime.GOOS != goHostOS || runtime.GOARCH != goHostArch {
263
264
265
266 env = append(env, "CGO_ENABLED="+cgoEnabled)
267 }
268
269 for _, key := range extraEnvKeys {
270 if val, ok := os.LookupEnv(key); ok {
271 env = append(env, key+"="+val)
272 }
273 }
274
275 return env, nil
276 }
277
278 var extraEnvKeys = []string{
279 "SYSTEMROOT",
280 "WINDIR",
281 "LD_LIBRARY_PATH",
282 "LIBRARY_PATH",
283 "C_INCLUDE_PATH",
284 "CC",
285 "GO_TESTING_GOTOOLS",
286 "GCCGO",
287 "GCCGOTOOLDIR",
288 }
289
290
291
292
293
294 func updateSum(t testing.TB, e *script.Engine, s *script.State, archive *txtar.Archive) (rewrite bool) {
295 gomodIdx, gosumIdx := -1, -1
296 for i := range archive.Files {
297 switch archive.Files[i].Name {
298 case "go.mod":
299 gomodIdx = i
300 case "go.sum":
301 gosumIdx = i
302 }
303 }
304 if gomodIdx < 0 {
305 return false
306 }
307
308 var cmd string
309 switch *testSum {
310 case "tidy":
311 cmd = "go mod tidy"
312 case "listm":
313 cmd = "go list -m -mod=mod all"
314 case "listall":
315 cmd = "go list -mod=mod all"
316 default:
317 t.Fatalf(`unknown value for -testsum %q; may be "tidy", "listm", or "listall"`, *testSum)
318 }
319
320 log := new(strings.Builder)
321 err := e.Execute(s, "updateSum", bufio.NewReader(strings.NewReader(cmd)), log)
322 if log.Len() > 0 {
323 t.Logf("%s", log)
324 }
325 if err != nil {
326 t.Fatal(err)
327 }
328
329 newGomodData, err := os.ReadFile(s.Path("go.mod"))
330 if err != nil {
331 t.Fatalf("reading go.mod after -testsum: %v", err)
332 }
333 if !bytes.Equal(newGomodData, archive.Files[gomodIdx].Data) {
334 archive.Files[gomodIdx].Data = newGomodData
335 rewrite = true
336 }
337
338 newGosumData, err := os.ReadFile(s.Path("go.sum"))
339 if err != nil && !os.IsNotExist(err) {
340 t.Fatalf("reading go.sum after -testsum: %v", err)
341 }
342 switch {
343 case os.IsNotExist(err) && gosumIdx >= 0:
344
345 rewrite = true
346 archive.Files = append(archive.Files[:gosumIdx], archive.Files[gosumIdx+1:]...)
347 case err == nil && gosumIdx < 0:
348
349 rewrite = true
350 gosumIdx = gomodIdx + 1
351 archive.Files = append(archive.Files, txtar.File{})
352 copy(archive.Files[gosumIdx+1:], archive.Files[gosumIdx:])
353 archive.Files[gosumIdx] = txtar.File{Name: "go.sum", Data: newGosumData}
354 case err == nil && gosumIdx >= 0 && !bytes.Equal(newGosumData, archive.Files[gosumIdx].Data):
355
356 rewrite = true
357 archive.Files[gosumIdx].Data = newGosumData
358 }
359 return rewrite
360 }
361
View as plain text