Skip to content
This repository was archived by the owner on Jan 4, 2022. It is now read-only.

Commit be7a338

Browse files
author
Dongsu Park
committed
tests: initial implementation of smoke tests
A simple implementation of smoke tests based on Vagrant. It initializes a simple K8s cluster with 2 nodes, deploys an nginx pod, a service for the deployment, and checks if it's running. Fixes #56
1 parent 93806d8 commit be7a338

File tree

3 files changed

+317
-0
lines changed

3 files changed

+317
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
apiVersion: apps/v1beta1 # for versions before 1.6.0 use extensions/v1beta1
2+
kind: Deployment
3+
metadata:
4+
name: nginx-deployment
5+
spec:
6+
replicas: 3
7+
template:
8+
metadata:
9+
labels:
10+
app: nginx
11+
spec:
12+
containers:
13+
- name: nginx
14+
image: nginx:1.7.9
15+
ports:
16+
- containerPort: 80

tests/init_test.go

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
/*
2+
Copyright 2017 Kinvolk GmbH
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// +build integration
18+
19+
package tests
20+
21+
import (
22+
"bufio"
23+
"fmt"
24+
"os"
25+
"os/exec"
26+
"path/filepath"
27+
"strings"
28+
"testing"
29+
30+
"github.com/kinvolk/kube-spawn/pkg/utils"
31+
)
32+
33+
const (
34+
k8sStableVersion string = "1.7.5"
35+
defaultKubeSpawnDir string = "/var/lib/kube-spawn"
36+
deploymentName string = "nginx-deployment"
37+
)
38+
39+
var (
40+
numNodes int = 2
41+
42+
kubeSpawnDir string = defaultKubeSpawnDir
43+
kubeSpawnK8sPath string = filepath.Join(kubeSpawnDir, "k8s")
44+
kubeSpawnPath string
45+
kubeCtlPath string
46+
47+
machineCtlPath string
48+
)
49+
50+
func checkRequirements(t *testing.T) {
51+
if os.Geteuid() != 0 {
52+
t.Fatal("smoke test requires root privileges")
53+
}
54+
}
55+
56+
func initPath(t *testing.T) {
57+
var err error
58+
59+
// go one dir upper, from "tests" to the top source directory
60+
if err := os.Chdir(".."); err != nil {
61+
t.Fatal(err)
62+
}
63+
64+
kubeSpawnPath = "./kube-spawn"
65+
t.Logf("kubeSpawnPath = %s\n", kubeSpawnPath)
66+
if err := utils.CheckValidFile(kubeSpawnPath); err != nil {
67+
if kubeSpawnPath, err = exec.LookPath("kube-spawn"); err != nil {
68+
// fall back to an ordinary abspath to kube-spawn
69+
kubeSpawnPath = "/usr/bin/kube-spawn"
70+
}
71+
}
72+
73+
_ = os.MkdirAll(kubeSpawnK8sPath, os.FileMode(0755))
74+
75+
kubeCtlPath = filepath.Join(kubeSpawnK8sPath, "kubectl")
76+
if err := utils.CheckValidFile(kubeCtlPath); err != nil {
77+
if kubeCtlPath, err = exec.LookPath(kubeCtlPath); err != nil {
78+
// fall back to an ordinary abspath to kubectl
79+
kubeCtlPath = "/usr/bin/kubectl"
80+
}
81+
}
82+
83+
machineCtlPath, err = exec.LookPath("machinectl")
84+
if err != nil {
85+
// fall back to an ordinary abspath to machinectl
86+
machineCtlPath = "/usr/bin/machinectl"
87+
}
88+
}
89+
90+
func initNode(t *testing.T) {
91+
// If no coreos image exists, just download it
92+
if _, _, err := runCommand(fmt.Sprintf("%s show-image coreos", machineCtlPath)); err != nil {
93+
if stdout, stderr, err := runCommand(fmt.Sprintf("%s pull-raw --verify=no %s %s",
94+
machineCtlPath,
95+
"https://alpha.release.core-os.net/amd64-usr/current/coreos_developer_container.bin.bz2",
96+
"coreos",
97+
)); err != nil {
98+
t.Fatalf("error running machinectl pull-raw: %v\nstdout: %s\nstderr: %s", err, stdout, stderr)
99+
}
100+
}
101+
}
102+
103+
func getRunningNodes() ([]string, error) {
104+
var nodeNames []string
105+
106+
stdout, stderr, err := runCommand(fmt.Sprintf("%s list --no-legend", machineCtlPath))
107+
if err != nil {
108+
return nil, fmt.Errorf("error running machinectl list: %v\nstdout: %s\nstderr: %s", err, stdout, stderr)
109+
}
110+
111+
s := bufio.NewScanner(strings.NewReader(strings.TrimSpace(stdout)))
112+
for s.Scan() {
113+
line := strings.Fields(s.Text())
114+
if len(line) <= 2 {
115+
continue
116+
}
117+
118+
// an example line:
119+
// kube-spawn-0 container systemd-nspawn coreos 1478.0.0 10.22.0.130...
120+
nodeName := strings.TrimSpace(line[0])
121+
if !strings.HasPrefix(nodeName, "kube-spawn-") {
122+
continue
123+
}
124+
125+
nodeNames = append(nodeNames, nodeName)
126+
}
127+
128+
return nodeNames, nil
129+
}
130+
131+
func checkK8sNodes(t *testing.T) {
132+
stdout, stderr, err := runCommand(fmt.Sprintf("%s get nodes", kubeCtlPath))
133+
if err != nil {
134+
t.Fatalf("error running kubectl get nodes: %v\nstdout: %s\nstderr: %s", err, stdout, stderr)
135+
}
136+
137+
outStr := strings.TrimSpace(string(stdout))
138+
scanner := bufio.NewScanner(strings.NewReader(outStr))
139+
var numLines int = 0
140+
for scanner.Scan() {
141+
if len(strings.TrimSpace(scanner.Text())) == 0 {
142+
continue
143+
}
144+
numLines += 1
145+
}
146+
147+
if numLines != numNodes {
148+
t.Fatalf("got %d nodes, expected %d nodes.\n", numLines, numNodes)
149+
}
150+
}
151+
152+
func testSetupK8sStable(t *testing.T) {
153+
if stdout, stderr, err := runCommand(fmt.Sprintf("%s --kubernetes-version=%s setup --nodes=%d",
154+
kubeSpawnPath, k8sStableVersion, numNodes),
155+
); err != nil {
156+
t.Fatalf("error running kube-spawn setup: %v\nstdout: %s\nstderr: %s", err, stdout, stderr)
157+
}
158+
159+
nodes, err := getRunningNodes()
160+
if err != nil {
161+
t.Fatalf("error getting list of running nodes: %v\n", err)
162+
}
163+
if len(nodes) != numNodes {
164+
t.Fatalf("got %d nodes, expected %d nodes.\n", len(nodes), numNodes)
165+
}
166+
}
167+
168+
func testInitK8sStable(t *testing.T) {
169+
if stdout, stderr, err := runCommand(fmt.Sprintf("%s --kubernetes-version=%s init",
170+
kubeSpawnPath, k8sStableVersion),
171+
); err != nil {
172+
t.Fatalf("error running kube-spawn init: %v\nstdout: %s\nstderr: %s", err, stdout, stderr)
173+
}
174+
175+
// set env variable KUBECONFIG to /var/lib/kube-spawn/default/kubeconfig
176+
if err := os.Setenv("KUBECONFIG", utils.GetValidKubeConfig()); err != nil {
177+
t.Fatalf("error running setenv: %v\n", err)
178+
}
179+
checkK8sNodes(t)
180+
}
181+
182+
func testCreateDeploy(t *testing.T) {
183+
if stdout, stderr, err := runCommand(fmt.Sprintf("%s create -f %s",
184+
kubeCtlPath, "./tests/fixtures/nginx-deployment.yaml"),
185+
); err != nil {
186+
t.Fatalf("error creating deployment: %v\nstdout: %s\nstderr: %s", err, stdout, stderr)
187+
}
188+
189+
stdout, stderr, err := runCommand(fmt.Sprintf("%s get deployments --no-headers=true", kubeCtlPath))
190+
if err != nil {
191+
t.Fatalf("error getting deployments: %v\nstdout: %s\nstderr: %s", err, stdout, stderr)
192+
}
193+
194+
outStr := strings.TrimSpace(string(stdout))
195+
scanner := bufio.NewScanner(strings.NewReader(outStr))
196+
var depNames []string
197+
for scanner.Scan() {
198+
if len(strings.TrimSpace(scanner.Text())) == 0 {
199+
continue
200+
}
201+
depNames = append(depNames, strings.Fields(scanner.Text())[0])
202+
}
203+
204+
if len(depNames) == 0 {
205+
t.Fatalf("cannot find any deployment\n")
206+
}
207+
208+
if !existInSlice(deploymentName, depNames) {
209+
t.Fatalf("cannot find nginx deployment\n")
210+
}
211+
}
212+
213+
func testServices(t *testing.T) {
214+
stdout, stderr, err := runCommand(fmt.Sprintf("%s get services --no-headers=true", kubeCtlPath))
215+
if err != nil {
216+
t.Fatalf("error getting services: %v\nstdout: %s\nstderr: %s", err, stdout, stderr)
217+
}
218+
219+
outStr := strings.TrimSpace(string(stdout))
220+
scanner := bufio.NewScanner(strings.NewReader(outStr))
221+
var svcNames []string
222+
for scanner.Scan() {
223+
if len(strings.TrimSpace(scanner.Text())) == 0 {
224+
continue
225+
}
226+
svcNames = append(svcNames, strings.Fields(scanner.Text())[0])
227+
}
228+
229+
if len(svcNames) == 0 {
230+
t.Fatalf("cannot find any services\n")
231+
}
232+
233+
if !existInSlice("kubernetes", svcNames) {
234+
t.Fatalf("cannot find a service\n")
235+
}
236+
}
237+
238+
func testDeleteDeploy(t *testing.T) {
239+
stdout, stderr, err := runCommand(fmt.Sprintf("%s delete deployment %s", kubeCtlPath, deploymentName))
240+
if err != nil {
241+
t.Fatalf("error deleting deployments %v\nstdout: %s\nstderr: %s", err, stdout, stderr)
242+
}
243+
}
244+
245+
func TestMainK8sStable(t *testing.T) {
246+
checkRequirements(t)
247+
initPath(t)
248+
initNode(t)
249+
250+
testSetupK8sStable(t)
251+
testInitK8sStable(t)
252+
testCreateDeploy(t)
253+
testServices(t)
254+
}

tests/utils.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
Copyright 2017 Kinvolk GmbH
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// +build integration
18+
19+
package tests
20+
21+
import (
22+
"bytes"
23+
"log"
24+
"os/exec"
25+
"strings"
26+
)
27+
28+
func runCommand(command string) (string, string, error) {
29+
log.Printf(command)
30+
31+
var stdoutBytes, stderrBytes bytes.Buffer
32+
args := strings.Split(command, " ")
33+
cmd := exec.Command(args[0], args[1:]...)
34+
cmd.Stdout = &stdoutBytes
35+
cmd.Stderr = &stderrBytes
36+
err := cmd.Run()
37+
return stdoutBytes.String(), stderrBytes.String(), err
38+
}
39+
40+
func existInSlice(key string, inSlice []string) bool {
41+
for _, n := range inSlice {
42+
if n == key {
43+
return true
44+
}
45+
}
46+
return false
47+
}

0 commit comments

Comments
 (0)