Skip to content

Commit 2e5ac25

Browse files
author
Priya Wadhwa
committed
Add integration test for skaffold dev
I added an integration test to make sure a Job is deleted and redeployed upon changes when running via skaffold dev. The test sets up by creating a file foo. It runs skaffold dev and make sure the Job is created. It then changes foo so that skaffold redeploys, and makes sure the UID of the new Job is different from the UID of the old job.
1 parent 8747bf9 commit 2e5ac25

File tree

6 files changed

+166
-7
lines changed

6 files changed

+166
-7
lines changed

examples/test-dev-job/Dockerfile

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
FROM golang:1.10.1-alpine3.7 as builder
2+
COPY main.go .
3+
RUN go build -o /app main.go
4+
5+
FROM alpine:3.7
6+
CMD ["./app"]
7+
COPY --from=builder /app .
8+
COPY foo /foo

examples/test-dev-job/k8s-job.yaml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
apiVersion: batch/v1
2+
kind: Job
3+
metadata:
4+
name: test-dev-job
5+
spec:
6+
template:
7+
spec:
8+
containers:
9+
- name: test-dev-job
10+
image: gcr.io/k8s-skaffold/test-dev-job
11+
restartPolicy: OnFailure

examples/test-dev-job/main.go

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"time"
6+
)
7+
8+
func main() {
9+
for {
10+
fmt.Println("Hello world!!")
11+
time.Sleep(time.Second * 1)
12+
}
13+
}

examples/test-dev-job/skaffold.yaml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
apiVersion: skaffold/v1alpha2
2+
kind: Config
3+
build:
4+
artifacts:
5+
- imageName: gcr.io/k8s-skaffold/test-dev-job
6+
deploy:
7+
kubectl:
8+
manifests:
9+
- k8s-*
10+
profiles:
11+
- name: gcb
12+
build:
13+
googleCloudBuild:
14+
projectId: k8s-skaffold

integration/run_test.go

+106-7
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ import (
3030
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
3131
"github.com/sirupsen/logrus"
3232
appsv1 "k8s.io/api/apps/v1"
33+
batchv1 "k8s.io/api/batch/v1"
3334
"k8s.io/api/core/v1"
3435
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
36+
"k8s.io/apimachinery/pkg/util/wait"
3537
"k8s.io/client-go/kubernetes"
3638
)
3739

@@ -185,19 +187,116 @@ func TestRun(t *testing.T) {
185187
}
186188

