gogit: add CheckoutStrategy tests

Signed-off-by: Hidde Beydals <hello@hidde.co>
This commit is contained in:
Hidde Beydals 2021-10-23 14:30:58 +02:00 committed by Sunny
parent 0cf0d4e756
commit 80b9807550
5 changed files with 391 additions and 27 deletions

View File

@ -74,7 +74,7 @@ func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *g
RecurseSubmodules: recurseSubmodules(c.recurseSubmodules),
Progress: nil,
Tags: extgogit.NoTags,
CABundle: opts.CAFile,
CABundle: caBundle(opts),
})
if err != nil {
return nil, "", fmt.Errorf("unable to clone '%s', error: %w", url, gitutil.GoGitError(err))
@ -111,7 +111,7 @@ func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, opts *git.
RecurseSubmodules: recurseSubmodules(c.recurseSubmodules),
Progress: nil,
Tags: extgogit.NoTags,
CABundle: opts.CAFile,
CABundle: caBundle(opts),
})
if err != nil {
return nil, "", fmt.Errorf("unable to clone '%s', error: %w", url, err)
@ -148,7 +148,7 @@ func (c *CheckoutCommit) Checkout(ctx context.Context, path, url string, opts *g
RecurseSubmodules: recurseSubmodules(c.recurseSubmodules),
Progress: nil,
Tags: extgogit.NoTags,
CABundle: opts.CAFile,
CABundle: caBundle(opts),
})
if err != nil {
return nil, "", fmt.Errorf("unable to clone '%s', error: %w", url, err)
@ -194,7 +194,7 @@ func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, opts *g
RecurseSubmodules: recurseSubmodules(c.recurseSubmodules),
Progress: nil,
Tags: extgogit.AllTags,
CABundle: opts.CAFile,
CABundle: caBundle(opts),
})
if err != nil {
return nil, "", fmt.Errorf("unable to clone '%s', error: %w", url, err)

View File

@ -18,37 +18,379 @@ package gogit
import (
"context"
"errors"
"os"
"path/filepath"
"testing"
"time"
"github.com/fluxcd/source-controller/pkg/git"
"github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-billy/v5/osfs"
extgogit "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/cache"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/go-git/go-git/v5/storage/filesystem"
. "github.com/onsi/gomega"
)
func TestCheckoutTagSemVer_Checkout(t *testing.T) {
auth := &git.AuthOptions{}
tag := CheckoutTag{
tag: "v1.7.0",
}
tmpDir, _ := os.MkdirTemp("", "test")
defer os.RemoveAll(tmpDir)
cTag, _, err := tag.Checkout(context.TODO(), tmpDir, "https://github.com/projectcontour/contour", auth)
func TestCheckoutBranch_Checkout(t *testing.T) {
repo, path, err := initRepo()
if err != nil {
t.Error(err)
t.Fatal(err)
}
defer os.RemoveAll(path)
semVer := CheckoutSemVer{
semVer: ">=1.0.0 <=1.7.0",
}
tmpDir2, _ := os.MkdirTemp("", "test")
defer os.RemoveAll(tmpDir2)
cSemVer, _, err := semVer.Checkout(context.TODO(), tmpDir2, "https://github.com/projectcontour/contour", auth)
firstCommit, err := commitFile(repo, "branch", "init", time.Now())
if err != nil {
t.Error(err)
t.Fatal(err)
}
if cTag.Hash() != cSemVer.Hash() {
t.Errorf("expected semver hash %s, got %s", cTag.Hash(), cSemVer.Hash())
if err = createBranch(repo, "test"); err != nil {
t.Fatal(err)
}
secondCommit, err := commitFile(repo, "branch", "second", time.Now())
if err != nil {
t.Fatal(err)
}
tests := []struct {
name string
branch string
expectedCommit string
expectedErr string
}{
{
name: "Default branch",
branch: "master",
expectedCommit: firstCommit.String(),
},
{
name: "Other branch",
branch: "test",
expectedCommit: secondCommit.String(),
},
{
name: "Non existing branch",
branch: "invalid",
expectedErr: "couldn't find remote ref \"refs/heads/invalid\"",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
branch := CheckoutBranch{
branch: tt.branch,
}
tmpDir, _ := os.MkdirTemp("", "test")
defer os.RemoveAll(tmpDir)
_, ref, err := branch.Checkout(context.TODO(), tmpDir, path, nil)
if tt.expectedErr != "" {
g.Expect(err.Error()).To(ContainSubstring(tt.expectedErr))
g.Expect(ref).To(BeEmpty())
return
}
g.Expect(err).To(BeNil())
g.Expect(ref).To(Equal(tt.branch + "/" + tt.expectedCommit))
})
}
}
func TestCheckoutTag_Checkout(t *testing.T) {
tests := []struct {
name string
tag string
annotated bool
checkoutTag string
expectTag string
expectErr string
}{
{
name: "Tag",
tag: "tag-1",
checkoutTag: "tag-1",
expectTag: "tag-1",
},
{
name: "Annotated",
tag: "annotated",
annotated: true,
checkoutTag: "annotated",
expectTag: "annotated",
},
{
name: "Non existing tag",
tag: "tag-1",
checkoutTag: "invalid",
expectErr: "error: couldn't find remote ref \"refs/tags/invalid\"",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
repo, path, err := initRepo()
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(path)
var h plumbing.Hash
if tt.tag != "" {
h, err = commitFile(repo, "tag", tt.tag, time.Now())
if err != nil {
t.Fatal(err)
}
_, err = tag(repo, h, !tt.annotated, tt.tag, time.Now())
if err != nil {
t.Fatal(err)
}
}
tag := CheckoutTag{
tag: tt.checkoutTag,
}
tmpDir, _ := os.MkdirTemp("", "test")
defer os.RemoveAll(tmpDir)
_, ref, err := tag.Checkout(context.TODO(), tmpDir, path, nil)
if tt.expectErr != "" {
g.Expect(err.Error()).To(ContainSubstring(tt.expectErr))
g.Expect(ref).To(BeEmpty())
return
}
if tt.expectTag != "" {
g.Expect(ref).To(Equal(tt.expectTag + "/" + h.String()))
g.Expect(filepath.Join(tmpDir, "tag")).To(BeARegularFile())
g.Expect(os.ReadFile(filepath.Join(tmpDir, "tag"))).To(BeEquivalentTo(tt.tag))
}
})
}
}
func TestCheckoutCommit_Checkout(t *testing.T) {
g := NewWithT(t)
repo, path, err := initRepo()
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(path)
c, err := commitFile(repo, "commit", "init", time.Now())
if err != nil {
t.Fatal(err)
}
if _, err = commitFile(repo, "commit", "second", time.Now()); err != nil {
t.Fatal(err)
}
commit := CheckoutCommit{
commit: c.String(),
branch: "master",
}
tmpDir, _ := os.MkdirTemp("", "git2go")
defer os.RemoveAll(tmpDir)
_, ref, err := commit.Checkout(context.TODO(), tmpDir, path, nil)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(ref).To(Equal("master/" + c.String()))
g.Expect(filepath.Join(tmpDir, "commit")).To(BeARegularFile())
g.Expect(os.ReadFile(filepath.Join(tmpDir, "commit"))).To(BeEquivalentTo("init"))
commit = CheckoutCommit{
commit: "4dc3185c5fc94eb75048376edeb44571cece25f4",
branch: "master",
}
tmpDir2, _ := os.MkdirTemp("", "git2go")
defer os.RemoveAll(tmpDir)
_, ref, err = commit.Checkout(context.TODO(), tmpDir2, path, nil)
g.Expect(err).To(HaveOccurred())
g.Expect(err.Error()).To(HavePrefix("git commit '4dc3185c5fc94eb75048376edeb44571cece25f4' not found:"))
g.Expect(ref).To(BeEmpty())
}
func TestCheckoutTagSemVer_Checkout(t *testing.T) {
now := time.Now()
tags := []struct {
tag string
annotated bool
commitTime time.Time
tagTime time.Time
}{
{
tag: "v0.0.1",
annotated: false,
commitTime: now,
},
{
tag: "v0.1.0+build-1",
annotated: true,
commitTime: now.Add(10 * time.Minute),
tagTime: now.Add(2 * time.Hour), // This should be ignored during TS comparisons
},
{
tag: "v0.1.0+build-2",
annotated: false,
commitTime: now.Add(30 * time.Minute),
},
{
tag: "v0.1.0+build-3",
annotated: true,
commitTime: now.Add(1 * time.Hour),
tagTime: now.Add(1 * time.Hour), // This should be ignored during TS comparisons
},
{
tag: "0.2.0",
annotated: true,
commitTime: now,
tagTime: now,
},
}
tests := []struct {
name string
constraint string
expectErr error
expectTag string
}{
{
name: "Orders by SemVer",
constraint: ">0.1.0",
expectTag: "0.2.0",
},
{
name: "Orders by SemVer and timestamp",
constraint: "<0.2.0",
expectTag: "v0.1.0+build-3",
},
{
name: "Errors without match",
constraint: ">=1.0.0",
expectErr: errors.New("no match found for semver: >=1.0.0"),
},
}
repo, path, err := initRepo()
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(path)
refs := make(map[string]string, len(tags))
for _, tt := range tags {
ref, err := commitFile(repo, "tag", tt.tag, tt.commitTime)
if err != nil {
t.Fatal(err)
}
_, err = tag(repo, ref, tt.annotated, tt.tag, tt.tagTime)
if err != nil {
t.Fatal(err)
}
refs[tt.tag] = ref.String()
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
semVer := CheckoutSemVer{
semVer: tt.constraint,
}
tmpDir, _ := os.MkdirTemp("", "test")
defer os.RemoveAll(tmpDir)
_, ref, err := semVer.Checkout(context.TODO(), tmpDir, path, nil)
if tt.expectErr != nil {
g.Expect(err).To(Equal(tt.expectErr))
g.Expect(ref).To(BeEmpty())
return
}
g.Expect(err).ToNot(HaveOccurred())
g.Expect(ref).To(Equal(tt.expectTag + "/" + refs[tt.expectTag]))
g.Expect(filepath.Join(tmpDir, "tag")).To(BeARegularFile())
g.Expect(os.ReadFile(filepath.Join(tmpDir, "tag"))).To(BeEquivalentTo(tt.expectTag))
})
}
}
func initRepo() (*extgogit.Repository, string, error) {
tmpDir, err := os.MkdirTemp("", "gogit")
if err != nil {
os.RemoveAll(tmpDir)
return nil, "", err
}
sto := filesystem.NewStorage(osfs.New(tmpDir), cache.NewObjectLRUDefault())
repo, err := extgogit.Init(sto, memfs.New())
if err != nil {
os.RemoveAll(tmpDir)
return nil, "", err
}
return repo, tmpDir, err
}
func createBranch(repo *extgogit.Repository, branch string) error {
wt, err := repo.Worktree()
if err != nil {
return err
}
h, err := repo.Head()
if err != nil {
return err
}
return wt.Checkout(&extgogit.CheckoutOptions{
Hash: h.Hash(),
Branch: plumbing.ReferenceName("refs/heads/" + branch),
Create: true,
})
}
func commitFile(repo *extgogit.Repository, path, content string, time time.Time) (plumbing.Hash, error) {
wt, err := repo.Worktree()
if err != nil {
return plumbing.Hash{}, err
}
f, err := wt.Filesystem.Create(path)
if err != nil {
return plumbing.Hash{}, err
}
if _, err = f.Write([]byte(content)); err != nil {
f.Close()
return plumbing.Hash{}, err
}
if err = f.Close(); err != nil {
return plumbing.Hash{}, err
}
if _, err = wt.Add(path); err != nil {
return plumbing.Hash{}, err
}
return wt.Commit("Adding: "+path, &extgogit.CommitOptions{
Author: signature(time),
Committer: signature(time),
})
}
func tag(repo *extgogit.Repository, commit plumbing.Hash, annotated bool, tag string, time time.Time) (*plumbing.Reference, error) {
var opts *extgogit.CreateTagOptions
if annotated {
opts = &extgogit.CreateTagOptions{
Tagger: signature(time),
Message: "Annotated tag for: " + tag,
}
}
return repo.CreateTag(tag, commit, opts)
}
func signature(time time.Time) *object.Signature {
return &object.Signature{
Name: "Jane Doe",
Email: "jane@example.com",
When: time,
}
}

