Add git.CheckoutStrategy SemVer checkout tests
Adds tests for git.CheckoutStrategy to check if both the git implementations follow the same SemVer tag selection rules. Signed-off-by: Sunny <darkowlzz@protonmail.com>
This commit is contained in:
parent
99428f593e
commit
562af6d658
|
|
@ -18,14 +18,20 @@ package strategy
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fluxcd/pkg/gittestserver"
|
||||
"github.com/fluxcd/pkg/ssh"
|
||||
extgogit "github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/config"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/fluxcd/source-controller/pkg/git"
|
||||
|
|
@ -198,3 +204,203 @@ func getSSHRepoURL(sshAddress, repoPath string) string {
|
|||
sshURL := strings.Replace(sshAddress, "127.0.0.1", "localhost", 1)
|
||||
return sshURL + "/" + repoPath
|
||||
}
|
||||
|
||||
func TestCheckoutStrategyForImplementation_SemVerCheckout(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
gitImpls := []git.Implementation{gogit.Implementation, libgit2.Implementation}
|
||||
|
||||
// Setup git server and repo.
|
||||
gitServer, err := gittestserver.NewTempGitServer()
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
defer os.RemoveAll(gitServer.Root())
|
||||
username := "test-user"
|
||||
password := "test-password"
|
||||
gitServer.Auth(username, password)
|
||||
gitServer.KeyDir(gitServer.Root())
|
||||
g.Expect(gitServer.StartHTTP()).ToNot(HaveOccurred())
|
||||
defer gitServer.StopHTTP()
|
||||
|
||||
repoPath := "bar/test-reponame"
|
||||
err = gitServer.InitRepo("testdata/repo1", "master", repoPath)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
repoURL := gitServer.HTTPAddressWithCredentials() + "/" + repoPath
|
||||
|
||||
authOpts := &git.AuthOptions{
|
||||
Transport: git.HTTP,
|
||||
Username: username,
|
||||
Password: password,
|
||||
}
|
||||
|
||||
// Create test tags in the repo.
|
||||
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,
|
||||
},
|
||||
}
|
||||
|
||||
// Clone the repo locally.
|
||||
cloneDir, err := os.MkdirTemp("", "test-clone")
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
defer os.RemoveAll(cloneDir)
|
||||
repo, err := extgogit.PlainClone(cloneDir, false, &extgogit.CloneOptions{
|
||||
URL: repoURL,
|
||||
})
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
// Create commits and tags.
|
||||
// Keep a record of all the tags and commit refs.
|
||||
refs := make(map[string]string, len(tags))
|
||||
for _, tt := range tags {
|
||||
ref, err := commitFile(repo, "tag", tt.tag, tt.commitTime)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
_, err = tag(repo, ref, tt.annotated, tt.tag, tt.tagTime)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
refs[tt.tag] = ref.String()
|
||||
}
|
||||
|
||||
// Push everything.
|
||||
err = repo.Push(&extgogit.PushOptions{
|
||||
RefSpecs: []config.RefSpec{"refs/*:refs/*"},
|
||||
})
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
// Test cases.
|
||||
type testCase struct {
|
||||
name string
|
||||
constraint string
|
||||
expectErr error
|
||||
expectTag string
|
||||
}
|
||||
tests := []testCase{
|
||||
{
|
||||
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"),
|
||||
},
|
||||
}
|
||||
testFunc := func(tt testCase, impl git.Implementation) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
// Get the checkout strategy.
|
||||
checkoutOpts := git.CheckoutOptions{
|
||||
SemVer: tt.constraint,
|
||||
}
|
||||
checkoutStrategy, err := CheckoutStrategyForImplementation(context.TODO(), impl, checkoutOpts)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
// Checkout and verify.
|
||||
tmpDir, err := os.MkdirTemp("", "test-checkout")
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
cc, err := checkoutStrategy.Checkout(context.TODO(), tmpDir, repoURL, authOpts)
|
||||
if tt.expectErr != nil {
|
||||
g.Expect(err).To(Equal(tt.expectErr))
|
||||
g.Expect(cc).To(BeNil())
|
||||
return
|
||||
}
|
||||
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
g.Expect(cc.String()).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))
|
||||
}
|
||||
}
|
||||
|
||||
// Run the test cases against the git implementations.
|
||||
for _, gitImpl := range gitImpls {
|
||||
for _, tt := range tests {
|
||||
t.Run(string(gitImpl)+"_"+tt.name, testFunc(tt, gitImpl))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
if ferr := f.Close(); ferr != nil {
|
||||
return plumbing.Hash{}, ferr
|
||||
}
|
||||
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: mockSignature(time),
|
||||
Committer: mockSignature(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: mockSignature(time),
|
||||
Message: "Annotated tag for: " + tag,
|
||||
}
|
||||
}
|
||||
return repo.CreateTag(tag, commit, opts)
|
||||
}
|
||||
|
||||
func mockSignature(time time.Time) *object.Signature {
|
||||
return &object.Signature{
|
||||
Name: "Jane Doe",
|
||||
Email: "jane@example.com",
|
||||
When: time,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue