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