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