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 func TestCodeRepo(t *testing.T) {
424 testenv.MustHaveExternalNetwork(t)
425
426 tmpdir, err := os.MkdirTemp("", "modfetch-test-")
427 if err != nil {
428 t.Fatal(err)
429 }
430 defer os.RemoveAll(tmpdir)
431
432 t.Run("parallel", func(t *testing.T) {
433 for _, tt := range codeRepoTests {
434 f := func(tt codeRepoTest) func(t *testing.T) {
435 return func(t *testing.T) {
436 t.Parallel()
437 if tt.vcs != "mod" {
438 testenv.MustHaveExecPath(t, tt.vcs)
439 }
440
441 repo := Lookup("direct", tt.path)
442
443 if tt.mpath == "" {
444 tt.mpath = tt.path
445 }
446 if mpath := repo.ModulePath(); mpath != tt.mpath {
447 t.Errorf("repo.ModulePath() = %q, want %q", mpath, tt.mpath)
448 }
449
450 info, err := repo.Stat(tt.rev)
451 if err != nil {
452 if tt.err != "" {
453 if !strings.Contains(err.Error(), tt.err) {
454 t.Fatalf("repoStat(%q): %v, wanted %q", tt.rev, err, tt.err)
455 }
456 return
457 }
458 t.Fatalf("repo.Stat(%q): %v", tt.rev, err)
459 }
460 if tt.err != "" {
461 t.Errorf("repo.Stat(%q): success, wanted error", tt.rev)
462 }
463 if info.Version != tt.version {
464 t.Errorf("info.Version = %q, want %q", info.Version, tt.version)
465 }
466 if info.Name != tt.name {
467 t.Errorf("info.Name = %q, want %q", info.Name, tt.name)
468 }
469 if info.Short != tt.short {
470 t.Errorf("info.Short = %q, want %q", info.Short, tt.short)
471 }
472 if !info.Time.Equal(tt.time) {
473 t.Errorf("info.Time = %v, want %v", info.Time, tt.time)
474 }
475
476 if tt.gomod != "" || tt.gomodErr != "" {
477 data, err := repo.GoMod(tt.version)
478 if err != nil && tt.gomodErr == "" {
479 t.Errorf("repo.GoMod(%q): %v", tt.version, err)
480 } else if err != nil && tt.gomodErr != "" {
481 if err.Error() != tt.gomodErr {
482 t.Errorf("repo.GoMod(%q): %v, want %q", tt.version, err, tt.gomodErr)
483 }
484 } else if tt.gomodErr != "" {
485 t.Errorf("repo.GoMod(%q) = %q, want error %q", tt.version, data, tt.gomodErr)
486 } else if string(data) != tt.gomod {
487 t.Errorf("repo.GoMod(%q) = %q, want %q", tt.version, data, tt.gomod)
488 }
489 }
490
491 needHash := !testing.Short() && (tt.zipFileHash != "" || tt.zipSum != "")
492 if tt.zip != nil || tt.zipErr != "" || needHash {
493 f, err := os.CreateTemp(tmpdir, tt.version+".zip.")
494 if err != nil {
495 t.Fatalf("os.CreateTemp: %v", err)
496 }
497 zipfile := f.Name()
498 defer func() {
499 f.Close()
500 os.Remove(zipfile)
501 }()
502
503 var w io.Writer
504 var h hash.Hash
505 if needHash {
506 h = sha256.New()
507 w = io.MultiWriter(f, h)
508 } else {
509 w = f
510 }
511 err = repo.Zip(w, tt.version)
512 f.Close()
513 if err != nil {
514 if tt.zipErr != "" {
515 if err.Error() == tt.zipErr {
516 return
517 }
518 t.Fatalf("repo.Zip(%q): %v, want error %q", tt.version, err, tt.zipErr)
519 }
520 t.Fatalf("repo.Zip(%q): %v", tt.version, err)
521 }
522 if tt.zipErr != "" {
523 t.Errorf("repo.Zip(%q): success, want error %q", tt.version, tt.zipErr)
524 }
525
526 if tt.zip != nil {
527 prefix := tt.path + "@" + tt.version + "/"
528 z, err := zip.OpenReader(zipfile)
529 if err != nil {
530 t.Fatalf("open zip %s: %v", zipfile, err)
531 }
532 var names []string
533 for _, file := range z.File {
534 if !strings.HasPrefix(file.Name, prefix) {
535 t.Errorf("zip entry %v does not start with prefix %v", file.Name, prefix)
536 continue
537 }
538 names = append(names, file.Name[len(prefix):])
539 }
540 z.Close()
541 if !reflect.DeepEqual(names, tt.zip) {
542 t.Fatalf("zip = %v\nwant %v\n", names, tt.zip)
543 }
544 }
545
546 if needHash {
547 sum, err := dirhash.HashZip(zipfile, dirhash.Hash1)
548 if err != nil {
549 t.Errorf("repo.Zip(%q): %v", tt.version, err)
550 } else if sum != tt.zipSum {
551 t.Errorf("repo.Zip(%q): got file with sum %q, want %q", tt.version, sum, tt.zipSum)
552 } else if zipFileHash := hex.EncodeToString(h.Sum(nil)); zipFileHash != tt.zipFileHash {
553 t.Errorf("repo.Zip(%q): got file with hash %q, want %q (but content has correct sum)", tt.version, zipFileHash, tt.zipFileHash)
554 }
555 }
556 }
557 }
558 }
559 t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt))
560 if strings.HasPrefix(tt.path, vgotest1git) {
561 for vcs, alt := range altVgotests {
562 altTest := tt
563 altTest.vcs = vcs
564 altTest.path = alt + strings.TrimPrefix(altTest.path, vgotest1git)
565 if strings.HasPrefix(altTest.mpath, vgotest1git) {
566 altTest.mpath = alt + strings.TrimPrefix(altTest.mpath, vgotest1git)
567 }
568 var m map[string]string
569 if alt == vgotest1hg {
570 m = hgmap
571 }
572 altTest.version = remap(altTest.version, m)
573 altTest.name = remap(altTest.name, m)
574 altTest.short = remap(altTest.short, m)
575 altTest.rev = remap(altTest.rev, m)
576 altTest.err = remap(altTest.err, m)
577 altTest.gomodErr = remap(altTest.gomodErr, m)
578 altTest.zipErr = remap(altTest.zipErr, m)
579 altTest.zipSum = ""
580 altTest.zipFileHash = ""
581 t.Run(strings.ReplaceAll(altTest.path, "/", "_")+"/"+altTest.rev, f(altTest))
582 }
583 }
584 }
585 })
586 }
587
588 var hgmap = map[string]string{
589 "github.com/rsc/vgotest1": "vcs-test.golang.org/hg/vgotest1.hg",
590 "f18795870fb14388a21ef3ebc1d75911c8694f31": "a9ad6d1d14eb544f459f446210c7eb3b009807c6",
591 "ea65f87c8f52c15ea68f3bdd9925ef17e20d91e9": "f1fc0f22021b638d073d31c752847e7bf385def7",
592 "b769f2de407a4db81af9c5de0a06016d60d2ea09": "92c7eb888b4fac17f1c6bd2e1060a1b881a3b832",
593 "8afe2b2efed96e0880ecd2a69b98a53b8c2738b6": "4e58084d459ae7e79c8c2264d0e8e9a92eb5cd44",
594 "2f615117ce481c8efef46e0cc0b4b4dccfac8fea": "879ea98f7743c8eff54f59a918f3a24123d1cf46",
595 "80d85c5d4d17598a0e9055e7c175a32b415d6128": "e125018e286a4b09061079a81e7b537070b7ff71",
596 "1f863feb76bc7029b78b21c5375644838962f88d": "bf63880162304a9337477f3858f5b7e255c75459",
597 "45f53230a74ad275c7127e117ac46914c8126160": "814fce58e83abd5bf2a13892e0b0e1198abefcd4",
598 }
599
600 func remap(name string, m map[string]string) string {
601 if m[name] != "" {
602 return m[name]
603 }
604 if codehost.AllHex(name) {
605 for k, v := range m {
606 if strings.HasPrefix(k, name) {
607 return v[:len(name)]
608 }
609 }
610 }
611 for k, v := range m {
612 name = strings.ReplaceAll(name, k, v)
613 if codehost.AllHex(k) {
614 name = strings.ReplaceAll(name, k[:12], v[:12])
615 }
616 }
617 return name
618 }
619
620 var codeRepoVersionsTests = []struct {
621 vcs string
622 path string
623 prefix string
624 versions []string
625 }{
626 {
627 vcs: "git",
628 path: "github.com/rsc/vgotest1",
629 versions: []string{"v0.0.0", "v0.0.1", "v1.0.0", "v1.0.1", "v1.0.2", "v1.0.3", "v1.1.0"},
630 },
631 {
632 vcs: "git",
633 path: "github.com/rsc/vgotest1",
634 prefix: "v1.0",
635 versions: []string{"v1.0.0", "v1.0.1", "v1.0.2", "v1.0.3"},
636 },
637 {
638 vcs: "git",
639 path: "github.com/rsc/vgotest1/v2",
640 versions: []string{"v2.0.0", "v2.0.1", "v2.0.2", "v2.0.3", "v2.0.4", "v2.0.5", "v2.0.6"},
641 },
642 {
643 vcs: "mod",
644 path: "swtch.com/testmod",
645 versions: []string{"v1.0.0", "v1.1.1"},
646 },
647 {
648 vcs: "git",
649 path: "gopkg.in/natefinch/lumberjack.v2",
650 versions: []string{"v2.0.0"},
651 },
652 }
653
654 func TestCodeRepoVersions(t *testing.T) {
655 testenv.MustHaveExternalNetwork(t)
656
657 tmpdir, err := os.MkdirTemp("", "vgo-modfetch-test-")
658 if err != nil {
659 t.Fatal(err)
660 }
661 defer os.RemoveAll(tmpdir)
662
663 t.Run("parallel", func(t *testing.T) {
664 for _, tt := range codeRepoVersionsTests {
665 t.Run(strings.ReplaceAll(tt.path, "/", "_"), func(t *testing.T) {
666 tt := tt
667 t.Parallel()
668 if tt.vcs != "mod" {
669 testenv.MustHaveExecPath(t, tt.vcs)
670 }
671
672 repo := Lookup("direct", tt.path)
673 list, err := repo.Versions(tt.prefix)
674 if err != nil {
675 t.Fatalf("Versions(%q): %v", tt.prefix, err)
676 }
677 if !reflect.DeepEqual(list, tt.versions) {
678 t.Fatalf("Versions(%q):\nhave %v\nwant %v", tt.prefix, list, tt.versions)
679 }
680 })
681 }
682 })
683 }
684
685 var latestTests = []struct {
686 vcs string
687 path string
688 version string
689 err string
690 }{
691 {
692 vcs: "git",
693 path: "github.com/rsc/empty",
694 err: "no commits",
695 },
696 {
697 vcs: "git",
698 path: "github.com/rsc/vgotest1",
699 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`,
700 },
701 {
702 vcs: "git",
703 path: "github.com/rsc/vgotest1/v2",
704 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`,
705 },
706 {
707 vcs: "git",
708 path: "github.com/rsc/vgotest1/subdir",
709 err: "github.com/rsc/vgotest1/subdir@v0.0.0-20180219223237-a08abb797a67: invalid version: missing github.com/rsc/vgotest1/subdir/go.mod at revision a08abb797a67",
710 },
711 {
712 vcs: "git",
713 path: "vcs-test.golang.org/git/commit-after-tag.git",
714 version: "v1.0.1-0.20190715211727-b325d8217783",
715 },
716 {
717 vcs: "git",
718 path: "vcs-test.golang.org/git/no-tags.git",
719 version: "v0.0.0-20190715212047-e706ba1d9f6d",
720 },
721 {
722 vcs: "mod",
723 path: "swtch.com/testmod",
724 version: "v1.1.1",
725 },
726 }
727
728 func TestLatest(t *testing.T) {
729 testenv.MustHaveExternalNetwork(t)
730
731 tmpdir, err := os.MkdirTemp("", "vgo-modfetch-test-")
732 if err != nil {
733 t.Fatal(err)
734 }
735 defer os.RemoveAll(tmpdir)
736
737 t.Run("parallel", func(t *testing.T) {
738 for _, tt := range latestTests {
739 name := strings.ReplaceAll(tt.path, "/", "_")
740 t.Run(name, func(t *testing.T) {
741 tt := tt
742 t.Parallel()
743 if tt.vcs != "mod" {
744 testenv.MustHaveExecPath(t, tt.vcs)
745 }
746
747 repo := Lookup("direct", tt.path)
748 info, err := repo.Latest()
749 if err != nil {
750 if tt.err != "" {
751 if err.Error() == tt.err {
752 return
753 }
754 t.Fatalf("Latest(): %v, want %q", err, tt.err)
755 }
756 t.Fatalf("Latest(): %v", err)
757 }
758 if tt.err != "" {
759 t.Fatalf("Latest() = %v, want error %q", info.Version, tt.err)
760 }
761 if info.Version != tt.version {
762 t.Fatalf("Latest() = %v, want %v", info.Version, tt.version)
763 }
764 })
765 }
766 })
767 }
768
769
770 type fixedTagsRepo struct {
771 tags []string
772 codehost.Repo
773 }
774
775 func (ch *fixedTagsRepo) Tags(string) ([]string, error) { return ch.tags, nil }
776
777 func TestNonCanonicalSemver(t *testing.T) {
778 root := "golang.org/x/issue24476"
779 ch := &fixedTagsRepo{
780 tags: []string{
781 "", "huh?", "1.0.1",
782
783 "v1.🐕.🐄",
784 "v1", "v0.1",
785
786 "v1.0.1",
787 },
788 }
789
790 cr, err := newCodeRepo(ch, root, root)
791 if err != nil {
792 t.Fatal(err)
793 }
794
795 v, err := cr.Versions("")
796 if err != nil {
797 t.Fatal(err)
798 }
799 if len(v) != 1 || v[0] != "v1.0.1" {
800 t.Fatal("unexpected versions returned:", v)
801 }
802 }
803
View as plain text