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