View File

@ -29,6 +29,9 @@ import (
// transportAuth constructs the transport.AuthMethod for the git.Transport of
// the given git.AuthOptions. It returns the result, or an error.
func transportAuth(opts *git.AuthOptions) (transport.AuthMethod, error) {
if opts == nil {
return nil, nil
}
switch opts.Transport {
case git.HTTPS, git.HTTP:
return &http.BasicAuth{
@ -53,3 +56,11 @@ func transportAuth(opts *git.AuthOptions) (transport.AuthMethod, error) {
}
return nil, nil
}
// caBundle returns the CA bundle from the given git.AuthOptions.
func caBundle(opts *git.AuthOptions) []byte {
if opts == nil {
return nil
}
return opts.CAFile
}

View File

@ -193,3 +193,10 @@ func Test_transportAuth(t *testing.T) {
})
}
}
func Test_caBundle(t *testing.T) {
g := NewWithT(t)
g.Expect(caBundle(&git.AuthOptions{CAFile: []byte("foo")})).To(BeEquivalentTo("foo"))
g.Expect(caBundle(nil)).To(BeNil())
}

View File

@ -84,6 +84,7 @@ func TestCheckoutBranch_Checkout(t *testing.T) {
_, ref, err := branch.Checkout(context.TODO(), tmpDir, repo.Path(), nil)
if tt.expectedErr != "" {
g.Expect(err).To(HaveOccurred())
g.Expect(err.Error()).To(ContainSubstring(tt.expectedErr))
g.Expect(ref).To(BeEmpty())
return
@ -154,7 +155,8 @@ func TestCheckoutTag_Checkout(t *testing.T) {
_, ref, err := tag.Checkout(context.TODO(), tmpDir, repo.Path(), nil)
if tt.expectErr != "" {
g.Expect(err.Error()).To(Equal(tt.expectErr))
g.Expect(err).To(HaveOccurred())
g.Expect(err.Error()).To(ContainSubstring(tt.expectErr))
g.Expect(ref).To(BeEmpty())
return
}
@ -193,7 +195,7 @@ func TestCheckoutCommit_Checkout(t *testing.T) {
defer os.RemoveAll(tmpDir)
_, ref, err := commit.Checkout(context.TODO(), tmpDir, repo.Path(), nil)
g.Expect(err).To(BeNil())
g.Expect(err).ToNot(HaveOccurred())
g.Expect(ref).To(Equal("main/" + c.String()))
g.Expect(filepath.Join(tmpDir, "commit")).To(BeARegularFile())
g.Expect(os.ReadFile(filepath.Join(tmpDir, "commit"))).To(BeEquivalentTo("init"))
@ -205,6 +207,7 @@ func TestCheckoutCommit_Checkout(t *testing.T) {
defer os.RemoveAll(tmpDir)
_, ref, err = commit.Checkout(context.TODO(), tmpDir2, repo.Path(), nil)
g.Expect(err).To(HaveOccurred())
g.Expect(err.Error()).To(HavePrefix("git checkout error: git commit '4dc3185c5fc94eb75048376edeb44571cece25f4' not found:"))
g.Expect(ref).To(BeEmpty())
}
@ -316,6 +319,7 @@ func TestCheckoutTagSemVer_Checkout(t *testing.T) {
g.Expect(ref).To(BeEmpty())
return
}
g.Expect(err).ToNot(HaveOccurred())
g.Expect(ref).To(Equal(tt.expectTag + "/" + refs[tt.expectTag]))
g.Expect(filepath.Join(tmpDir, "tag")).To(BeARegularFile())