Skip to content

Commit

Permalink
Merge pull request fluxcd#34 from fluxcd/gitrepository-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
hiddeco authored May 29, 2020
2 parents 96a76c2 + 24b77d3 commit 7352bce
Show file tree
Hide file tree
Showing 7 changed files with 405 additions and 7 deletions.
258 changes: 258 additions & 0 deletions controllers/gitrepository_controller_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
/*
Copyright 2020 The Flux CD contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package controllers

import (
"context"
"fmt"
"net/url"
"os"
"path"
"strings"
"time"

"github.com/go-git/go-billy/v5/memfs"
"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/go-git/go-git/v5/storage/memory"
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"

sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
"github.com/fluxcd/source-controller/internal/testserver"
)

var _ = Describe("GitRepositoryReconciler", func() {

const (
timeout = time.Second * 30
interval = time.Second * 1
indexInterval = time.Second * 1
)

Context("GitRepository", func() {
var (
namespace *corev1.Namespace
gitServer *testserver.GitServer
err error
)

BeforeEach(func() {
namespace = &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{Name: "git-repository-test" + randStringRunes(5)},
}
err = k8sClient.Create(context.Background(), namespace)
Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")

gitServer, err = testserver.NewTempGitServer()
Expect(err).NotTo(HaveOccurred())
gitServer.AutoCreate()
})

AfterEach(func() {
os.RemoveAll(gitServer.Root())

err = k8sClient.Delete(context.Background(), namespace)
Expect(err).NotTo(HaveOccurred(), "failed to delete test namespace")
})

type refTestCase struct {
reference *sourcev1.GitRepositoryRef
createRefs []string

waitForReason string

expectStatus corev1.ConditionStatus
expectMessage string
expectRevision string
}

DescribeTable("Git references tests", func(t refTestCase) {
err = gitServer.StartHTTP()
defer gitServer.StopHTTP()
Expect(err).NotTo(HaveOccurred())

u, err := url.Parse(gitServer.HTTPAddress())
Expect(err).NotTo(HaveOccurred())
u.Path = path.Join(u.Path, fmt.Sprintf("repository-%s.git", randStringRunes(5)))

fs := memfs.New()
gitrepo, err := git.Init(memory.NewStorage(), fs)
Expect(err).NotTo(HaveOccurred())

wt, err := gitrepo.Worktree()
Expect(err).NotTo(HaveOccurred())

ff, _ := fs.Create("fixture")
_ = ff.Close()
_, err = wt.Add(fs.Join("fixture"))
Expect(err).NotTo(HaveOccurred())

commit, err := wt.Commit("Sample", &git.CommitOptions{Author: &object.Signature{
Name: "John Doe",
Email: "john@example.com",
When: time.Now(),
}})
Expect(err).NotTo(HaveOccurred())

gitrepo.Worktree()

for _, ref := range t.createRefs {
hRef := plumbing.NewHashReference(plumbing.ReferenceName(ref), commit)
err = gitrepo.Storer.SetReference(hRef)
Expect(err).NotTo(HaveOccurred())
}

remote, err := gitrepo.CreateRemote(&config.RemoteConfig{
Name: "origin",
URLs: []string{u.String()},
})
Expect(err).NotTo(HaveOccurred())

err = remote.Push(&git.PushOptions{
RefSpecs: []config.RefSpec{"refs/heads/*:refs/heads/*", "refs/tags/*:refs/tags/*"},
})
Expect(err).NotTo(HaveOccurred())

t.reference.Commit = strings.Replace(t.reference.Commit, "<commit>", commit.String(), 1)

key := types.NamespacedName{
Name: fmt.Sprintf("git-ref-test-%s", randStringRunes(5)),
Namespace: namespace.Name,
}
created := &sourcev1.GitRepository{
ObjectMeta: metav1.ObjectMeta{
Name: key.Name,
Namespace: key.Namespace,
},
Spec: sourcev1.GitRepositorySpec{
URL: u.String(),
Interval: metav1.Duration{Duration: indexInterval},
Reference: t.reference,
},
}
Expect(k8sClient.Create(context.Background(), created)).Should(Succeed())
defer k8sClient.Delete(context.Background(), created)

got := &sourcev1.GitRepository{}
var cond sourcev1.SourceCondition
Eventually(func() bool {
_ = k8sClient.Get(context.Background(), key, got)
for _, c := range got.Status.Conditions {
if c.Reason == t.waitForReason {
cond = c
return true
}
}
return false
}, timeout, interval).Should(BeTrue())

Expect(cond.Status).To(Equal(t.expectStatus))
Expect(cond.Message).To(ContainSubstring(t.expectMessage))
Expect(got.Status.Artifact == nil).To(Equal(t.expectRevision == ""))
if t.expectRevision != "" {
Expect(got.Status.Artifact.Revision).To(Equal(t.expectRevision + "/" + commit.String()))
}
},
Entry("branch", refTestCase{
reference: &sourcev1.GitRepositoryRef{Branch: "some-branch"},
createRefs: []string{"refs/heads/some-branch"},
waitForReason: sourcev1.GitOperationSucceedReason,
expectStatus: corev1.ConditionTrue,
expectRevision: "some-branch",
}),
Entry("branch non existing", refTestCase{
reference: &sourcev1.GitRepositoryRef{Branch: "invalid-branch"},
waitForReason: sourcev1.GitOperationFailedReason,
expectStatus: corev1.ConditionFalse,
expectMessage: "couldn't find remote ref",
}),
Entry("tag", refTestCase{
reference: &sourcev1.GitRepositoryRef{Tag: "some-tag"},
createRefs: []string{"refs/tags/some-tag"},
waitForReason: sourcev1.GitOperationSucceedReason,
expectStatus: corev1.ConditionTrue,
expectRevision: "some-tag",
}),
Entry("tag non existing", refTestCase{
reference: &sourcev1.GitRepositoryRef{Tag: "invalid-tag"},
waitForReason: sourcev1.GitOperationFailedReason,
expectStatus: corev1.ConditionFalse,
expectMessage: "couldn't find remote ref",
}),
Entry("semver", refTestCase{
reference: &sourcev1.GitRepositoryRef{SemVer: "1.0.0"},
createRefs: []string{"refs/tags/v1.0.0"},
waitForReason: sourcev1.GitOperationSucceedReason,
expectStatus: corev1.ConditionTrue,
expectRevision: "v1.0.0",
}),
Entry("semver range", refTestCase{
reference: &sourcev1.GitRepositoryRef{SemVer: ">=0.1.0 <1.0.0"},
createRefs: []string{"refs/tags/0.1.0", "refs/tags/0.1.1", "refs/tags/0.2.0", "refs/tags/1.0.0"},
waitForReason: sourcev1.GitOperationSucceedReason,
expectStatus: corev1.ConditionTrue,
expectRevision: "0.2.0",
}),
Entry("semver invalid", refTestCase{
reference: &sourcev1.GitRepositoryRef{SemVer: "v1.0.0"},
waitForReason: sourcev1.GitOperationFailedReason,
expectStatus: corev1.ConditionFalse,
expectMessage: "semver parse range error",
}),
Entry("semver no match", refTestCase{
reference: &sourcev1.GitRepositoryRef{SemVer: "1.0.0"},
waitForReason: sourcev1.GitOperationFailedReason,
expectStatus: corev1.ConditionFalse,
expectMessage: "no match found for semver: 1.0.0",
}),
Entry("commit", refTestCase{
reference: &sourcev1.GitRepositoryRef{
Commit: "<commit>",
},
waitForReason: sourcev1.GitOperationSucceedReason,
expectStatus: corev1.ConditionTrue,
expectRevision: "master",
}),
Entry("commit in branch", refTestCase{
reference: &sourcev1.GitRepositoryRef{
Branch: "some-branch",
Commit: "<commit>",
},
createRefs: []string{"refs/heads/some-branch"},
waitForReason: sourcev1.GitOperationSucceedReason,
expectStatus: corev1.ConditionTrue,
expectRevision: "some-branch",
}),
Entry("invalid commit", refTestCase{
reference: &sourcev1.GitRepositoryRef{
Branch: "master",
Commit: "invalid",
},
waitForReason: sourcev1.GitOperationFailedReason,
expectStatus: corev1.ConditionFalse,
expectMessage: "git commit 'invalid' not found: object not found",
}),
)
})
})
2 changes: 1 addition & 1 deletion controllers/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func (s *Storage) RemoveAll(artifact sourcev1.Artifact) error {
// RemoveAllButCurrent removes all files for the given artifact base dir excluding the current one
func (s *Storage) RemoveAllButCurrent(artifact sourcev1.Artifact) error {
dir := filepath.Dir(artifact.Path)
errors := []string{}
var errors []string
_ = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if path != artifact.Path && !info.IsDir() && info.Mode()&os.ModeSymlink != os.ModeSymlink {
if err := os.Remove(path); err != nil {
Expand Down
10 changes: 9 additions & 1 deletion controllers/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ var _ = BeforeSuite(func(done Done) {

Expect(loadExampleKeys()).To(Succeed())

tmpStoragePath, err := ioutil.TempDir("", "helmrepository")
tmpStoragePath, err := ioutil.TempDir("", "source-controller-storage-")
Expect(err).NotTo(HaveOccurred(), "failed to create tmp storage dir")

storage, err = NewStorage(tmpStoragePath, "localhost", time.Second*30)
Expand All @@ -105,6 +105,14 @@ var _ = BeforeSuite(func(done Done) {
})
Expect(err).ToNot(HaveOccurred())

err = (&GitRepositoryReconciler{
Client: k8sManager.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("GitRepository"),
Scheme: scheme.Scheme,
Storage: storage,
}).SetupWithManager(k8sManager)
Expect(err).ToNot(HaveOccurred(), "failed to setup GtRepositoryReconciler")

err = (&HelmRepositoryReconciler{
Client: k8sManager.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("HelmRepository"),
Expand Down
6 changes: 6 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ go 1.13

require (
github.com/blang/semver v3.5.0+incompatible
github.com/go-git/go-billy/v5 v5.0.0
github.com/go-git/go-git/v5 v5.0.0
github.com/go-logr/logr v0.1.0
github.com/onsi/ginkgo v1.11.0
github.com/onsi/gomega v1.8.1
github.com/sosedoff/gitkit v0.2.1-0.20191202022816-7182d43c6254
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073
helm.sh/helm/v3 v3.1.2
k8s.io/api v0.17.2
Expand All @@ -17,3 +19,7 @@ require (
sigs.k8s.io/controller-runtime v0.5.0
sigs.k8s.io/yaml v1.1.0
)

// TODO(hidde): drop when PR is accepted:
// https://github.com/sosedoff/gitkit/pull/21
replace github.com/sosedoff/gitkit => github.com/hiddeco/gitkit v0.2.1-0.20200422093229-4355fec70348
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hiddeco/gitkit v0.2.1-0.20200422093229-4355fec70348 h1:m5YZOS7599S/K4swKGL4cDHbo2zqNhZKU2Z1leL7vuY=
github.com/hiddeco/gitkit v0.2.1-0.20200422093229-4355fec70348/go.mod h1:CrGdGLdRnoHSdSLqDVwmNbgUD5BmyapU+w3Z9r+s8xY=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0=
Expand Down Expand Up @@ -451,6 +453,7 @@ github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uY
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
Expand Down
14 changes: 9 additions & 5 deletions internal/git/checkout.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ func CheckoutStrategyForRef(ref *sourcev1.GitRepositoryRef) CheckoutStrategy {
case ref.Tag != "":
return &CheckoutTag{tag: ref.Tag}
case ref.Commit != "":
return &CheckoutCommit{branch: ref.Branch, commit: ref.Commit}
strategy := &CheckoutCommit{branch: ref.Branch, commit: ref.Commit}
if strategy.branch == "" {
strategy.branch = defaultBranch
}
return strategy
case ref.Branch != "":
return &CheckoutBranch{branch: ref.Branch}
default:
Expand Down Expand Up @@ -81,7 +85,7 @@ func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, auth tr
}
commit, err := repo.CommitObject(head.Hash())
if err != nil {
return nil, "", fmt.Errorf("git commit not found: %w", err)
return nil, "", fmt.Errorf("git commit '%s' not found: %w", head.Hash(), err)
}
return commit, fmt.Sprintf("%s/%s", c.branch, head.Hash().String()), nil
}
Expand Down Expand Up @@ -112,7 +116,7 @@ func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, auth trans
}
commit, err := repo.CommitObject(head.Hash())
if err != nil {
return nil, "", fmt.Errorf("git commit not found: %w", err)
return nil, "", fmt.Errorf("git commit '%s' not found: %w", head.Hash(), err)
}
return commit, fmt.Sprintf("%s/%s", c.tag, head.Hash().String()), nil
}
Expand Down Expand Up @@ -143,7 +147,7 @@ func (c *CheckoutCommit) Checkout(ctx context.Context, path, url string, auth tr
}
commit, err := repo.CommitObject(plumbing.NewHash(c.commit))
if err != nil {
return nil, "", fmt.Errorf("git commit not found: %w", err)
return nil, "", fmt.Errorf("git commit '%s' not found: %w", c.commit, err)
}
err = w.Checkout(&git.CheckoutOptions{
Hash: commit.Hash,
Expand Down Expand Up @@ -217,7 +221,7 @@ func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, auth tr

commit, err := repo.CommitObject(plumbing.NewHash(commitRef))
if err != nil {
return nil, "", fmt.Errorf("git commit not found: %w", err)
return nil, "", fmt.Errorf("git commit '%s' not found: %w", commitRef, err)
}
err = w.Checkout(&git.CheckoutOptions{
Hash: commit.Hash,
Expand Down
Loading

0 comments on commit 7352bce

Please sign in to comment.