Skip to content

Commit

Permalink
Tests for get command
Browse files Browse the repository at this point in the history
  • Loading branch information
timebertt committed May 27, 2024
1 parent a4ed912 commit 6d352b5
Show file tree
Hide file tree
Showing 6 changed files with 378 additions and 0 deletions.
176 changes: 176 additions & 0 deletions test/e2e/get_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package e2e

import (
"io"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gbytes"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"

. "github.com/timebertt/kubectl-history/test/e2e/exec"
"github.com/timebertt/kubectl-history/test/e2e/workload"
)

var _ = Describe("get command", func() {
var (
namespace string
object client.Object

args []string
)

BeforeEach(func() {
namespace = workload.PrepareTestNamespace()
args = []string{"get", "-n", namespace}
})

Describe("command aliases", func() {
BeforeEach(func() {
object = workload.CreateDeployment(namespace)
args = append(args, "deployment", object.GetName())
})

It("should work with alias ls", func() {
args[0] = "ls"
Eventually(RunHistoryAndWait(args...)).Should(Say(`nginx-\S+\s+1\s+\S+\n`))
})

It("should work with alias list", func() {
args[0] = "list"
Eventually(RunHistoryAndWait(args...)).Should(Say(`nginx-\S+\s+1\s+\S+\n`))
})
})

testCommon := func() {
It("should print a single revision in list format", func() {
session := RunHistoryAndWait(args...)
Eventually(session).Should(Say(`nginx-\S+\s+1\s+\S+\n`))
Consistently(session).ShouldNot(Say(`nginx-`))
})

It("should print image column in wide format", func() {
workload.BumpImage(object)
workload.BumpImage(object)

session := RunHistoryAndWait(append(args, "-o", "wide")...)
Eventually(session).Should(Say(`nginx-\S+\s+1\s+\S+\s+nginx\s+\S+:0.1\n`))
Eventually(session).Should(Say(`nginx-\S+\s+2\s+\S+\s+nginx\s+\S+:0.2\n`))
Eventually(session).Should(Say(`nginx-\S+\s+3\s+\S+\s+nginx\s+\S+:0.3\n`))
Consistently(session).ShouldNot(Say(`nginx-`))
})

It("should print a specific revision in list format (absolute revision)", func() {
workload.BumpImage(object)
workload.BumpImage(object)

session := RunHistoryAndWait(append(args, "--revision=2")...)
Eventually(session).Should(Say(`nginx-\S+\s+2\s+\S+\n`))
Consistently(session).ShouldNot(Say(`nginx-`))
})

It("should print a specific revision in wide format (relative revision)", func() {
workload.BumpImage(object)
workload.BumpImage(object)

session := RunHistoryAndWait(append(args, "--revision=2", "-o", "wide")...)
Eventually(session).Should(Say(`nginx-\S+\s+2\s+\S+\s+nginx\s+\S+:0.2\n`))
Consistently(session).ShouldNot(Say(`nginx-`))
})

It("should print a specific revision in yaml format", func() {
workload.BumpImage(object)
workload.BumpImage(object)

session := RunHistoryAndWait(append(args, "--revision=1", "-o", "yaml")...)

yamlBytes, err := io.ReadAll(session.Out)
Expect(err).NotTo(HaveOccurred())
Expect(string(yamlBytes)).To(ContainSubstring("image: " + workload.ImageRepository + ":0.1"))

Expect(runtime.DecodeInto(decoder, yamlBytes, workload.RevisionObjectFor(object))).To(Succeed())
})

It("should print a specific revision's pod template in json format on --template-only", func() {
workload.BumpImage(object)
workload.BumpImage(object)

session := RunHistoryAndWait(append(args, "--revision=2", "-o", "json", "--template-only")...)

jsonBytes, err := io.ReadAll(session.Out)
Expect(err).NotTo(HaveOccurred())

pod := &corev1.Pod{}
Expect(runtime.DecodeInto(decoder, jsonBytes, pod)).To(Succeed())
Expect(pod.Spec.Containers).To(HaveLen(1))
Expect(pod.Spec.Containers[0].Image).To(Equal(workload.ImageRepository + ":0.2"))
})

It("should print the full revision list in yaml format", func() {
workload.BumpImage(object)
workload.BumpImage(object)

session := RunHistoryAndWait(append(args, "-o", "yaml")...)

yamlBytes, err := io.ReadAll(session.Out)
Expect(err).NotTo(HaveOccurred())

list := &metav1.List{}
Expect(runtime.DecodeInto(decoder, yamlBytes, list)).To(Succeed())
Expect(list.Items).To(HaveLen(3))

Expect(runtime.DecodeInto(decoder, list.Items[0].Raw, workload.RevisionObjectFor(object))).To(Succeed())
})
}

Context("Deployment", func() {
BeforeEach(func() {
object = workload.CreateDeployment(namespace)
args = append(args, "deployment", object.GetName())
})

testCommon()

It("should work with short type", func() {
args[3] = "deploy"
Eventually(RunHistoryAndWait(args...)).Should(Say(`nginx-\S+\s+1\s+\S+\n`))
})

It("should work with grouped type", func() {
args[3] = "deployments.apps"
Eventually(RunHistoryAndWait(args...)).Should(Say(`nginx-\S+\s+1\s+\S+\n`))
})

It("should work with fully-qualified type", func() {
args[3] = "deployments.v1.apps"
Eventually(RunHistoryAndWait(args...)).Should(Say(`nginx-\S+\s+1\s+\S+\n`))
})

It("should work with slash name", func() {
args[3] = "deployment/nginx"
args = args[:len(args)-1]
Eventually(RunHistoryAndWait(args...)).Should(Say(`nginx-\S+\s+1\s+\S+\n`))
})
})

Context("StatefulSet", func() {
BeforeEach(func() {
object = workload.CreateStatefulSet(namespace)
args = append(args, "statefulset", object.GetName())
})

testCommon()
})

Context("DaemonSet", func() {
BeforeEach(func() {
object = workload.CreateDaemonSet(namespace)
args = append(args, "daemonset", object.GetName())
})

testCommon()
})
})
41 changes: 41 additions & 0 deletions test/e2e/workload/daemonset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package workload

