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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fluxcd/pkg/gittestserver"
|
"github.com/fluxcd/pkg/gittestserver"
|
||||||
"github.com/fluxcd/pkg/ssh"
|
"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/onsi/gomega"
|
||||||
|
|
||||||
"github.com/fluxcd/source-controller/pkg/git"
|
"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)
|
sshURL := strings.Replace(sshAddress, "127.0.0.1", "localhost", 1)
|
||||||
return sshURL + "/" + repoPath
|
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