Skip to content

Commit 649c35f

Browse files
committed
End-to-end tests
Setup minikube on Travis following this doc: https://blog.travis-ci.com/2017-10-26-running-kubernetes-on-travis-ci-with-minikube This allow automated e2e tests for Katafygio.
1 parent 64195b7 commit 649c35f

File tree

4 files changed

+149
-0
lines changed

4 files changed

+149
-0
lines changed

.travis.yml

+29
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,34 @@ language: go
22
go:
33
- "1.10.x"
44

5+
# only needed for e2e tests
6+
sudo: required
7+
8+
env:
9+
global:
10+
# only needed for e2e tests
11+
- K8S_VERSION=v1.10.0
12+
- MINIKUBE_VERSION=v0.26.1
13+
- MINIKUBE_WANTREPORTERRORPROMPT=false
14+
- MINIKUBE_WANTUPDATENOTIFICATION=false
15+
- CHANGE_MINIKUBE_NONE_USER=true
16+
- MINIKUBE_HOME=$HOME
17+
- KUBECONFIG=$HOME/.kube/config
18+
19+
# setup a minikube in travis-ci. only needed for e2e tests
20+
before_script:
21+
- sudo curl -Lo /usr/local/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/${K8S_VERSION}/bin/linux/amd64/kubectl
22+
- sudo curl -Lo /usr/local/bin/minikube https://github.com/kubernetes/minikube/releases/download/${MINIKUBE_VERSION}/minikube-linux-amd64
23+
- sudo chmod +x /usr/local/bin/kubectl /usr/local/bin/minikube
24+
- mkdir -p $HOME/.kube && touch $HOME/.kube/config
25+
# remove the --bootstrapper flag once this issue is solved: https://github.com/kubernetes/minikube/issues/2704
26+
- sudo -E /usr/local/bin/minikube start --vm-driver=none --bootstrapper=localkube --kubernetes-version=${K8S_VERSION}
27+
# Fix the kubectl context, as it is often stale.
28+
- /usr/local/bin/minikube update-context
29+
# Wait for Kubernetes to be up and ready.
30+
- for i in {1..150}; do kubectl get po &> /dev/null && break; sleep 2; done
31+
- kubectl get ns
32+
533
install:
634
- make tools
735
- make deps
@@ -11,4 +39,5 @@ script:
1139
- make test
1240
- make coverall
1341
- make install
42+
- make e2e
1443

Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ clean:
5050
coverall:
5151
goveralls -coverprofile=profile.cov -service=travis-ci -package github.com/bpineau/katafygio/pkg/...
5252

53+
e2e:
54+
kubectl get ns >/dev/null || exit 1
55+
go test -count=1 -v assets/e2e_test.go
56+
5357
test:
5458
go test -i github.com/bpineau/katafygio/...
5559
go test -race -cover -coverprofile=profile.cov github.com/bpineau/katafygio/...

assets/e2e_test.go

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// +build ignore
2+
3+
// end-to-end tests.
4+
// A kubernetes cluster must be reachable by kubectl and katafygio.
5+
package main
6+
7+
import (
8+
"context"
9+
"fmt"
10+
"os"
11+
"os/exec"
12+
"path"
13+
"strings"
14+
"testing"
15+
"time"
16+
)
17+
18+
var (
19+
checkTimeout = 30 * time.Second
20+
checkInterval = 1 * time.Second
21+
dumpPath = "/tmp/kf-e2e-test"
22+
)
23+
24+
type dumpStep struct {
25+
// a kubectl command to create a dumpable object
26+
cmd string
27+
// the counter-command, to purge the created object
28+
teardown string
29+
// the file that this command will eventually trigger katafygio to generate or delete
30+
relpath string
31+
// wether the file should be created or deleted
32+
shouldExist bool
33+
}
34+
35+
var testsTable = []dumpStep{
36+
{"kubectl create ns kf-e2e-test-1", "kubectl delete ns kf-e2e-test-1", "namespace-kf-e2e-test-1.yaml", true},
37+
{"kubectl run kf-e2e-test-2 --image=gcr.io/google_containers/pause-amd64:3.0", "kubectl delete deploy kf-e2e-test-2", "default/deployment-kf-e2e-test-2.yaml", true},
38+
{"kubectl expose deployment kf-e2e-test-2 --port=80 --target-port=8000 --name=kf-e2e-test-3", "kubectl delete svc kf-e2e-test-3", "default/service-kf-e2e-test-3.yaml", true},
39+
{"kubectl delete service kf-e2e-test-3", "", "default/service-kf-e2e-test-3.yaml", false},
40+
{"kubectl delete namespace kf-e2e-test-1", "", "namespace-kf-e2e-test-1.yaml", false},
41+
{"kubectl create configmap kf-e2e-test-4 --from-literal=key1=config1", "kubectl delete configmap kf-e2e-test-4", "default/configmap-kf-e2e-test-4.yaml", true},
42+
}
43+
44+
func TestE2E(t *testing.T) {
45+
for _, tt := range testsTable {
46+
t.Run(tt.cmd, func(t *testing.T) {
47+
err := tt.fileExists()
48+
if err != nil {
49+
t.Errorf("%s test failed (%v)", tt.cmd, err)
50+
}
51+
})
52+
53+
}
54+
}
55+
56+
func TestMain(m *testing.M) {
57+
deleteResources()
58+
_ = exec.Command("rm", "-rf", dumpPath)
59+
60+
ctx, cancel := context.WithCancel(context.Background())
61+
62+
go func() {
63+
cmd := exec.CommandContext(ctx, "katafygio", "-e", dumpPath)
64+
_ = cmd.Run()
65+
}()
66+
67+
ret := m.Run()
68+
cancel()
69+
deleteResources()
70+
os.Exit(ret)
71+
}
72+
73+
func deleteResources() {
74+
for _, d := range testsTable {
75+
if len(d.teardown) == 0 {
76+
continue
77+
}
78+
79+
command := strings.Split(d.teardown, " ")
80+
_ = exec.Command(command[0], command[1:]...).Run()
81+
}
82+
}
83+
84+
func (d *dumpStep) fileExists() error {
85+
checkTick := time.NewTicker(checkInterval)
86+
timeoutTick := time.NewTicker(checkTimeout)
87+
defer checkTick.Stop()
88+
defer timeoutTick.Stop()
89+
90+
command := strings.Split(d.cmd, " ")
91+
cmd := exec.Command(command[0], command[1:]...)
92+
93+
out, err := cmd.CombinedOutput()
94+
if err != nil {
95+
return fmt.Errorf("%s failed with code %v: %s", d.cmd, err, out)
96+
}
97+
98+
for {
99+
select {
100+
case <-checkTick.C:
101+
_, err := os.Stat(path.Join(dumpPath, d.relpath))
102+
103+
if err == nil && d.shouldExist {
104+
return nil
105+
}
106+
107+
if os.IsNotExist(err) && !d.shouldExist {
108+
return nil
109+
}
110+
111+
case <-timeoutTick.C:
112+
return fmt.Errorf("timeout waiting for %s", d.relpath)
113+
}
114+
}
115+
}

pkg/client/client_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ func TestClientSet(t *testing.T) {
3131

3232
_ = os.Unsetenv("KUBERNETES_SERVICE_HOST")
3333
_ = os.Setenv("HOME", nonExistentPath)
34+
_ = os.Setenv("KUBECONFIG", nonExistentPath)
3435
_, err = New("", "")
3536
if err == nil {
3637
t.Fatal("New() should fail to load InClusterConfig without kube address env")

0 commit comments

Comments
 (0)