Merge pull request #108 from fluxcd/pkg-testserver

This commit is contained in:
Hidde Beydals 2020-08-18 12:27:46 +02:00 committed by GitHub
commit 7ea5739691
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 24 additions and 405 deletions

View File

@ -38,8 +38,9 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"github.com/fluxcd/pkg/gittestserver"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
"github.com/fluxcd/source-controller/pkg/testserver"
)
var _ = Describe("GitRepositoryReconciler", func() {
@ -53,7 +54,7 @@ var _ = Describe("GitRepositoryReconciler", func() {
Context("GitRepository", func() {
var (
namespace *corev1.Namespace
gitServer *testserver.GitServer
gitServer *gittestserver.GitServer
err error
)
@ -64,7 +65,7 @@ var _ = Describe("GitRepositoryReconciler", func() {
err = k8sClient.Create(context.Background(), namespace)
Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
gitServer, err = testserver.NewTempGitServer()
gitServer, err = gittestserver.NewTempGitServer()
Expect(err).NotTo(HaveOccurred())
gitServer.AutoCreate()
})

View File

@ -30,8 +30,9 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"github.com/fluxcd/pkg/helmtestserver"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
"github.com/fluxcd/source-controller/pkg/testserver"
)
var _ = Describe("HelmChartReconciler", func() {
@ -46,7 +47,7 @@ var _ = Describe("HelmChartReconciler", func() {
Context("HelmChart", func() {
var (
namespace *corev1.Namespace
helmServer *testserver.HelmServer
helmServer *helmtestserver.HelmServer
err error
)
@ -57,7 +58,7 @@ var _ = Describe("HelmChartReconciler", func() {
err = k8sClient.Create(context.Background(), namespace)
Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
helmServer, err = testserver.NewTempHelmServer()
helmServer, err = helmtestserver.NewTempHelmServer()
Expect(err).To(Succeed())
helmServer.Start()
})

View File

@ -30,8 +30,9 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"github.com/fluxcd/pkg/helmtestserver"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
"github.com/fluxcd/source-controller/pkg/testserver"
)
var _ = Describe("HelmRepositoryReconciler", func() {
@ -46,7 +47,7 @@ var _ = Describe("HelmRepositoryReconciler", func() {
Context("HelmRepository", func() {
var (
namespace *corev1.Namespace
helmServer *testserver.HelmServer
helmServer *helmtestserver.HelmServer
err error
)
@ -57,7 +58,7 @@ var _ = Describe("HelmRepositoryReconciler", func() {
err = k8sClient.Create(context.Background(), namespace)
Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
helmServer, err = testserver.NewTempHelmServer()
helmServer, err = helmtestserver.NewTempHelmServer()
Expect(err).To(Succeed())
})
@ -204,7 +205,7 @@ var _ = Describe("HelmRepositoryReconciler", func() {
})
It("Authenticates when basic auth credentials are provided", func() {
helmServer, err = testserver.NewTempHelmServer()
helmServer, err = helmtestserver.NewTempHelmServer()
Expect(err).NotTo(HaveOccurred())
var username, password = "john", "doe"
@ -310,7 +311,7 @@ var _ = Describe("HelmRepositoryReconciler", func() {
})
It("Authenticates when TLS credentials are provided", func() {
err = helmServer.StartTLS(examplePublicKey, examplePrivateKey, exampleCA)
err = helmServer.StartTLS(examplePublicKey, examplePrivateKey, exampleCA, "example.com")
Expect(err).NotTo(HaveOccurred())
Expect(helmServer.PackageChart(path.Join("testdata/helmchart"))).Should(Succeed())

4
go.mod
View File

@ -6,6 +6,8 @@ replace github.com/fluxcd/source-controller/api => ./api
require (
github.com/blang/semver v3.5.0+incompatible
github.com/fluxcd/pkg/gittestserver v0.0.1
github.com/fluxcd/pkg/helmtestserver v0.0.1
github.com/fluxcd/pkg/lockedfile v0.0.5
github.com/fluxcd/pkg/recorder v0.0.5
github.com/fluxcd/pkg/ssh v0.0.5
@ -15,13 +17,11 @@ require (
github.com/go-logr/logr v0.1.0
github.com/onsi/ginkgo v1.12.1
github.com/onsi/gomega v1.10.1
github.com/sosedoff/gitkit v0.2.1-0.20191202022816-7182d43c6254
go.uber.org/zap v1.13.0
helm.sh/helm/v3 v3.3.0
k8s.io/api v0.18.4
k8s.io/apimachinery v0.18.4
k8s.io/client-go v0.18.4
rsc.io/letsencrypt v0.0.3 // indirect
sigs.k8s.io/controller-runtime v0.6.1
sigs.k8s.io/yaml v1.2.0
)

9
go.sum
View File

@ -199,12 +199,18 @@ github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZM
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fluxcd/pkg/gittestserver v0.0.1 h1:2jGRV1pFlycrOiLmXc99s5iCFRgHIfygYR7QVe4KXYY=
github.com/fluxcd/pkg/gittestserver v0.0.1/go.mod h1:cGNJIdH3y9cE8YkPXx9PQfzZFBndibc4ZqrHc5Tq4xo=
github.com/fluxcd/pkg/helmtestserver v0.0.1 h1:8RcLZdg7Zr9ZqyijsIIASjjMXQtF4UWP4Uds4iK2VJM=
github.com/fluxcd/pkg/helmtestserver v0.0.1/go.mod h1:GR8LriiU7PqZSTH4Xe6Cimpig2VVPB29PeUXJjNJYfA=
github.com/fluxcd/pkg/lockedfile v0.0.5 h1:C3T8wfdff1UY1bvplmCkGOLrdMWJHO8Q8+tdlEXJYzQ=
github.com/fluxcd/pkg/lockedfile v0.0.5/go.mod h1:uAtPUBId6a2RqO84MTH5HKGX0SbM1kNW3Wr/FhYyDVA=
github.com/fluxcd/pkg/recorder v0.0.5 h1:D8qfupahIvh6ncCMn2yTHsrzG91S05sp4zdpsbKWeaU=
github.com/fluxcd/pkg/recorder v0.0.5/go.mod h1:2UG6EroZ6ZbqmqoL8k/cQMe09e6A36WyH4t4UDUGyuU=
github.com/fluxcd/pkg/ssh v0.0.5 h1:rnbFZ7voy2JBlUfMbfyqArX2FYaLNpDhccGFC3qW83A=
github.com/fluxcd/pkg/ssh v0.0.5/go.mod h1:7jXPdXZpc0ttMNz2kD9QuMi3RNn/e0DOFbj0Tij/+Hs=
github.com/fluxcd/pkg/testserver v0.0.2 h1:SoaMtO9cE5p/wl2zkGudzflnEHd9mk68CGjZOo7w0Uk=
github.com/fluxcd/pkg/testserver v0.0.2/go.mod h1:pgUZTh9aQ44FSTQo+5NFlh7YMbUfdz1B80DalW7k96Y=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
@ -767,8 +773,9 @@ golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=

View File

@ -1,95 +0,0 @@
/*
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 testserver
import (
"archive/tar"
"compress/gzip"
"crypto/sha1"
"errors"
"fmt"
"os"
"path/filepath"
)
func NewTempArtifactServer() (*ArtifactServer, error) {
server, err := NewTempHTTPServer()
if err != nil {
return nil, err
}
artifact := &ArtifactServer{server}
return artifact, nil
}
type ArtifactServer struct {
*HTTPServer
}
type File struct {
Name string
Body string
}
// ArtifactFromFiles creates a tar.gz artifact from the given files and
// returns the file name of the artifact.
func (s *ArtifactServer) ArtifactFromFiles(files []File) (string, error) {
fileName := calculateArtifactName(files)
filePath := filepath.Join(s.docroot, fileName)
gzFile, err := os.Create(filePath)
if err != nil {
return "", err
}
defer gzFile.Close()
gw := gzip.NewWriter(gzFile)
defer gw.Close()
tw := tar.NewWriter(gw)
defer tw.Close()
for _, f := range files {
hdr := &tar.Header{
Name: f.Name,
Mode: 0600,
Size: int64(len(f.Body)),
}
if err := tw.WriteHeader(hdr); err != nil {
return "", err
}
if _, err := tw.Write([]byte(f.Body)); err != nil {
return "", err
}
}
return fileName, nil
}
// URLForFile returns the URL the given file can be reached at or
// an error if the server has not been started.
func (s *ArtifactServer) URLForFile(file string) (string, error) {
if s.URL() == "" {
return "", errors.New("server must be started to be able to determine the URL of the given file")
}
return fmt.Sprintf("%s/%s", s.URL(), file), nil
}
func calculateArtifactName(files []File) string {
h := sha1.New()
for _, f := range files {
h.Write([]byte(f.Body))
}
return fmt.Sprintf("%x.tar.gz", h.Sum(nil))
}

View File

@ -1,119 +0,0 @@
/*
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 testserver
import (
"io/ioutil"
"net/http/httptest"
"path/filepath"
"github.com/sosedoff/gitkit"
)
// NewTempGitServer returns a GitServer with a newly created temp
// dir as repository docroot.
func NewTempGitServer() (*GitServer, error) {
tmpDir, err := ioutil.TempDir("", "git-server-test-")
if err != nil {
return nil, err
}
srv := NewGitServer(tmpDir)
return srv, nil
}
// NewGitServer returns a GitServer with the given repository docroot
// set.
func NewGitServer(docroot string) *GitServer {
root, err := filepath.Abs(docroot)
if err != nil {
panic(err)
}
return &GitServer{
config: gitkit.Config{Dir: root},
}
}
// GitServer is a git server for testing purposes.
// It can serve git repositories over HTTP and SSH.
type GitServer struct {
config gitkit.Config
httpServer *httptest.Server
sshServer *gitkit.SSH
}
// AutoCreate enables the automatic creation of a non-existing Git
// repository on push.
func (s *GitServer) AutoCreate() *GitServer {
s.config.AutoCreate = true
return s
}
// StartHTTP starts a new HTTP git server with the current configuration.
func (s *GitServer) StartHTTP() error {
s.StopHTTP()
service := gitkit.New(s.config)
if err := service.Setup(); err != nil {
return err
}
s.httpServer = httptest.NewServer(service)
return nil
}
// StopHTTP stops the HTTP git server.
func (s *GitServer) StopHTTP() {
if s.httpServer != nil {
s.httpServer.Close()
}
return
}
// StartSSH starts a new SSH git server with the current configuration.
func (s *GitServer) StartSSH() error {
_ = s.StopSSH()
s.sshServer = gitkit.NewSSH(s.config)
// :0 should result in an OS assigned free port
return s.sshServer.ListenAndServe(":0")
}
// StopSSH stops the SSH git server.
func (s *GitServer) StopSSH() error {
if s.sshServer != nil {
return s.sshServer.Stop()
}
return nil
}
// Root returns the repositories root directory.
func (s *GitServer) Root() string {
return s.config.Dir
}
// HTTPAddress returns the address of the HTTP git server.
func (s *GitServer) HTTPAddress() string {
if s.httpServer != nil {
return s.httpServer.URL
}
return ""
}
// SSHAddress returns the address of the SSH git server.
func (s *GitServer) SSHAddress() string {
if s.sshServer != nil {
return s.sshServer.Address()
}
return ""
}

View File

@ -1,64 +0,0 @@
/*
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 testserver
import (
"io/ioutil"
"path/filepath"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/repo"
"sigs.k8s.io/yaml"
)
func NewTempHelmServer() (*HelmServer, error) {
server, err := NewTempHTTPServer()
if err != nil {
return nil, err
}
helm := &HelmServer{server}
return helm, nil
}
type HelmServer struct {
*HTTPServer
}
func (s *HelmServer) GenerateIndex() error {
index, err := repo.IndexDirectory(s.HTTPServer.docroot, s.HTTPServer.URL())
if err != nil {
return err
}
d, err := yaml.Marshal(index)
if err != nil {
return err
}
f := filepath.Join(s.HTTPServer.docroot, "index.yaml")
return ioutil.WriteFile(f, d, 0644)
}
func (s *HelmServer) PackageChart(path string) error {
return s.PackageChartWithVersion(path, "")
}
func (s *HelmServer) PackageChartWithVersion(path, version string) error {
pkg := action.NewPackage()
pkg.Destination = s.HTTPServer.docroot
pkg.Version = version
_, err := pkg.Run(path, nil)
return err
}

View File

@ -1,113 +0,0 @@
/*
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 testserver
import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"net/http"
"net/http/httptest"
"path/filepath"
)
func NewTempHTTPServer() (*HTTPServer, error) {
tmpDir, err := ioutil.TempDir("", "http-test-")
if err != nil {
return nil, err
}
srv := NewHTTPServer(tmpDir)
return srv, nil
}
func NewHTTPServer(docroot string) *HTTPServer {
root, err := filepath.Abs(docroot)
if err != nil {
panic(err)
}
return &HTTPServer{
docroot: root,
}
}
type HTTPServer struct {
docroot string
middleware func(http.Handler) http.Handler
server *httptest.Server
}
func (s *HTTPServer) WithMiddleware(m func(handler http.Handler) http.Handler) *HTTPServer {
s.middleware = m
return s
}
func (s *HTTPServer) Start() {
s.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
handler := http.FileServer(http.Dir(s.docroot))
if s.middleware != nil {
s.middleware(handler).ServeHTTP(w, r)
return
}
handler.ServeHTTP(w, r)
}))
}
func (s *HTTPServer) StartTLS(cert, key, ca []byte) error {
s.server = httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
handler := http.FileServer(http.Dir(s.docroot))
if s.middleware != nil {
s.middleware(handler).ServeHTTP(w, r)
return
}
handler.ServeHTTP(w, r)
}))
config := tls.Config{}
keyPair, err := tls.X509KeyPair(cert, key)
if err != nil {
return err
}
config.Certificates = []tls.Certificate{keyPair}
cp := x509.NewCertPool()
cp.AppendCertsFromPEM(ca)
config.RootCAs = cp
config.ServerName = "example.com"
s.server.TLS = &config
s.server.StartTLS()
return nil
}
func (s *HTTPServer) Stop() {
if s.server != nil {
s.server.Close()
}
}
func (s *HTTPServer) Root() string {
return s.docroot
}
func (s *HTTPServer) URL() string {
if s.server != nil {
return s.server.URL
}
return ""
}