1
2
3
4
5 package modfetch
6
7 import (
8 "archive/zip"
9 "context"
10 "crypto/sha256"
11 "encoding/hex"
12 "flag"
13 "hash"
14 "internal/testenv"
15 "io"
16 "log"
17 "os"
18 "path/filepath"
19 "reflect"
20 "strings"
21 "testing"
22 "time"
23
24 "cmd/go/internal/cfg"
25 "cmd/go/internal/modfetch/codehost"
26 "cmd/go/internal/vcweb/vcstest"
27
28 "golang.org/x/mod/sumdb/dirhash"
29 )
30
31 func TestMain(m *testing.M) {
32 flag.Parse()
33 if err := testMain(m); err != nil {
34 log.Fatal(err)
35 }
36 }
37
38 func testMain(m *testing.M) (err error) {
39 cfg.GOPROXY = "direct"
40
41
42
43
44
45 cfg.GOSUMDB = "off"
46
47 dir, err := os.MkdirTemp("", "gitrepo-test-")
48 if err != nil {
49 return err
50 }
51 defer func() {
52 if rmErr := os.RemoveAll(dir); err == nil {
53 err = rmErr
54 }
55 }()
56
57 cfg.GOMODCACHE = filepath.Join(dir, "modcache")
58 if err := os.Mkdir(cfg.GOMODCACHE, 0o755); err != nil {
59 return err
60 }
61
62 srv, err := vcstest.NewServer()
63 if err != nil {
64 return err
65 }
66 defer func() {
67 if closeErr := srv.Close(); err == nil {
68 err = closeErr
69 }
70 }()
71
72 m.Run()
73 return nil
74 }
75
76 const (
77 vgotest1git = "github.com/rsc/vgotest1"
78 vgotest1hg = "vcs-test.golang.org/hg/vgotest1.hg"
79 )
80
81 var altVgotests = map[string]string{
82 "hg": vgotest1hg,
83 }
84
85 type codeRepoTest struct {
86 vcs string
87 path string
88 mpath string
89 rev string
90 err string
91 version string
92 name string
93 short string
94 time time.Time
95 gomod string
96 gomodErr string
97 zip []string
98 zipErr string
99 zipSum string
100 zipFileHash string
101 }
102
103 var codeRepoTests = []codeRepoTest{
104 {
105 vcs: "git",
106 path: "github.com/rsc/vgotest1",
107 rev: "v0.0.0",
108 version: "v0.0.0",
109 name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
110 short: "80d85c5d4d17",
111 time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
112 zip: []string{
113 "LICENSE",
114 "README.md",
115 "pkg/p.go",
116 },
117 zipSum: "h1:zVEjciLdlk/TPWCOyZo7k24T+tOKRQC+u8MKq/xS80I=",
118 zipFileHash: "738a00ddbfe8c329dce6b48e1f23c8e22a92db50f3cfb2653caa0d62676bc09c",
119 },
120 {
121 vcs: "git",
122 path: "github.com/rsc/vgotest1",
123 rev: "v0.0.0-20180219231006-80d85c5d4d17",
124 version: "v0.0.0-20180219231006-80d85c5d4d17",
125 name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
126 short: "80d85c5d4d17",
127 time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
128 zip: []string{
129 "LICENSE",
130 "README.md",
131 "pkg/p.go",
132 },
133 zipSum: "h1:nOznk2xKsLGkTnXe0q9t1Ewt9jxK+oadtafSUqHM3Ec=",
134 zipFileHash: "bacb08f391e29d2eaaef8281b5c129ee6d890e608ee65877e0003c0181a766c8",
135 },
136 {
137 vcs: "git",
138 path: "github.com/rsc/vgotest1",
139 rev: "v0.0.1-0.20180219231006-80d85c5d4d17",
140 err: `github.com/rsc/vgotest1@v0.0.1-0.20180219231006-80d85c5d4d17: invalid pseudo-version: tag (v0.0.0) found on revision 80d85c5d4d17 is already canonical, so should not be replaced with a pseudo-version derived from that tag`,
141 },
142 {
143 vcs: "git",
144 path: "github.com/rsc/vgotest1",
145 rev: "v1.0.0",
146 version: "v1.0.0",
147 name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
148 short: "80d85c5d4d17",
149 time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
150 zip: []string{
151 "LICENSE",
152 "README.md",
153 "pkg/p.go",
154 },
155 zipSum: "h1:e040hOoWGeuJLawDjK9DW6med+cz9FxMFYDMOVG8ctQ=",
156 zipFileHash: "74caab65cfbea427c341fa815f3bb0378681d8f0e3cf62a7f207014263ec7be3",
157 },
158 {
159 vcs: "git",
160 path: "github.com/rsc/vgotest1/v2",
161 rev: "v2.0.0",
162 version: "v2.0.0",
163 name: "45f53230a74ad275c7127e117ac46914c8126160",
164 short: "45f53230a74a",
165 time: time.Date(2018, 7, 19, 1, 21, 27, 0, time.UTC),
166 err: "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0",
167 },
168 {
169 vcs: "git",
170 path: "github.com/rsc/vgotest1",
171 rev: "80d85c5",
172 version: "v1.0.0",
173 name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
174 short: "80d85c5d4d17",
175 time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
176 zip: []string{
177 "LICENSE",
178 "README.md",
179 "pkg/p.go",
180 },
181 zipSum: "h1:e040hOoWGeuJLawDjK9DW6med+cz9FxMFYDMOVG8ctQ=",
182 zipFileHash: "74caab65cfbea427c341fa815f3bb0378681d8f0e3cf62a7f207014263ec7be3",
183 },
184 {
185 vcs: "git",
186 path: "github.com/rsc/vgotest1",
187 rev: "mytag",
188 version: "v1.0.0",
189 name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
190 short: "80d85c5d4d17",
191 time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
192 zip: []string{
193 "LICENSE",
194 "README.md",
195 "pkg/p.go",
196 },
197 },
198 {
199 vcs: "git",
200 path: "github.com/rsc/vgotest1/v2",
201 rev: "45f53230a",
202 version: "v2.0.0",
203 name: "45f53230a74ad275c7127e117ac46914c8126160",
204 short: "45f53230a74a",
205 time: time.Date(2018, 7, 19, 1, 21, 27, 0, time.UTC),
206 err: "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0",
207 },
208 {
209 vcs: "git",
210 path: "github.com/rsc/vgotest1/v54321",
211 rev: "80d85c5",
212 version: "v54321.0.0-20180219231006-80d85c5d4d17",
213 name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
214 short: "80d85c5d4d17",
215 time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
216 err: "missing github.com/rsc/vgotest1/go.mod and .../v54321/go.mod at revision 80d85c5d4d17",
217 },
218 {
219 vcs: "git",
220 path: "github.com/rsc/vgotest1/submod",
221 rev: "v1.0.0",
222 err: "unknown revision submod/v1.0.0",
223 },
224 {
225 vcs: "git",
226 path: "github.com/rsc/vgotest1/submod",
227 rev: "v1.0.3",
228 err: "unknown revision submod/v1.0.3",
229 },
230 {
231 vcs: "git",
232 path: "github.com/rsc/vgotest1/submod",
233 rev: "v1.0.4",
234 version: "v1.0.4",
235 name: "8afe2b2efed96e0880ecd2a69b98a53b8c2738b6",
236 short: "8afe2b2efed9",
237 time: time.Date(2018, 2, 19, 23, 12, 7, 0, time.UTC),
238 gomod: "module \"github.com/vgotest1/submod\" // submod/go.mod\n",
239 zip: []string{
240 "go.mod",
241 "pkg/p.go",
242 "LICENSE",
243 },
244 zipSum: "h1:iMsJ/9uQsk6MnZNnJK311f11QiSlmN92Q2aSjCywuJY=",
245 zipFileHash: "95801bfa69c5197ae809af512946d22f22850068527cd78100ae3f176bc8043b",
246 },
247 {
248 vcs: "git",
249 path: "github.com/rsc/vgotest1",
250 rev: "v1.1.0",
251 version: "v1.1.0",
252 name: "b769f2de407a4db81af9c5de0a06016d60d2ea09",
253 short: "b769f2de407a",
254 time: time.Date(2018, 2, 19, 23, 13, 36, 0, time.UTC),
255 gomod: "module \"github.com/rsc/vgotest1\" // root go.mod\nrequire \"github.com/rsc/vgotest1/submod\" v1.0.5\n",
256 zip: []string{
257 "LICENSE",
258 "README.md",
259 "go.mod",
260 "pkg/p.go",
261 },
262 zipSum: "h1:M69k7q+8bQ+QUpHov45Z/NoR8rj3DsQJUnXLWvf01+Q=",
263 zipFileHash: "58af45fb248d320ea471f568e006379e2b8d71d6d1663f9b19b2e00fd9ac9265",
264 },
265 {
266 vcs: "git",
267 path: "github.com/rsc/vgotest1/v2",
268 rev: "v2.0.1",
269 version: "v2.0.1",
270 name: "ea65f87c8f52c15ea68f3bdd9925ef17e20d91e9",
271 short: "ea65f87c8f52",
272 time: time.Date(2018, 2, 19, 23, 14, 23, 0, time.UTC),
273 gomod: "module \"github.com/rsc/vgotest1/v2\" // root go.mod\n",
274 zipSum: "h1:QmgYy/zt+uoWhDpcsgrSVzYFvKtBEjl5zT/FRz9GTzA=",
275 zipFileHash: "1aedf1546d322a0121879ddfd6d0e8bfbd916d2cafbeb538ddb440e04b04b9ef",
276 },
277 {
278 vcs: "git",
279 path: "github.com/rsc/vgotest1/v2",
280 rev: "v2.0.3",
281 version: "v2.0.3",
282 name: "f18795870fb14388a21ef3ebc1d75911c8694f31",
283 short: "f18795870fb1",
284 time: time.Date(2018, 2, 19, 23, 16, 4, 0, time.UTC),
285 err: "github.com/rsc/vgotest1/v2/go.mod has non-.../v2 module path \"github.com/rsc/vgotest\" at revision v2.0.3",
286 },
287 {
288 vcs: "git",
289 path: "github.com/rsc/vgotest1/v2",
290 rev: "v2.0.4",
291 version: "v2.0.4",
292 name: "1f863feb76bc7029b78b21c5375644838962f88d",
293 short: "1f863feb76bc",
294 time: time.Date(2018, 2, 20, 0, 3, 38, 0, time.UTC),
295 err: "github.com/rsc/vgotest1/go.mod and .../v2/go.mod both have .../v2 module paths at revision v2.0.4",
296 },
297 {
298 vcs: "git",
299 path: "github.com/rsc/vgotest1/v2",
300 rev: "v2.0.5",
301 version: "v2.0.5",
302 name: "2f615117ce481c8efef46e0cc0b4b4dccfac8fea",
303 short: "2f615117ce48",
304 time: time.Date(2018, 2, 20, 0, 3, 59, 0, time.UTC),
305 gomod: "module \"github.com/rsc/vgotest1/v2\" // v2/go.mod\n",
306 zipSum: "h1:RIEb9q1SUSEQOzMn0zfl/LQxGFWlhWEAdeEguf1MLGU=",
307 zipFileHash: "7d92c2c328c5e9b0694101353705d5843746ec1d93a1e986d0da54c8a14dfe6d",
308 },
309 {
310
311 vcs: "git",
312 path: "rsc.io/quote",
313 rev: "v1.0.0",
314 version: "v1.0.0",
315 name: "f488df80bcdbd3e5bafdc24ad7d1e79e83edd7e6",
316 short: "f488df80bcdb",
317 time: time.Date(2018, 2, 14, 0, 45, 20, 0, time.UTC),
318 gomod: "module \"rsc.io/quote\"\n",
319 zipSum: "h1:haUSojyo3j2M9g7CEUFG8Na09dtn7QKxvPGaPVQdGwM=",
320 zipFileHash: "5c08ba2c09a364f93704aaa780e7504346102c6ef4fe1333a11f09904a732078",
321 },
322 {
323
324 vcs: "mod",
325 path: "swtch.com/testmod",
326 rev: "v1.0.0",
327 version: "v1.0.0",
328
329 time: time.Date(1972, 7, 18, 12, 34, 56, 0, time.UTC),
330 gomod: "module \"swtch.com/testmod\"\n",
331 },
332 {
333
334 vcs: "git",
335 path: "golang.org/x/text",
336 rev: "4e4a3210bb",
337 version: "v0.3.1-0.20180208041248-4e4a3210bb54",
338 name: "4e4a3210bb54bb31f6ab2cdca2edcc0b50c420c1",
339 short: "4e4a3210bb54",
340 time: time.Date(2018, 2, 8, 4, 12, 48, 0, time.UTC),
341 zipSum: "h1:Yxu6pHX9X2RECiuw/Q5/4uvajuaowck8zOFKXgbfNBk=",
342 zipFileHash: "ac2c165a5c10aa5a7545dea60a08e019270b982fa6c8bdcb5943931de64922fe",
343 },
344 {
345 vcs: "git",
346 path: "github.com/pkg/errors",
347 rev: "v0.8.0",
348 version: "v0.8.0",
349 name: "645ef00459ed84a119197bfb8d8205042c6df63d",
350 short: "645ef00459ed",
351 time: time.Date(2016, 9, 29, 1, 48, 1, 0, time.UTC),
352 zipSum: "h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=",
353 zipFileHash: "e4fa69ba057356614edbc1da881a7d3ebb688505be49f65965686bcb859e2fae",
354 },
355 {
356
357
358
359 vcs: "git",
360 path: "gopkg.in/yaml.v2/abc",
361 err: "invalid module path \"gopkg.in/yaml.v2/abc\"",
362 },
363 {
364
365
366 vcs: "git",
367 path: "github.com/rsc/quote/buggy",
368 rev: "c4d4236f",
369 err: "missing github.com/rsc/quote/buggy/go.mod at revision c4d4236f9242",
370 },
371 {
372 vcs: "git",
373 path: "gopkg.in/yaml.v2",
374 rev: "d670f940",
375 version: "v2.0.0",
376 name: "d670f9405373e636a5a2765eea47fac0c9bc91a4",
377 short: "d670f9405373",
378 time: time.Date(2018, 1, 9, 11, 43, 31, 0, time.UTC),
379 gomod: "module gopkg.in/yaml.v2\n",
380 zipSum: "h1:uUkhRGrsEyx/laRdeS6YIQKIys8pg+lRSRdVMTYjivs=",
381 zipFileHash: "7b0a141b1b0b49772ab4eecfd11dfd6609a94a5e868cab04a3abb1861ffaa877",
382 },
383 {
384 vcs: "git",
385 path: "gopkg.in/check.v1",
386 rev: "20d25e280405",
387 version: "v1.0.0-20161208181325-20d25e280405",
388 name: "20d25e2804050c1cd24a7eea1e7a6447dd0e74ec",
389 short: "20d25e280405",
390 time: time.Date(2016, 12, 8, 18, 13, 25, 0, time.UTC),
391 gomod: "module gopkg.in/check.v1\n",
392 zipSum: "h1:829vOVxxusYHC+IqBtkX5mbKtsY9fheQiQn0MZRVLfQ=",
393 zipFileHash: "9e7cb3f4f1e66d722306442b0dbe1f6f43d74d1736d54c510537bdfb1d6f432f",
394 },
395 {
396 vcs: "git",
397 path: "vcs-test.golang.org/go/mod/gitrepo1",
398 rev: "master",
399 version: "v1.2.4-annotated",
400 name: "ede458df7cd0fdca520df19a33158086a8a68e81",
401 short: "ede458df7cd0",
402 time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
403 gomod: "module vcs-test.golang.org/go/mod/gitrepo1\n",
404 zipSum: "h1:YJYZRsM9BHFTlVr8YADjT0cJH8uFIDtoc5NLiVqZEx8=",
405 zipFileHash: "c15e49d58b7a4c37966cbe5bc01a0330cd5f2927e990e1839bda1d407766d9c5",
406 },
407 {
408 vcs: "git",
409 path: "gopkg.in/natefinch/lumberjack.v2",
410
411
412
413
414
415
416 rev: "v2.1",
417 version: "v2.0.0-20170531160350-a96e63847dc3",
418 name: "a96e63847dc3c67d17befa69c303767e2f84e54f",
419 short: "a96e63847dc3",
420 time: time.Date(2017, 5, 31, 16, 3, 50, 0, time.UTC),
421 gomod: "module gopkg.in/natefinch/lumberjack.v2\n",
422 },
423 {
424 vcs: "git",
425 path: "vcs-test.golang.org/go/v2module/v2",
426 rev: "v2.0.0",
427 version: "v2.0.0",
428 name: "203b91c896acd173aa719e4cdcb7d463c4b090fa",
429 short: "203b91c896ac",
430 time: time.Date(2019, 4, 3, 15, 52, 15, 0, time.UTC),
431 gomod: "module vcs-test.golang.org/go/v2module/v2\n\ngo 1.12\n",
432 zipSum: "h1:JItBZ+gwA5WvtZEGEbuDL4lUttGtLrs53lmdurq3bOg=",
433 zipFileHash: "9ea9ae1673cffcc44b7fdd3cc89953d68c102449b46c982dbf085e4f2e394da5",
434 },
435 {
436
437 vcs: "git",
438 path: "vcs-test.golang.org/go/mod/gitrepo1",
439 rev: "v2.3.4+incompatible",
440 err: `resolves to version v2.0.1+incompatible (v2.3.4 is not a tag)`,
441 },
442 {
443
444 vcs: "git",
445 path: "vcs-test.golang.org/git/semver-branch.git",
446 rev: "v1.0.0",
447 err: `resolves to version v0.1.1-0.20220202191944-09c4d8f6938c (v1.0.0 is not a tag)`,
448 },
449 {
450
451
452 vcs: "git",
453 path: "vcs-test.golang.org/git/semver-branch.git",
454 rev: "v2.0.0+incompatible",
455 err: `resolves to version v0.1.0 (v2.0.0 is not a tag)`,
456 },
457 {
458
459
460 vcs: "git",
461 path: "vcs-test.golang.org/git/semver-branch.git",
462 rev: "v2.0.0",
463 err: `resolves to version v0.1.0 (v2.0.0 is not a tag)`,
464 },
465 {
466
467
468
469
470 vcs: "git",
471 path: "vcs-test.golang.org/git/semver-branch.git",
472 rev: "v3.0.0-devel",
473 err: `resolves to version v0.1.1-0.20220203155313-d59622f6e4d7 (v3.0.0-devel is not a tag)`,
474 },
475
476
477
478
479
480
481
482
483
484 {
485 vcs: "git",
486 path: "vcs-test.golang.org/git/v2sub.git",
487 rev: "80beb17a1603",
488 version: "v0.0.0-20220222205507-80beb17a1603",
489 name: "80beb17a16036f17a5aedd1bb5bd6d407b3c6dc5",
490 short: "80beb17a1603",
491 time: time.Date(2022, 2, 22, 20, 55, 7, 0, time.UTC),
492 },
493 {
494 vcs: "git",
495 path: "vcs-test.golang.org/git/v2sub.git",
496 rev: "v2.0.0",
497 err: `module contains a go.mod file, so module path must match major version ("vcs-test.golang.org/git/v2sub.git/v2")`,
498 },
499 {
500 vcs: "git",
501 path: "vcs-test.golang.org/git/v2sub.git",
502 rev: "v2.0.1-0.20220222205507-80beb17a1603",
503 err: `module contains a go.mod file, so module path must match major version ("vcs-test.golang.org/git/v2sub.git/v2")`,
504 },
505 {
506 vcs: "git",
507 path: "vcs-test.golang.org/git/v2sub.git",
508 rev: "v2.0.0+incompatible",
509 version: "v2.0.0+incompatible",
510 name: "5fcd3eaeeb391d399f562fd45a50dac9fc34ae8b",
511 short: "5fcd3eaeeb39",
512 time: time.Date(2022, 2, 22, 20, 53, 33, 0, time.UTC),
513 },
514 {
515 vcs: "git",
516 path: "vcs-test.golang.org/git/v2sub.git",
517 rev: "v2.0.1-0.20220222205507-80beb17a1603+incompatible",
518 version: "v2.0.1-0.20220222205507-80beb17a1603+incompatible",
519 name: "80beb17a16036f17a5aedd1bb5bd6d407b3c6dc5",
520 short: "80beb17a1603",
521 time: time.Date(2022, 2, 22, 20, 55, 7, 0, time.UTC),
522 },
523
524
525
526 {
527 vcs: "git",
528 path: "vcs-test.golang.org/git/odd-tags.git",
529 rev: "v0.1.0+build-metadata",
530 version: "v0.1.1-0.20220223184835-9d863d525bbf",
531 name: "9d863d525bbfcc8eda09364738c4032393711a56",
532 short: "9d863d525bbf",
533 time: time.Date(2022, 2, 23, 18, 48, 35, 0, time.UTC),
534 },
535 {
536 vcs: "git",
537 path: "vcs-test.golang.org/git/odd-tags.git",
538 rev: "9d863d525bbf",
539 version: "v0.1.1-0.20220223184835-9d863d525bbf",
540 name: "9d863d525bbfcc8eda09364738c4032393711a56",
541 short: "9d863d525bbf",
542 time: time.Date(2022, 2, 23, 18, 48, 35, 0, time.UTC),
543 },
544 {
545 vcs: "git",
546 path: "vcs-test.golang.org/git/odd-tags.git",
547 rev: "latest",
548 version: "v0.1.1-0.20220223184835-9d863d525bbf",
549 name: "9d863d525bbfcc8eda09364738c4032393711a56",
550 short: "9d863d525bbf",
551 time: time.Date(2022, 2, 23, 18, 48, 35, 0, time.UTC),
552 },
553
554
555
556
557
558
559 {
560 vcs: "git",
561 path: "vcs-test.golang.org/git/odd-tags.git",
562 rev: "v2.0.0+incompatible",
563 err: `unknown revision v2.0.0`,
564 },
565 {
566 vcs: "git",
567 path: "vcs-test.golang.org/git/odd-tags.git",
568 rev: "12d19af20458",
569 version: "v2.0.1-0.20220223184802-12d19af20458+incompatible",
570 name: "12d19af204585b0db3d2a876ceddf5b9323f5a4a",
571 short: "12d19af20458",
572 time: time.Date(2022, 2, 23, 18, 48, 2, 0, time.UTC),
573 },
574
575
576
577 {
578 vcs: "git",
579 path: "vcs-test.golang.org/git/odd-tags.git",
580 rev: "v3.0.0-20220223184802-12d19af20458",
581 version: "v3.0.0-20220223184802-12d19af20458+incompatible",
582 name: "12d19af204585b0db3d2a876ceddf5b9323f5a4a",
583 short: "12d19af20458",
584 time: time.Date(2022, 2, 23, 18, 48, 2, 0, time.UTC),
585 },
586 }
587
588 func TestCodeRepo(t *testing.T) {
589 testenv.MustHaveExternalNetwork(t)
590 tmpdir := t.TempDir()
591 fetcher := NewFetcher()
592
593 for _, tt := range codeRepoTests {
594 f := func(tt codeRepoTest) func(t *testing.T) {
595 return func(t *testing.T) {
596 if strings.Contains(tt.path, "gopkg.in") {
597 testenv.SkipFlaky(t, 54503)
598 }
599
600 t.Parallel()
601 if tt.vcs != "mod" {
602 testenv.MustHaveExecPath(t, tt.vcs)
603 }
604 ctx := context.Background()
605
606 repo := fetcher.Lookup(ctx, "direct", tt.path)
607
608 if tt.mpath == "" {
609 tt.mpath = tt.path
610 }
611 if mpath := repo.ModulePath(); mpath != tt.mpath {
612 t.Errorf("repo.ModulePath() = %q, want %q", mpath, tt.mpath)
613 }
614
615 info, err := repo.Stat(ctx, tt.rev)
616 if err != nil {
617 if tt.err != "" {
618 if !strings.Contains(err.Error(), tt.err) {
619 t.Fatalf("repoStat(%q): %v, wanted %q", tt.rev, err, tt.err)
620 }
621 return
622 }
623 t.Fatalf("repo.Stat(%q): %v", tt.rev, err)
624 }
625 if tt.err != "" {
626 t.Errorf("repo.Stat(%q): success, wanted error", tt.rev)
627 }
628 if info.Version != tt.version {
629 t.Errorf("info.Version = %q, want %q", info.Version, tt.version)
630 }
631 if info.Name != tt.name {
632 t.Errorf("info.Name = %q, want %q", info.Name, tt.name)
633 }
634 if info.Short != tt.short {
635 t.Errorf("info.Short = %q, want %q", info.Short, tt.short)
636 }
637 if !info.Time.Equal(tt.time) {
638 t.Errorf("info.Time = %v, want %v", info.Time, tt.time)
639 }
640
641 if tt.gomod != "" || tt.gomodErr != "" {
642 data, err := repo.GoMod(ctx, tt.version)
643 if err != nil && tt.gomodErr == "" {
644 t.Errorf("repo.GoMod(%q): %v", tt.version, err)
645 } else if err != nil && tt.gomodErr != "" {
646 if err.Error() != tt.gomodErr {
647 t.Errorf("repo.GoMod(%q): %v, want %q", tt.version, err, tt.gomodErr)
648 }
649 } else if tt.gomodErr != "" {
650 t.Errorf("repo.GoMod(%q) = %q, want error %q", tt.version, data, tt.gomodErr)
651 } else if string(data) != tt.gomod {
652 t.Errorf("repo.GoMod(%q) = %q, want %q", tt.version, data, tt.gomod)
653 }
654 }
655
656 needHash := !testing.Short() && (tt.zipFileHash != "" || tt.zipSum != "")
657 if tt.zip != nil || tt.zipErr != "" || needHash {
658 f, err := os.CreateTemp(tmpdir, tt.version+".zip.")
659 if err != nil {
660 t.Fatalf("os.CreateTemp: %v", err)
661 }
662 zipfile := f.Name()
663 defer func() {
664 f.Close()
665 os.Remove(zipfile)
666 }()
667
668 var w io.Writer
669 var h hash.Hash
670 if needHash {
671 h = sha256.New()
672 w = io.MultiWriter(f, h)
673 } else {
674 w = f
675 }
676 err = repo.Zip(ctx, w, tt.version)
677 f.Close()
678 if err != nil {
679 if tt.zipErr != "" {
680 if err.Error() == tt.zipErr {
681 return
682 }
683 t.Fatalf("repo.Zip(%q): %v, want error %q", tt.version, err, tt.zipErr)
684 }
685 t.Fatalf("repo.Zip(%q): %v", tt.version, err)
686 }
687 if tt.zipErr != "" {
688 t.Errorf("repo.Zip(%q): success, want error %q", tt.version, tt.zipErr)
689 }
690
691 if tt.zip != nil {
692 prefix := tt.path + "@" + tt.version + "/"
693 z, err := zip.OpenReader(zipfile)
694 if err != nil {
695 t.Fatalf("open zip %s: %v", zipfile, err)
696 }
697 var names []string
698 for _, file := range z.File {
699 if !strings.HasPrefix(file.Name, prefix) {
700 t.Errorf("zip entry %v does not start with prefix %v", file.Name, prefix)
701 continue
702 }
703 names = append(names, file.Name[len(prefix):])
704 }
705 z.Close()
706 if !reflect.DeepEqual(names, tt.zip) {
707 t.Fatalf("zip = %v\nwant %v\n", names, tt.zip)
708 }
709 }
710
711 if needHash {
712 sum, err := dirhash.HashZip(zipfile, dirhash.Hash1)
713 if err != nil {
714 t.Errorf("repo.Zip(%q): %v", tt.version, err)
715 } else if sum != tt.zipSum {
716 t.Errorf("repo.Zip(%q): got file with sum %q, want %q", tt.version, sum, tt.zipSum)
717 } else if zipFileHash := hex.EncodeToString(h.Sum(nil)); zipFileHash != tt.zipFileHash {
718 t.Errorf("repo.Zip(%q): got file with hash %q, want %q (but content has correct sum)", tt.version, zipFileHash, tt.zipFileHash)
719 }
720 }
721 }
722 }
723 }
724 t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt))
725 if strings.HasPrefix(tt.path, vgotest1git) {
726 for vcs, alt := range altVgotests {
727 altTest := tt
728 altTest.vcs = vcs
729 altTest.path = alt + strings.TrimPrefix(altTest.path, vgotest1git)
730 if strings.HasPrefix(altTest.mpath, vgotest1git) {
731 altTest.mpath = alt + strings.TrimPrefix(altTest.mpath, vgotest1git)
732 }
733 var m map[string]string
734 if alt == vgotest1hg {
735 m = hgmap
736 }
737 altTest.version = remap(altTest.version, m)
738 altTest.name = remap(altTest.name, m)
739 altTest.short = remap(altTest.short, m)
740 altTest.rev = remap(altTest.rev, m)
741 altTest.err = remap(altTest.err, m)
742 altTest.gomodErr = remap(altTest.gomodErr, m)
743 altTest.zipErr = remap(altTest.zipErr, m)
744 altTest.zipSum = ""
745 altTest.zipFileHash = ""
746 t.Run(strings.ReplaceAll(altTest.path, "/", "_")+"/"+altTest.rev, f(altTest))
747 }
748 }
749 }
750 }
751
752 var hgmap = map[string]string{
753 "github.com/rsc/vgotest1": "vcs-test.golang.org/hg/vgotest1.hg",
754 "f18795870fb14388a21ef3ebc1d75911c8694f31": "a9ad6d1d14eb544f459f446210c7eb3b009807c6",
755 "ea65f87c8f52c15ea68f3bdd9925ef17e20d91e9": "f1fc0f22021b638d073d31c752847e7bf385def7",
756 "b769f2de407a4db81af9c5de0a06016d60d2ea09": "92c7eb888b4fac17f1c6bd2e1060a1b881a3b832",
757 "8afe2b2efed96e0880ecd2a69b98a53b8c2738b6": "4e58084d459ae7e79c8c2264d0e8e9a92eb5cd44",
758 "2f615117ce481c8efef46e0cc0b4b4dccfac8fea": "879ea98f7743c8eff54f59a918f3a24123d1cf46",
759 "80d85c5d4d17598a0e9055e7c175a32b415d6128": "e125018e286a4b09061079a81e7b537070b7ff71",
760 "1f863feb76bc7029b78b21c5375644838962f88d": "bf63880162304a9337477f3858f5b7e255c75459",
761 "45f53230a74ad275c7127e117ac46914c8126160": "814fce58e83abd5bf2a13892e0b0e1198abefcd4",
762 }
763
764 func remap(name string, m map[string]string) string {
765 if m[name] != "" {
766 return m[name]
767 }
768 if codehost.AllHex(name) {
769 for k, v := range m {
770 if strings.HasPrefix(k, name) {
771 return v[:len(name)]
772 }
773 }
774 }
775 for k, v := range m {
776 name = strings.ReplaceAll(name, k, v)
777 if codehost.AllHex(k) {
778 name = strings.ReplaceAll(name, k[:12], v[:12])
779 }
780 }
781 return name
782 }
783
784 var codeRepoVersionsTests = []struct {
785 vcs string
786 path string
787 prefix string
788 versions []string
789 }{
790 {
791 vcs: "git",
792 path: "github.com/rsc/vgotest1",
793 versions: []string{"v0.0.0", "v0.0.1", "v1.0.0", "v1.0.1", "v1.0.2", "v1.0.3", "v1.1.0"},
794 },
795 {
796 vcs: "git",
797 path: "github.com/rsc/vgotest1",
798 prefix: "v1.0",
799 versions: []string{"v1.0.0", "v1.0.1", "v1.0.2", "v1.0.3"},
800 },
801 {
802 vcs: "git",
803 path: "github.com/rsc/vgotest1/v2",
804 versions: []string{"v2.0.0", "v2.0.1", "v2.0.2", "v2.0.3", "v2.0.4", "v2.0.5", "v2.0.6"},
805 },
806 {
807 vcs: "mod",
808 path: "swtch.com/testmod",
809 versions: []string{"v1.0.0", "v1.1.1"},
810 },
811 {
812 vcs: "git",
813 path: "vcs-test.golang.org/git/odd-tags.git",
814 versions: nil,
815 },
816 }
817
818 func TestCodeRepoVersions(t *testing.T) {
819 testenv.MustHaveExternalNetwork(t)
820 fetcher := NewFetcher()
821 for _, tt := range codeRepoVersionsTests {
822 tt := tt
823 t.Run(strings.ReplaceAll(tt.path, "/", "_"), func(t *testing.T) {
824 if strings.Contains(tt.path, "gopkg.in") {
825 testenv.SkipFlaky(t, 54503)
826 }
827
828 t.Parallel()
829 if tt.vcs != "mod" {
830 testenv.MustHaveExecPath(t, tt.vcs)
831 }
832 ctx := context.Background()
833
834 repo := fetcher.Lookup(ctx, "direct", tt.path)
835 list, err := repo.Versions(ctx, tt.prefix)
836 if err != nil {
837 t.Fatalf("Versions(%q): %v", tt.prefix, err)
838 }
839 if !reflect.DeepEqual(list.List, tt.versions) {
840 t.Fatalf("Versions(%q):\nhave %v\nwant %v", tt.prefix, list, tt.versions)
841 }
842 })
843 }
844 }
845
846 var latestTests = []struct {
847 vcs string
848 path string
849 version string
850 err string
851 }{
852 {
853 vcs: "git",
854 path: "github.com/rsc/empty",
855 err: "no commits",
856 },
857 {
858 vcs: "git",
859 path: "github.com/rsc/vgotest1",
860 err: `github.com/rsc/vgotest1@v0.0.0-20180219223237-a08abb797a67: invalid version: go.mod has post-v0 module path "github.com/vgotest1/v2" at revision a08abb797a67`,
861 },
862 {
863 vcs: "git",
864 path: "github.com/rsc/vgotest1/v2",
865 err: `github.com/rsc/vgotest1/v2@v2.0.0-20180219223237-a08abb797a67: invalid version: github.com/rsc/vgotest1/go.mod and .../v2/go.mod both have .../v2 module paths at revision a08abb797a67`,
866 },
867 {
868 vcs: "git",
869 path: "github.com/rsc/vgotest1/subdir",
870 err: "github.com/rsc/vgotest1/subdir@v0.0.0-20180219223237-a08abb797a67: invalid version: missing github.com/rsc/vgotest1/subdir/go.mod at revision a08abb797a67",
871 },
872 {
873 vcs: "git",
874 path: "vcs-test.golang.org/git/commit-after-tag.git",
875 version: "v1.0.1-0.20190715211727-b325d8217783",
876 },
877 {
878 vcs: "git",
879 path: "vcs-test.golang.org/git/no-tags.git",
880 version: "v0.0.0-20190715212047-e706ba1d9f6d",
881 },
882 {
883 vcs: "mod",
884 path: "swtch.com/testmod",
885 version: "v1.1.1",
886 },
887 {
888 vcs: "git",
889 path: "vcs-test.golang.org/go/gitreposubdir",
890 version: "v1.2.3",
891 },
892 {
893 vcs: "git",
894 path: "vcs-test.golang.org/go/gitreposubdirv2/v2",
895 version: "v2.0.0",
896 },
897 }
898
899 func TestLatest(t *testing.T) {
900 testenv.MustHaveExternalNetwork(t)
901 fetcher := NewFetcher()
902 for _, tt := range latestTests {
903 name := strings.ReplaceAll(tt.path, "/", "_")
904 t.Run(name, func(t *testing.T) {
905 tt := tt
906 t.Parallel()
907 if tt.vcs != "mod" {
908 testenv.MustHaveExecPath(t, tt.vcs)
909 }
910 ctx := context.Background()
911
912 repo := fetcher.Lookup(ctx, "direct", tt.path)
913 info, err := repo.Latest(ctx)
914 if err != nil {
915 if tt.err != "" {
916 if err.Error() == tt.err {
917 return
918 }
919 t.Fatalf("Latest(): %v, want %q", err, tt.err)
920 }
921 t.Fatalf("Latest(): %v", err)
922 }
923 if tt.err != "" {
924 t.Fatalf("Latest() = %v, want error %q", info.Version, tt.err)
925 }
926 if info.Version != tt.version {
927 t.Fatalf("Latest() = %v, want %v", info.Version, tt.version)
928 }
929 })
930 }
931 }
932
933
934 type fixedTagsRepo struct {
935 tags []string
936 codehost.Repo
937 }
938
939 func (ch *fixedTagsRepo) Tags(ctx context.Context, prefix string) (*codehost.Tags, error) {
940 tags := &codehost.Tags{}
941 for _, t := range ch.tags {
942 tags.List = append(tags.List, codehost.Tag{Name: t})
943 }
944 return tags, nil
945 }
946
947 func TestNonCanonicalSemver(t *testing.T) {
948 t.Parallel()
949 ctx := context.Background()
950
951 root := "golang.org/x/issue24476"
952 ch := &fixedTagsRepo{
953 tags: []string{
954 "", "huh?", "1.0.1",
955
956 "v1.🐕.🐄",
957 "v1", "v0.1",
958
959 "v1.0.1",
960 },
961 }
962
963 cr, err := newCodeRepo(ch, root, "", root)
964 if err != nil {
965 t.Fatal(err)
966 }
967
968 v, err := cr.Versions(ctx, "")
969 if err != nil {
970 t.Fatal(err)
971 }
972 if len(v.List) != 1 || v.List[0] != "v1.0.1" {
973 t.Fatal("unexpected versions returned:", v)
974 }
975 }
976
View as plain text