187189
// Cleanup
188-
args = []string{"delete", "--namespace", ns.Name}
189-
if testCase.filename != "" {
190-
args = append(args, "-f", testCase.filename)
191-
}
192-
cmd = exec.Command("skaffold", args...)
190+
cleanupTest(t, ns, testCase.dir, testCase.filename)
191+
})
192+
}
193+
}
194+
195+
func TestDev(t *testing.T) {
196+
type testDevCase struct {
197+
description string
198+
dir string
199+
args []string
200+
setup func(t *testing.T) func(t *testing.T)
201+
jobs []string
202+
jobValidation func(t *testing.T, ns *v1.Namespace, j *batchv1.Job)
203+
}
204+
205+
testCases := []testDevCase{
206+
{
207+
description: "delete and redeploy job",
208+
dir: "../examples/test-dev-job",
209+
args: []string{"dev"},
210+
setup: func(t *testing.T) func(t *testing.T) {
211+
// create foo
212+
cmd := exec.Command("touch", "../examples/test-dev-job/foo")
213+
if output, err := util.RunCmdOut(cmd); err != nil {
214+
t.Fatalf("creating foo: %s %v", output, err)
215+
}
216+
return func(t *testing.T) {
217+
// delete foo
218+
cmd := exec.Command("rm", "../examples/test-dev-job/foo")
219+
if output, err := util.RunCmdOut(cmd); err != nil {
220+
t.Fatalf("creating foo: %s %v", output, err)
221+
}
222+
}
223+
},
224+
jobs: []string{
225+
"test-dev-job",
226+
},
227+
jobValidation: func(t *testing.T, ns *v1.Namespace, j *batchv1.Job) {
228+
originalUID := j.GetUID()
229+
// Make a change to foo so that dev is forced to delete the job and redeploy
230+
cmd := exec.Command("sh", "-c", "echo bar > ../examples/test-dev-job/foo")
231+
if output, err := util.RunCmdOut(cmd); err != nil {
232+
t.Fatalf("creating bar: %s %v", output, err)
233+
}
234+
// Make sure the UID of the old Job and the UID of the new Job is different
235+
err := wait.PollImmediate(time.Millisecond*500, 10*time.Minute, func() (bool, error) {
236+
newJob, err := client.BatchV1().Jobs(ns.Name).Get(j.Name, meta_v1.GetOptions{})
237+
if err != nil {
238+
return false, nil
239+
}
240+
return originalUID != newJob.GetUID(), nil
241+
})
242+
if err != nil {
243+
t.Fatalf("original UID and new UID are the same, redeploy failed")
244+
}
245+
},
246+
},
247+
}
248+
249+
for _, testCase := range testCases {
250+
t.Run(testCase.description, func(t *testing.T) {
251+
ns, deleteNs := setupNamespace(t)
252+
defer deleteNs()
253+
254+
cleanupTC := testCase.setup(t)
255+
defer cleanupTC(t)
256+
257+
args := []string{}
258+
args = append(args, testCase.args...)
259+
args = append(args, "--namespace", ns.Name)
260+
261+
cmd := exec.Command("skaffold", args...)
193262
cmd.Dir = testCase.dir
194-
if output, err := util.RunCmdOut(cmd); err != nil {
195-
t.Fatalf("skaffold delete: %s %v", output, err)
263+
go func() {
264+
if output, err := util.RunCmdOut(cmd); err != nil {
265+
t.Fatalf("skaffold: %s %v", output, err)
266+
}
267+
}()
268+
269+
for _, j := range testCase.jobs {
270+
if err := kubernetesutil.WaitForJobToStabilize(client, ns.Name, j, 10*time.Minute); err != nil {
271+
t.Fatalf("Timed out waiting for job to stabilize")
272+
}
273+
if testCase.jobValidation != nil {
274+
job, err := client.BatchV1().Jobs(ns.Name).Get(j, meta_v1.GetOptions{})
275+
if err != nil {
276+
t.Fatalf("Could not find job: %s %s", ns.Name, j)
277+
}
278+
testCase.jobValidation(t, ns, job)
279+
}
196280
}
281+
282+
// Cleanup
283+
cleanupTest(t, ns, testCase.dir, "")
197284
})
198285
}
199286
}
200287

288+
func cleanupTest(t *testing.T, ns *v1.Namespace, dir, filename string) {
289+
args := []string{"delete", "--namespace", ns.Name}
290+
if filename != "" {
291+
args = append(args, "-f", filename)
292+
}
293+
cmd := exec.Command("skaffold", args...)
294+
cmd.Dir = dir
295+
if output, err := util.RunCmdOut(cmd); err != nil {
296+
t.Fatalf("skaffold delete: %s %v", output, err)
297+
}
298+
}
299+
201300
func setupNamespace(t *testing.T) (*v1.Namespace, func()) {
202301
ns, err := client.CoreV1().Namespaces().Create(&v1.Namespace{
203302
ObjectMeta: meta_v1.ObjectMeta{

pkg/skaffold/kubernetes/wait.go

+14
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,17 @@ func WaitForDeploymentToStabilize(c kubernetes.Interface, ns, name string, timeo
123123
})
124124
return err
125125
}
126+
127+
// WaitForJobToStabilize waits till the Job has at least one active pod
128+
func WaitForJobToStabilize(c kubernetes.Interface, ns, name string, timeout time.Duration) error {
129+
return wait.PollImmediate(time.Millisecond*500, timeout, func() (bool, error) {
130+
job, err := c.BatchV1().Jobs(ns).Get(name, meta_v1.GetOptions{})
131+
if err != nil {
132+
return false, nil
133+
}
134+
if job.Status.Active > 0 {
135+
return true, nil
136+
}
137+
return false, nil
138+
})
139+
}

0 commit comments

Comments
 (0)