import (
"context"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/envtest/komega"
)

func CreateDaemonSet(namespace string) *appsv1.DaemonSet {
GinkgoHelper()

labels := map[string]string{"app": AppName}
statefulSet := &appsv1.DaemonSet{
ObjectMeta: metav1.ObjectMeta{
Name: AppName,
Namespace: namespace,
},
Spec: appsv1.DaemonSetSpec{
Selector: &metav1.LabelSelector{
MatchLabels: labels,
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: PodSpec(),
},
},
}

Expect(testClient.Create(context.Background(), statefulSet)).To(Succeed())

Eventually(komega.Object(statefulSet)).Should(HaveField("Status.ObservedGeneration", statefulSet.GetGeneration()))

return statefulSet
}
41 changes: 41 additions & 0 deletions test/e2e/workload/deployment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package workload

import (
"context"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/envtest/komega"
)

func CreateDeployment(namespace string) *appsv1.Deployment {
GinkgoHelper()

labels := map[string]string{"app": AppName}
deployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: AppName,
Namespace: namespace,
},
Spec: appsv1.DeploymentSpec{
Selector: &metav1.LabelSelector{
MatchLabels: labels,
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: PodSpec(),
},
},
}

Expect(testClient.Create(context.Background(), deployment)).To(Succeed())

Eventually(komega.Object(deployment)).Should(HaveField("Status.ObservedGeneration", deployment.GetGeneration()))

return deployment
}
60 changes: 60 additions & 0 deletions test/e2e/workload/pod.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package workload

import (
"context"
"fmt"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest/komega"
)

const (
AppName = "nginx"
ImageRepository = "registry.k8s.io/nginx-slim"
)

var (
generation = 0
)

func ImageTag() string {
generation++
if generation > 27 {
panic("ImageTag called too many times")
}

DeferCleanup(func() {
generation = 0
})

return fmt.Sprintf("0.%d", generation)
}

func Image() string {
return ImageRepository + ":" + ImageTag()
}

func PodSpec() corev1.PodSpec {
return corev1.PodSpec{
Containers: []corev1.Container{{
Name: AppName,
Image: Image(),
}},
}
}

func BumpImage(obj client.Object) {
GinkgoHelper()

Expect(testClient.Patch(context.Background(), obj, client.RawPatch(types.JSONPatchType, []byte(`[{
"op": "replace",
"path": "/spec/template/spec/containers/0/image",
"value": "`+Image()+`"
}]`)))).To(Succeed())

Eventually(komega.Object(obj)).Should(HaveField("Status.ObservedGeneration", obj.GetGeneration()))
}
19 changes: 19 additions & 0 deletions test/e2e/workload/revision.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package workload

import (
"fmt"

appsv1 "k8s.io/api/apps/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)

func RevisionObjectFor(obj client.Object) client.Object {
switch obj.(type) {
case *appsv1.Deployment:
return &appsv1.ReplicaSet{}
case *appsv1.DaemonSet, *appsv1.StatefulSet:
return &appsv1.ControllerRevision{}
default:
panic(fmt.Errorf("unexpted object type %T", obj))
}
}
41 changes: 41 additions & 0 deletions test/e2e/workload/statefulset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package workload

import (
"context"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/envtest/komega"
)

func CreateStatefulSet(namespace string) *appsv1.StatefulSet {
GinkgoHelper()

labels := map[string]string{"app": AppName}
statefulSet := &appsv1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{
Name: AppName,
Namespace: namespace,
},
Spec: appsv1.StatefulSetSpec{
Selector: &metav1.LabelSelector{
MatchLabels: labels,
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: PodSpec(),
},
},
}

Expect(testClient.Create(context.Background(), statefulSet)).To(Succeed())

Eventually(komega.Object(statefulSet)).Should(HaveField("Status.ObservedGeneration", statefulSet.GetGeneration()))

return statefulSet
}

0 comments on commit 6d352b5

Please sign in to comment.