1
2
3
4
5 package codehost
6
7 import (
8 "archive/zip"
9 "bytes"
10 "cmd/go/internal/cfg"
11 "cmd/go/internal/vcweb/vcstest"
12 "context"
13 "flag"
14 "internal/testenv"
15 "io"
16 "io/fs"
17 "log"
18 "os"
19 "os/exec"
20 "path"
21 "path/filepath"
22 "reflect"
23 "regexp"
24 "runtime"
25 "strings"
26 "sync"
27 "testing"
28 "time"
29
30 "golang.org/x/mod/semver"
31 )
32
33 func TestMain(m *testing.M) {
34 flag.Parse()
35 if err := testMain(m); err != nil {
36 log.Fatal(err)
37 }
38 }
39
40 var gitrepo1, gitsha256repo, hgrepo1, vgotest1 string
41
42 var altRepos = func() []string {
43 return []string{
44 "localGitRepo",
45 hgrepo1,
46 }
47 }
48
49
50
51
52
53
54
55
56 var localGitRepo string
57
58
59 func localGitURL(t testing.TB) string {
60 testenv.MustHaveExecPath(t, "git")
61 if runtime.GOOS == "android" && strings.HasSuffix(testenv.Builder(), "-corellium") {
62 testenv.SkipFlaky(t, 59940)
63 }
64
65 localGitURLOnce.Do(func() {
66
67
68
69
70 _, localGitURLErr = Run(context.Background(), "", "git", "clone", "--mirror", gitrepo1, localGitRepo)
71 if localGitURLErr != nil {
72 return
73 }
74 repo := gitRepo{dir: localGitRepo}
75 _, localGitURLErr = repo.runGit(context.Background(), "git", "config", "daemon.uploadarch", "true")
76
77 })
78
79 if localGitURLErr != nil {
80 t.Fatal(localGitURLErr)
81 }
82
83
84
85 if strings.HasPrefix(localGitRepo, "/") {
86 return "file://" + localGitRepo
87 } else {
88 return "file:///" + filepath.ToSlash(localGitRepo)
89 }
90 }
91
92 var (
93 localGitURLOnce sync.Once
94 localGitURLErr error
95 )
96
97 func testMain(m *testing.M) (err error) {
98 cfg.BuildX = testing.Verbose()
99
100 srv, err := vcstest.NewServer()
101 if err != nil {
102 return err
103 }
104 defer func() {
105 if closeErr := srv.Close(); err == nil {
106 err = closeErr
107 }
108 }()
109
110 gitrepo1 = srv.HTTP.URL + "/git/gitrepo1"
111 gitsha256repo = srv.HTTP.URL + "/git/gitrepo-sha256"
112 hgrepo1 = srv.HTTP.URL + "/hg/hgrepo1"
113 vgotest1 = srv.HTTP.URL + "/git/vgotest1"
114
115 dir, err := os.MkdirTemp("", "gitrepo-test-")
116 if err != nil {
117 return err
118 }
119 defer func() {
120 if rmErr := os.RemoveAll(dir); err == nil {
121 err = rmErr
122 }
123 }()
124
125 localGitRepo = filepath.Join(dir, "gitrepo2")
126
127
128
129 cfg.GOMODCACHE = filepath.Join(dir, "modcache")
130 cfg.ModCacheRW = true
131
132 m.Run()
133 return nil
134 }
135
136 func testContext(t testing.TB) context.Context {
137 w := newTestWriter(t)
138 return cfg.WithBuildXWriter(context.Background(), w)
139 }
140
141
142
143
144
145
146 type testWriter struct {
147 t testing.TB
148
149 mu sync.Mutex
150 buf bytes.Buffer
151 }
152
153 func newTestWriter(t testing.TB) *testWriter {
154 w := &testWriter{t: t}
155
156 t.Cleanup(func() {
157 w.mu.Lock()
158 defer w.mu.Unlock()
159 if b := w.buf.Bytes(); len(b) > 0 {
160 w.t.Logf("%s", b)
161 w.buf.Reset()
162 }
163 })
164
165 return w
166 }
167
168 func (w *testWriter) Write(p []byte) (int, error) {
169 w.mu.Lock()
170 defer w.mu.Unlock()
171 n, err := w.buf.Write(p)
172 if b := w.buf.Bytes(); len(b) > 0 && b[len(b)-1] == '\n' {
173 w.t.Logf("%s", b)
174 w.buf.Reset()
175 }
176 return n, err
177 }
178
179 func testRepo(ctx context.Context, t *testing.T, remote string) (Repo, error) {
180 if remote == "localGitRepo" {
181 return NewRepo(ctx, "git", localGitURL(t), false)
182 }
183 vcsName := "git"
184 for _, k := range []string{"hg"} {
185 if strings.Contains(remote, "/"+k+"/") {
186 vcsName = k
187 }
188 }
189 if testing.Short() && vcsName == "hg" {
190 t.Skipf("skipping hg test in short mode: hg is slow")
191 }
192 testenv.MustHaveExecPath(t, vcsName)
193 if runtime.GOOS == "android" && strings.HasSuffix(testenv.Builder(), "-corellium") {
194 testenv.SkipFlaky(t, 59940)
195 }
196 return NewRepo(ctx, vcsName, remote, false)
197 }
198
199 var gitVersLineExtract = regexp.MustCompile(`git version\s+([\d.]+)`)
200
201 func gitVersion(t testing.TB) string {
202 gitOut, runErr := exec.Command("git", "version").CombinedOutput()
203 if runErr != nil {
204 t.Logf("failed to execute git version: %s", runErr)
205 return "v0"
206 }
207 matches := gitVersLineExtract.FindSubmatch(gitOut)
208 if len(matches) < 2 {
209 t.Logf("git version extraction regexp did not match version line: %q", gitOut)
210 return "v0"
211 }
212 return "v" + string(matches[1])
213 }
214
215 const minGitSHA256Vers = "v2.29"
216
217 func TestTags(t *testing.T) {
218 t.Parallel()
219
220 gitVers := gitVersion(t)
221
222 type tagsTest struct {
223 repo string
224 prefix string
225 tags []Tag
226 }
227
228 runTest := func(tt tagsTest) func(*testing.T) {
229 return func(t *testing.T) {
230 t.Parallel()
231 if tt.repo == gitsha256repo && semver.Compare(gitVers, minGitSHA256Vers) < 0 {
232 t.Skipf("git version is too old (%+v); skipping git sha256 test", gitVers)
233 }
234 ctx := testContext(t)
235
236 r, err := testRepo(ctx, t, tt.repo)
237 if err != nil {
238 t.Fatal(err)
239 }
240 tags, err := r.Tags(ctx, tt.prefix)
241 if err != nil {
242 t.Fatal(err)
243 }
244 if tags == nil || !reflect.DeepEqual(tags.List, tt.tags) {
245 t.Errorf("Tags(%q): incorrect tags\nhave %v\nwant %v", tt.prefix, tags, tt.tags)
246 }
247 }
248 }
249
250 for _, tt := range []tagsTest{
251 {gitrepo1, "xxx", []Tag{}},
252 {gitrepo1, "", []Tag{
253 {"v1.2.3", "ede458df7cd0fdca520df19a33158086a8a68e81"},
254 {"v1.2.4-annotated", "ede458df7cd0fdca520df19a33158086a8a68e81"},
255 {"v2.0.1", "76a00fb249b7f93091bc2c89a789dab1fc1bc26f"},
256 {"v2.0.2", "9d02800338b8a55be062c838d1f02e0c5780b9eb"},
257 {"v2.3", "76a00fb249b7f93091bc2c89a789dab1fc1bc26f"},
258 }},
259 {gitrepo1, "v", []Tag{
260 {"v1.2.3", "ede458df7cd0fdca520df19a33158086a8a68e81"},
261 {"v1.2.4-annotated", "ede458df7cd0fdca520df19a33158086a8a68e81"},
262 {"v2.0.1", "76a00fb249b7f93091bc2c89a789dab1fc1bc26f"},
263 {"v2.0.2", "9d02800338b8a55be062c838d1f02e0c5780b9eb"},
264 {"v2.3", "76a00fb249b7f93091bc2c89a789dab1fc1bc26f"},
265 }},
266 {gitrepo1, "v1", []Tag{
267 {"v1.2.3", "ede458df7cd0fdca520df19a33158086a8a68e81"},
268 {"v1.2.4-annotated", "ede458df7cd0fdca520df19a33158086a8a68e81"},
269 }},
270 {gitrepo1, "2", []Tag{}},
271 {gitsha256repo, "xxx", []Tag{}},
272 {gitsha256repo, "", []Tag{
273 {"v1.2.3", "47b8b51b2a2d9d5caa3d460096c4e01f05700ce3a9390deb54400bd508214c5c"},
274 {"v1.2.4-annotated", "47b8b51b2a2d9d5caa3d460096c4e01f05700ce3a9390deb54400bd508214c5c"},
275 {"v1.3.0", "a9157cad2aa6dc2f78aa31fced5887f04e758afa8703f04d0178702ebf04ee17"},
276 {"v2.0.1", "b7550fd9d2129c724c39ae0536e8b2fae4364d8c82bb8b0880c9b71f67295d09"},
277 {"v2.0.2", "1401e4e1fdb4169b51d44a1ff62af63ccc708bf5c12d15051268b51bbb6cbd82"},
278 {"v2.3", "b7550fd9d2129c724c39ae0536e8b2fae4364d8c82bb8b0880c9b71f67295d09"},
279 }},
280 {gitsha256repo, "v", []Tag{
281 {"v1.2.3", "47b8b51b2a2d9d5caa3d460096c4e01f05700ce3a9390deb54400bd508214c5c"},
282 {"v1.2.4-annotated", "47b8b51b2a2d9d5caa3d460096c4e01f05700ce3a9390deb54400bd508214c5c"},
283 {"v1.3.0", "a9157cad2aa6dc2f78aa31fced5887f04e758afa8703f04d0178702ebf04ee17"},
284 {"v2.0.1", "b7550fd9d2129c724c39ae0536e8b2fae4364d8c82bb8b0880c9b71f67295d09"},
285 {"v2.0.2", "1401e4e1fdb4169b51d44a1ff62af63ccc708bf5c12d15051268b51bbb6cbd82"},
286 {"v2.3", "b7550fd9d2129c724c39ae0536e8b2fae4364d8c82bb8b0880c9b71f67295d09"},
287 }},
288 {gitsha256repo, "v1", []Tag{
289 {"v1.2.3", "47b8b51b2a2d9d5caa3d460096c4e01f05700ce3a9390deb54400bd508214c5c"},
290 {"v1.2.4-annotated", "47b8b51b2a2d9d5caa3d460096c4e01f05700ce3a9390deb54400bd508214c5c"},
291 {"v1.3.0", "a9157cad2aa6dc2f78aa31fced5887f04e758afa8703f04d0178702ebf04ee17"},
292 }},
293 {gitsha256repo, "2", []Tag{}},
294 } {
295 t.Run(path.Base(tt.repo)+"/"+tt.prefix, runTest(tt))
296 if tt.repo == gitrepo1 {
297
298 clearTags := []Tag{}
299 for _, tag := range tt.tags {
300 clearTags = append(clearTags, Tag{tag.Name, ""})
301 }
302 tags := tt.tags
303 for _, tt.repo = range altRepos() {
304 if strings.Contains(tt.repo, "Git") {
305 tt.tags = tags
306 } else {
307 tt.tags = clearTags
308 }
309 t.Run(path.Base(tt.repo)+"/"+tt.prefix, runTest(tt))
310 }
311 }
312 }
313 }
314
315 func TestLatest(t *testing.T) {
316 t.Parallel()
317
318 gitVers := gitVersion(t)
319
320 type latestTest struct {
321 repo string
322 info *RevInfo
323 }
324 runTest := func(tt latestTest) func(*testing.T) {
325 return func(t *testing.T) {
326 t.Parallel()
327 ctx := testContext(t)
328
329 if tt.repo == gitsha256repo && semver.Compare(gitVers, minGitSHA256Vers) < 0 {
330 t.Skipf("git version is too old (%+v); skipping git sha256 test", gitVers)
331 }
332
333 r, err := testRepo(ctx, t, tt.repo)
334 if err != nil {
335 t.Fatal(err)
336 }
337 info, err := r.Latest(ctx)
338 if err != nil {
339 t.Fatal(err)
340 }
341 if !reflect.DeepEqual(info, tt.info) {
342 t.Errorf("Latest: incorrect info\nhave %+v (origin %+v)\nwant %+v (origin %+v)", info, info.Origin, tt.info, tt.info.Origin)
343 }
344 }
345 }
346
347 for _, tt := range []latestTest{
348 {
349 gitrepo1,
350 &RevInfo{
351 Origin: &Origin{
352 VCS: "git",
353 URL: gitrepo1,
354 Ref: "HEAD",
355 Hash: "ede458df7cd0fdca520df19a33158086a8a68e81",
356 },
357 Name: "ede458df7cd0fdca520df19a33158086a8a68e81",
358 Short: "ede458df7cd0",
359 Version: "ede458df7cd0fdca520df19a33158086a8a68e81",
360 Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
361 Tags: []string{"v1.2.3", "v1.2.4-annotated"},
362 },
363 },
364 {
365 gitsha256repo,
366 &RevInfo{
367 Origin: &Origin{
368 VCS: "git",
369 URL: gitsha256repo,
370 Ref: "HEAD",
371 Hash: "47b8b51b2a2d9d5caa3d460096c4e01f05700ce3a9390deb54400bd508214c5c",
372 },
373 Name: "47b8b51b2a2d9d5caa3d460096c4e01f05700ce3a9390deb54400bd508214c5c",
374 Short: "47b8b51b2a2d",
375 Version: "47b8b51b2a2d9d5caa3d460096c4e01f05700ce3a9390deb54400bd508214c5c",
376 Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
377 Tags: []string{"v1.2.3", "v1.2.4-annotated"},
378 },
379 },
380 {
381 hgrepo1,
382 &RevInfo{
383 Origin: &Origin{
384 VCS: "hg",
385 URL: hgrepo1,
386 Hash: "18518c07eb8ed5c80221e997e518cccaa8c0c287",
387 },
388 Name: "18518c07eb8ed5c80221e997e518cccaa8c0c287",
389 Short: "18518c07eb8e",
390 Version: "18518c07eb8ed5c80221e997e518cccaa8c0c287",
391 Time: time.Date(2018, 6, 27, 16, 16, 30, 0, time.UTC),
392 },
393 },
394 } {
395 t.Run(path.Base(tt.repo), runTest(tt))
396 if tt.repo == gitrepo1 {
397 tt.repo = "localGitRepo"
398 info := *tt.info
399 tt.info = &info
400 o := *info.Origin
401 info.Origin = &o
402 o.URL = localGitURL(t)
403 t.Run(path.Base(tt.repo), runTest(tt))
404 }
405 }
406 }
407
408 func TestReadFile(t *testing.T) {
409 t.Parallel()
410
411 gitVers := gitVersion(t)
412
413 type readFileTest struct {
414 repo string
415 rev string
416 file string
417 err string
418 data string
419 }
420 runTest := func(tt readFileTest) func(*testing.T) {
421 return func(t *testing.T) {
422 t.Parallel()
423 ctx := testContext(t)
424
425 if tt.repo == gitsha256repo && semver.Compare(gitVers, minGitSHA256Vers) < 0 {
426 t.Skipf("git version is too old (%+v); skipping git sha256 test", gitVers)
427 }
428
429 r, err := testRepo(ctx, t, tt.repo)
430 if err != nil {
431 t.Fatal(err)
432 }
433 data, err := r.ReadFile(ctx, tt.rev, tt.file, 100)
434 if err != nil {
435 if tt.err == "" {
436 t.Fatalf("ReadFile: unexpected error %v", err)
437 }
438 if !strings.Contains(err.Error(), tt.err) {
439 t.Fatalf("ReadFile: wrong error %q, want %q", err, tt.err)
440 }
441 if len(data) != 0 {
442 t.Errorf("ReadFile: non-empty data %q with error %v", data, err)
443 }
444 return
445 }
446 if tt.err != "" {
447 t.Fatalf("ReadFile: no error, wanted %v", tt.err)
448 }
449 if string(data) != tt.data {
450 t.Errorf("ReadFile: incorrect data\nhave %q\nwant %q", data, tt.data)
451 }
452 }
453 }
454
455 for _, tt := range []readFileTest{
456 {
457 repo: gitrepo1,
458 rev: "latest",
459 file: "README",
460 data: "",
461 },
462 {
463 repo: gitrepo1,
464 rev: "v2",
465 file: "another.txt",
466 data: "another\n",
467 },
468 {
469 repo: gitrepo1,
470 rev: "v2.3.4",
471 file: "another.txt",
472 err: fs.ErrNotExist.Error(),
473 },
474 {
475 repo: gitsha256repo,
476 rev: "latest",
477 file: "README",
478 data: "",
479 },
480 {
481 repo: gitsha256repo,
482 rev: "v2",
483 file: "another.txt",
484 data: "another\n",
485 },
486 {
487 repo: gitsha256repo,
488 rev: "v2.3.4",
489 file: "another.txt",
490 err: fs.ErrNotExist.Error(),
491 },
492 } {
493 t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.file, runTest(tt))
494 if tt.repo == gitrepo1 {
495 for _, tt.repo = range altRepos() {
496 t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.file, runTest(tt))
497 }
498 }
499 }
500 }
501
502 type zipFile struct {
503 name string
504 size int64
505 }
506
507 func TestReadZip(t *testing.T) {
508 t.Parallel()
509
510 gitVers := gitVersion(t)
511
512 type readZipTest struct {
513 repo string
514 rev string
515 subdir string
516 err string
517 files map[string]uint64
518 }
519 runTest := func(tt readZipTest) func(*testing.T) {
520 return func(t *testing.T) {
521 t.Parallel()
522 ctx := testContext(t)
523
524 if tt.repo == gitsha256repo && semver.Compare(gitVers, minGitSHA256Vers) < 0 {
525 t.Skipf("git version is too old (%+v); skipping git sha256 test", gitVers)
526 }
527
528 r, err := testRepo(ctx, t, tt.repo)
529 if err != nil {
530 t.Fatal(err)
531 }
532 rc, err := r.ReadZip(ctx, tt.rev, tt.subdir, 100000)
533 if err != nil {
534 if tt.err == "" {
535 t.Fatalf("ReadZip: unexpected error %v", err)
536 }
537 if !strings.Contains(err.Error(), tt.err) {
538 t.Fatalf("ReadZip: wrong error %q, want %q", err, tt.err)
539 }
540 if rc != nil {
541 t.Errorf("ReadZip: non-nil io.ReadCloser with error %v", err)
542 }
543 return
544 }
545 defer rc.Close()
546 if tt.err != "" {
547 t.Fatalf("ReadZip: no error, wanted %v", tt.err)
548 }
549 zipdata, err := io.ReadAll(rc)
550 if err != nil {
551 t.Fatal(err)
552 }
553 z, err := zip.NewReader(bytes.NewReader(zipdata), int64(len(zipdata)))
554 if err != nil {
555 t.Fatalf("ReadZip: cannot read zip file: %v", err)
556 }
557 have := make(map[string]bool)
558 for _, f := range z.File {
559 size, ok := tt.files[f.Name]
560 if !ok {
561 t.Errorf("ReadZip: unexpected file %s", f.Name)
562 continue
563 }
564 have[f.Name] = true
565 if size != ^uint64(0) && f.UncompressedSize64 != size {
566 t.Errorf("ReadZip: file %s has unexpected size %d != %d", f.Name, f.UncompressedSize64, size)
567 }
568 }
569 for name := range tt.files {
570 if !have[name] {
571 t.Errorf("ReadZip: missing file %s", name)
572 }
573 }
574 }
575 }
576
577 for _, tt := range []readZipTest{
578 {
579 repo: gitrepo1,
580 rev: "v2.3.4",
581 subdir: "",
582 files: map[string]uint64{
583 "prefix/": 0,
584 "prefix/README": 0,
585 "prefix/v2": 3,
586 },
587 },
588 {
589 repo: gitsha256repo,
590 rev: "v2.3.4",
591 subdir: "",
592 files: map[string]uint64{
593 "prefix/": 0,
594 "prefix/README": 0,
595 "prefix/v2": 3,
596 },
597 },
598 {
599 repo: hgrepo1,
600 rev: "v2.3.4",
601 subdir: "",
602 files: map[string]uint64{
603 "prefix/.hg_archival.txt": ^uint64(0),
604 "prefix/README": 0,
605 "prefix/v2": 3,
606 },
607 },
608
609 {
610 repo: gitrepo1,
611 rev: "v2",
612 subdir: "",
613 files: map[string]uint64{
614 "prefix/": 0,
615 "prefix/README": 0,
616 "prefix/v2": 3,
617 "prefix/another.txt": 8,
618 "prefix/foo.txt": 13,
619 },
620 },
621 {
622 repo: gitsha256repo,
623 rev: "v2",
624 subdir: "",
625 files: map[string]uint64{
626 "prefix/": 0,
627 "prefix/README": 0,
628 "prefix/v2": 3,
629 "prefix/another.txt": 8,
630 "prefix/foo.txt": 13,
631 },
632 },
633 {
634 repo: hgrepo1,
635 rev: "v2",
636 subdir: "",
637 files: map[string]uint64{
638 "prefix/.hg_archival.txt": ^uint64(0),
639 "prefix/README": 0,
640 "prefix/v2": 3,
641 "prefix/another.txt": 8,
642 "prefix/foo.txt": 13,
643 },
644 },
645
646 {
647 repo: gitrepo1,
648 rev: "v3",
649 subdir: "",
650 files: map[string]uint64{
651 "prefix/": 0,
652 "prefix/v3/": 0,
653 "prefix/v3/sub/": 0,
654 "prefix/v3/sub/dir/": 0,
655 "prefix/v3/sub/dir/file.txt": 16,
656 "prefix/README": 0,
657 },
658 },
659 {
660 repo: gitsha256repo,
661 rev: "v3",
662 subdir: "",
663 files: map[string]uint64{
664 "prefix/": 0,
665 "prefix/v3/": 0,
666 "prefix/v3/sub/": 0,
667 "prefix/v3/sub/dir/": 0,
668 "prefix/v3/sub/dir/file.txt": 16,
669 "prefix/README": 0,
670 },
671 },
672 {
673 repo: hgrepo1,
674 rev: "v3",
675 subdir: "",
676 files: map[string]uint64{
677 "prefix/.hg_archival.txt": ^uint64(0),
678 "prefix/.hgtags": 405,
679 "prefix/v3/sub/dir/file.txt": 16,
680 "prefix/README": 0,
681 },
682 },
683
684 {
685 repo: gitrepo1,
686 rev: "v3",
687 subdir: "v3/sub/dir",
688 files: map[string]uint64{
689 "prefix/": 0,
690 "prefix/v3/": 0,
691 "prefix/v3/sub/": 0,
692 "prefix/v3/sub/dir/": 0,
693 "prefix/v3/sub/dir/file.txt": 16,
694 },
695 },
696 {
697 repo: gitsha256repo,
698 rev: "v3",
699 subdir: "v3/sub/dir",
700 files: map[string]uint64{
701 "prefix/": 0,
702 "prefix/v3/": 0,
703 "prefix/v3/sub/": 0,
704 "prefix/v3/sub/dir/": 0,
705 "prefix/v3/sub/dir/file.txt": 16,
706 },
707 },
708 {
709 repo: hgrepo1,
710 rev: "v3",
711 subdir: "v3/sub/dir",
712 files: map[string]uint64{
713 "prefix/v3/sub/dir/file.txt": 16,
714 },
715 },
716
717 {
718 repo: gitrepo1,
719 rev: "v3",
720 subdir: "v3/sub",
721 files: map[string]uint64{
722 "prefix/": 0,
723 "prefix/v3/": 0,
724 "prefix/v3/sub/": 0,
725 "prefix/v3/sub/dir/": 0,
726 "prefix/v3/sub/dir/file.txt": 16,
727 },
728 },
729 {
730 repo: gitsha256repo,
731 rev: "v3",
732 subdir: "v3/sub",
733 files: map[string]uint64{
734 "prefix/": 0,
735 "prefix/v3/": 0,
736 "prefix/v3/sub/": 0,
737 "prefix/v3/sub/dir/": 0,
738 "prefix/v3/sub/dir/file.txt": 16,
739 },
740 },
741 {
742 repo: hgrepo1,
743 rev: "v3",
744 subdir: "v3/sub",
745 files: map[string]uint64{
746 "prefix/v3/sub/dir/file.txt": 16,
747 },
748 },
749
750 {
751 repo: gitrepo1,
752 rev: "aaaaaaaaab",
753 subdir: "",
754 err: "unknown revision",
755 },
756 {
757 repo: gitsha256repo,
758 rev: "aaaaaaaaab",
759 subdir: "",
760 err: "unknown revision",
761 },
762 {
763 repo: hgrepo1,
764 rev: "aaaaaaaaab",
765 subdir: "",
766 err: "unknown revision",
767 },
768
769 {
770 repo: vgotest1,
771 rev: "submod/v1.0.4",
772 subdir: "submod",
773 files: map[string]uint64{
774 "prefix/": 0,
775 "prefix/submod/": 0,
776 "prefix/submod/go.mod": 53,
777 "prefix/submod/pkg/": 0,
778 "prefix/submod/pkg/p.go": 31,
779 },
780 },
781 } {
782 t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.subdir, runTest(tt))
783 if tt.repo == gitrepo1 {
784 tt.repo = "localGitRepo"
785 t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.subdir, runTest(tt))
786 }
787 }
788 }
789
790 var hgmap = map[string]string{
791 "HEAD": "41964ddce1180313bdc01d0a39a2813344d6261d",
792 "9d02800338b8a55be062c838d1f02e0c5780b9eb": "8f49ee7a6ddcdec6f0112d9dca48d4a2e4c3c09e",
793 "76a00fb249b7f93091bc2c89a789dab1fc1bc26f": "88fde824ec8b41a76baa16b7e84212cee9f3edd0",
794 "ede458df7cd0fdca520df19a33158086a8a68e81": "41964ddce1180313bdc01d0a39a2813344d6261d",
795 "97f6aa59c81c623494825b43d39e445566e429a4": "c0cbbfb24c7c3c50c35c7b88e7db777da4ff625d",
796 }
797
798 func TestStat(t *testing.T) {
799 t.Parallel()
800
801 gitVers := gitVersion(t)
802
803 type statTest struct {
804 repo string
805 rev string
806 err string
807 info *RevInfo
808 }
809 runTest := func(tt statTest) func(*testing.T) {
810 return func(t *testing.T) {
811 t.Parallel()
812 ctx := testContext(t)
813
814 if tt.repo == gitsha256repo && semver.Compare(gitVers, minGitSHA256Vers) < 0 {
815 t.Skipf("git version is too old (%+v); skipping git sha256 test", gitVers)
816 }
817
818 r, err := testRepo(ctx, t, tt.repo)
819 if err != nil {
820 t.Fatal(err)
821 }
822 info, err := r.Stat(ctx, tt.rev)
823 if err != nil {
824 if tt.err == "" {
825 t.Fatalf("Stat: unexpected error %v", err)
826 }
827 if !strings.Contains(err.Error(), tt.err) {
828 t.Fatalf("Stat: wrong error %q, want %q", err, tt.err)
829 }
830 if info != nil && info.Origin == nil {
831 t.Errorf("Stat: non-nil info with nil Origin with error %q", err)
832 }
833 return
834 }
835 info.Origin = nil
836 if !reflect.DeepEqual(info, tt.info) {
837 t.Errorf("Stat: incorrect info\nhave %+v\nwant %+v", *info, *tt.info)
838 }
839 }
840 }
841
842 for _, tt := range []statTest{
843 {
844 repo: gitrepo1,
845 rev: "HEAD",
846 info: &RevInfo{
847 Name: "ede458df7cd0fdca520df19a33158086a8a68e81",
848 Short: "ede458df7cd0",
849 Version: "ede458df7cd0fdca520df19a33158086a8a68e81",
850 Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
851 Tags: []string{"v1.2.3", "v1.2.4-annotated"},
852 },
853 },
854 {
855 repo: gitrepo1,
856 rev: "v2",
857 info: &RevInfo{
858 Name: "9d02800338b8a55be062c838d1f02e0c5780b9eb",
859 Short: "9d02800338b8",
860 Version: "9d02800338b8a55be062c838d1f02e0c5780b9eb",
861 Time: time.Date(2018, 4, 17, 20, 00, 32, 0, time.UTC),
862 Tags: []string{"v2.0.2"},
863 },
864 },
865 {
866 repo: gitrepo1,
867 rev: "v2.3.4",
868 info: &RevInfo{
869 Name: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f",
870 Short: "76a00fb249b7",
871 Version: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f",
872 Time: time.Date(2018, 4, 17, 19, 45, 48, 0, time.UTC),
873 Tags: []string{"v2.0.1", "v2.3"},
874 },
875 },
876 {
877 repo: gitrepo1,
878 rev: "v2.3",
879 info: &RevInfo{
880 Name: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f",
881 Short: "76a00fb249b7",
882 Version: "v2.3",
883 Time: time.Date(2018, 4, 17, 19, 45, 48, 0, time.UTC),
884 Tags: []string{"v2.0.1", "v2.3"},
885 },
886 },
887 {
888 repo: gitrepo1,
889 rev: "v1.2.3",
890 info: &RevInfo{
891 Name: "ede458df7cd0fdca520df19a33158086a8a68e81",
892 Short: "ede458df7cd0",
893 Version: "v1.2.3",
894 Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
895 Tags: []string{"v1.2.3", "v1.2.4-annotated"},
896 },
897 },
898 {
899 repo: gitrepo1,
900 rev: "ede458df",
901 info: &RevInfo{
902 Name: "ede458df7cd0fdca520df19a33158086a8a68e81",
903 Short: "ede458df7cd0",
904 Version: "ede458df7cd0fdca520df19a33158086a8a68e81",
905 Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
906 Tags: []string{"v1.2.3", "v1.2.4-annotated"},
907 },
908 },
909 {
910 repo: gitrepo1,
911 rev: "97f6aa59",
912 info: &RevInfo{
913 Name: "97f6aa59c81c623494825b43d39e445566e429a4",
914 Short: "97f6aa59c81c",
915 Version: "97f6aa59c81c623494825b43d39e445566e429a4",
916 Time: time.Date(2018, 4, 17, 20, 0, 19, 0, time.UTC),
917 },
918 },
919 {
920 repo: gitrepo1,
921 rev: "v1.2.4-annotated",
922 info: &RevInfo{
923 Name: "ede458df7cd0fdca520df19a33158086a8a68e81",
924 Short: "ede458df7cd0",
925 Version: "v1.2.4-annotated",
926 Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
927 Tags: []string{"v1.2.3", "v1.2.4-annotated"},
928 },
929 },
930 {
931 repo: gitrepo1,
932 rev: "aaaaaaaaab",
933 err: "unknown revision",
934 },
935 {
936 repo: gitsha256repo,
937 rev: "HEAD",
938 info: &RevInfo{
939 Name: "47b8b51b2a2d9d5caa3d460096c4e01f05700ce3a9390deb54400bd508214c5c",
940 Short: "47b8b51b2a2d",
941 Version: "47b8b51b2a2d9d5caa3d460096c4e01f05700ce3a9390deb54400bd508214c5c",
942 Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
943 Tags: []string{"v1.2.3", "v1.2.4-annotated"},
944 },
945 },
946 {
947 repo: gitsha256repo,
948 rev: "v2",
949 info: &RevInfo{
950 Name: "1401e4e1fdb4169b51d44a1ff62af63ccc708bf5c12d15051268b51bbb6cbd82",
951 Short: "1401e4e1fdb4",
952 Version: "1401e4e1fdb4169b51d44a1ff62af63ccc708bf5c12d15051268b51bbb6cbd82",
953 Time: time.Date(2018, 4, 17, 20, 00, 32, 0, time.UTC),
954 Tags: []string{"v2.0.2"},
955 },
956 },
957 {
958 repo: gitsha256repo,
959 rev: "v2.3.4",
960 info: &RevInfo{
961 Name: "b7550fd9d2129c724c39ae0536e8b2fae4364d8c82bb8b0880c9b71f67295d09",
962 Short: "b7550fd9d212",
963 Version: "b7550fd9d2129c724c39ae0536e8b2fae4364d8c82bb8b0880c9b71f67295d09",
964 Time: time.Date(2018, 4, 17, 19, 45, 48, 0, time.UTC),
965 Tags: []string{"v2.0.1", "v2.3"},
966 },
967 },
968 {
969 repo: gitsha256repo,
970 rev: "v2.3",
971 info: &RevInfo{
972 Name: "b7550fd9d2129c724c39ae0536e8b2fae4364d8c82bb8b0880c9b71f67295d09",
973 Short: "b7550fd9d212",
974 Version: "v2.3",
975 Time: time.Date(2018, 4, 17, 19, 45, 48, 0, time.UTC),
976 Tags: []string{"v2.0.1", "v2.3"},
977 },
978 },
979 {
980 repo: gitsha256repo,
981 rev: "v1.2.3",
982 info: &RevInfo{
983 Name: "47b8b51b2a2d9d5caa3d460096c4e01f05700ce3a9390deb54400bd508214c5c",
984 Short: "47b8b51b2a2d",
985 Version: "v1.2.3",
986 Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
987 Tags: []string{"v1.2.3", "v1.2.4-annotated"},
988 },
989 },
990 {
991 repo: gitsha256repo,
992 rev: "47b8b51b",
993 info: &RevInfo{
994 Name: "47b8b51b2a2d9d5caa3d460096c4e01f05700ce3a9390deb54400bd508214c5c",
995 Short: "47b8b51b2a2d",
996 Version: "47b8b51b2a2d9d5caa3d460096c4e01f05700ce3a9390deb54400bd508214c5c",
997 Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
998 Tags: []string{"v1.2.3", "v1.2.4-annotated"},
999 },
1000 },
1001 {
1002 repo: gitsha256repo,
1003 rev: "0be440b6",
1004 info: &RevInfo{
1005 Name: "0be440b60b6c81be26c7256781d8e57112ec46c8cd1a9481a8e78a283f10570c",
1006 Short: "0be440b60b6c",
1007 Version: "0be440b60b6c81be26c7256781d8e57112ec46c8cd1a9481a8e78a283f10570c",
1008 Time: time.Date(2018, 4, 17, 20, 0, 19, 0, time.UTC),
1009 },
1010 },
1011 {
1012 repo: gitsha256repo,
1013 rev: "v1.2.4-annotated",
1014 info: &RevInfo{
1015 Name: "47b8b51b2a2d9d5caa3d460096c4e01f05700ce3a9390deb54400bd508214c5c",
1016 Short: "47b8b51b2a2d",
1017 Version: "v1.2.4-annotated",
1018 Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
1019 Tags: []string{"v1.2.3", "v1.2.4-annotated"},
1020 },
1021 },
1022 {
1023 repo: gitsha256repo,
1024 rev: "aaaaaaaaab",
1025 err: "unknown revision",
1026 },
1027 } {
1028 t.Run(path.Base(tt.repo)+"/"+tt.rev, runTest(tt))
1029 if tt.repo == gitrepo1 {
1030 for _, tt.repo = range altRepos() {
1031 old := tt
1032 var m map[string]string
1033 if tt.repo == hgrepo1 {
1034 m = hgmap
1035 }
1036 if tt.info != nil {
1037 info := *tt.info
1038 tt.info = &info
1039 tt.info.Name = remap(tt.info.Name, m)
1040 tt.info.Version = remap(tt.info.Version, m)
1041 tt.info.Short = remap(tt.info.Short, m)
1042 }
1043 tt.rev = remap(tt.rev, m)
1044 t.Run(path.Base(tt.repo)+"/"+tt.rev, runTest(tt))
1045 tt = old
1046 }
1047 }
1048 }
1049 }
1050
1051 func remap(name string, m map[string]string) string {
1052 if m[name] != "" {
1053 return m[name]
1054 }
1055 if AllHex(name) {
1056 for k, v := range m {
1057 if strings.HasPrefix(k, name) {
1058 return v[:len(name)]
1059 }
1060 }
1061 }
1062 return name
1063 }
1064
View as plain text