Skip to content

Commit

Permalink
Add e2e tests for replicas of multiple revisions
Browse files Browse the repository at this point in the history
  • Loading branch information
timebertt committed Jun 12, 2024
1 parent 7080edd commit 862345a
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ kind-up kind-down: export KUBECONFIG = $(KIND_KUBECONFIG)

.PHONY: kind-up
kind-up: $(KIND) $(KUBECTL) ## Launch a kind cluster for local development and testing.
$(KIND) create cluster --name revisions --image kindest/node:$(KIND_KUBERNETES_VERSION)
$(KIND) create cluster --name revisions --config hack/kind-config.yaml --image kindest/node:$(KIND_KUBERNETES_VERSION)
# workaround https://kind.sigs.k8s.io/docs/user/known-issues/#pod-errors-due-to-too-many-open-files
$(KUBECTL) get nodes -o name | cut -d/ -f2 | xargs -I {} docker exec {} sh -c "sysctl fs.inotify.max_user_instances=8192"
# run `export KUBECONFIG=$$PWD/hack/kind_kubeconfig.yaml` to target the created kind cluster.
Expand Down
8 changes: 8 additions & 0 deletions hack/kind-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
# create a cluster with 3 worker nodes so that we can test DaemonSets with multiple replicas easily.
nodes:
- role: control-plane
- role: worker
- role: worker
- role: worker
54 changes: 54 additions & 0 deletions test/e2e/get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest/komega"

. "github.com/timebertt/kubectl-revisions/test/e2e/exec"
"github.com/timebertt/kubectl-revisions/test/e2e/workload"
Expand Down Expand Up @@ -156,6 +157,21 @@ var _ = Describe("get command", func() {
args = args[:len(args)-1]
Eventually(RunPluginAndWait(args...)).Should(Say(`pause-\S+\s+1\s+\d/\d\s+\S+\n`))
})

It("should correctly print replicas", func() {
workload.Scale(object, 2)
Eventually(komega.Object(object)).Should(HaveField("Status.ReadyReplicas", int32(2)))

// prepare second revision with broken image
// this make it easy and deterministic to test the replica column for multiple revisions
workload.SetImage(object, workload.ImageRepository+":non-existing")
Eventually(komega.Object(object)).Should(HaveField("Status.UpdatedReplicas", int32(1)))

session := RunPluginAndWait(args...)
Eventually(session).Should(Say(`NAME\s+REVISION\s+READY\s+AGE\n`))
Eventually(session).Should(Say(`pause-\S+\s+1\s+2/2\s+\S+\n`))
Eventually(session).Should(Say(`pause-\S+\s+2\s+0/1\s+\S+\n`))
})
})

Context("StatefulSet", func() {
Expand All @@ -165,6 +181,21 @@ var _ = Describe("get command", func() {
})

testCommon()

It("should correctly print replicas", func() {
workload.Scale(object, 2)
Eventually(komega.Object(object)).Should(HaveField("Status.ReadyReplicas", int32(2)))

// prepare second revision with broken image
// this make it easy and deterministic to test the replica column for multiple revisions
workload.SetImage(object, workload.ImageRepository+":non-existing")
Eventually(komega.Object(object)).Should(HaveField("Status.UpdatedReplicas", int32(1)))

session := RunPluginAndWait(args...)
Eventually(session).Should(Say(`NAME\s+REVISION\s+READY\s+AGE\n`))
Eventually(session).Should(Say(`pause-\S+\s+1\s+1/1\s+\S+\n`))
Eventually(session).Should(Say(`pause-\S+\s+2\s+0/1\s+\S+\n`))
})
})

Context("DaemonSet", func() {
Expand All @@ -174,5 +205,28 @@ var _ = Describe("get command", func() {
})

testCommon()

It("should correctly print replicas", func() {
Eventually(komega.Object(object)).Should(HaveField("Status.NumberReady", int32(3)))

// prepare second revision with broken image
// this make it easy and deterministic to test the replica column for multiple revisions
workload.SetImage(object, workload.ImageRepository+":non-existing")
Eventually(komega.Object(object)).Should(And(
HaveField("Status.NumberReady", int32(2)),
HaveField("Status.UpdatedNumberScheduled", int32(1)),
))

// We cannot determine from the DaemonSet status whether the old pod has finished terminating. To make testing
// the plugin deterministic, wait until there are exactly 3 pods left in the namespace (stable state).
// We don't need this for Deployment or StatefulSet as waiting for the status.updatedReplicas field ensures
// the system has a stable state where nothing happens.
Eventually(komega.ObjectList(&corev1.PodList{}, client.InNamespace(namespace))).Should(HaveField("Items", HaveLen(3)))

session := RunPluginAndWait(args...)
Eventually(session).Should(Say(`NAME\s+REVISION\s+READY\s+AGE\n`))
Eventually(session).Should(Say(`pause-\S+\s+1\s+2/2\s+\S+\n`))
Eventually(session).Should(Say(`pause-\S+\s+2\s+0/1\s+\S+\n`))
})
})
})
8 changes: 6 additions & 2 deletions test/e2e/workload/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,18 @@ func PodSpec() corev1.PodSpec {
}
}

func BumpImage(obj client.Object) {
func SetImage(obj client.Object, image string) {
GinkgoHelper()

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

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

func BumpImage(obj client.Object) {
SetImage(obj, Image())
}
22 changes: 22 additions & 0 deletions test/e2e/workload/workload.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package workload

import (
"context"
"fmt"

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

func Scale(obj client.Object, replicas int32) {
GinkgoHelper()

Expect(testClient.Patch(
context.Background(), obj, client.RawPatch(types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"replicas": %d}}`, replicas))),
)).To(Succeed())

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

0 comments on commit 862345a

Please sign in to comment.