From 617c094435436b0d392cbea3475db596ca3231f7 Mon Sep 17 00:00:00 2001 From: Itamar Holder Date: Tue, 7 Jan 2025 13:14:42 +0200 Subject: [PATCH] Add an e2e test Signed-off-by: Itamar Holder --- test/e2e_node/swap_test.go | 66 +++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/test/e2e_node/swap_test.go b/test/e2e_node/swap_test.go index aefd6c2ebb4..eb1cd3d5367 100644 --- a/test/e2e_node/swap_test.go +++ b/test/e2e_node/swap_test.go @@ -33,6 +33,7 @@ import ( "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" + "github.com/onsi/gomega/gstruct" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -56,7 +57,7 @@ var ( noLimits *resource.Quantity = nil ) -var _ = SIGDescribe("Swap", "[LinuxOnly]", feature.Swap, framework.WithSerial(), func() { +var _ = SIGDescribe("Swap", "[LinuxOnly]", ginkgo.Ordered, feature.Swap, framework.WithSerial(), func() { f := framework.NewDefaultFramework("swap-qos") addAfterEachForCleaningUpPods(f) f.NamespacePodSecurityLevel = admissionapi.LevelBaseline @@ -287,6 +288,69 @@ var _ = SIGDescribe("Swap", "[LinuxOnly]", feature.Swap, framework.WithSerial(), err := podClient.Delete(context.Background(), stressPod.Name, metav1.DeleteOptions{}) framework.ExpectNoError(err) }) + + ginkgo.It("ensure summary API properly reports swap", func() { + stressSize := divideQuantity(nodeTotalMemory, 5) + ginkgo.By("Creating a stress pod with stress size: " + stressSize.String()) + stressPod := getStressPod(stressSize) + + memoryLimit := cloneQuantity(stressSize) + memoryLimit.Sub(resource.MustParse("50Mi")) + memoryRequest := divideQuantity(memoryLimit, 2) + ginkgo.By("Adding memory request of " + memoryRequest.String() + " and memory limit of " + memoryLimit.String()) + setPodMemoryResources(stressPod, memoryRequest, memoryLimit) + gomega.Expect(qos.GetPodQOS(stressPod)).To(gomega.Equal(v1.PodQOSBurstable)) + + stressPod = runPodAndWaitUntilScheduled(f, stressPod) + + ginkgo.By("Ensuring the pod is using swap") + var swapUsage *resource.Quantity + gomega.Eventually(func() error { + stressPod = getUpdatedPod(f, stressPod) + gomega.Expect(stressPod.Status.Phase).To(gomega.Equal(v1.PodRunning), "pod should be running") + + var err error + swapUsage, err = getSwapUsage(f, stressPod) + if err != nil { + return err + } + + if swapUsage.IsZero() { + return fmt.Errorf("swap usage is zero") + } + + return nil + }, 5*time.Minute, 1*time.Second).Should(gomega.Succeed()) + + ginkgo.By("Waiting 15 seconds for cAdvisor to collect 2 stats points") + time.Sleep(15 * time.Second) + + getSwapExpectation := func() gomega.OmegaMatcher { + return gstruct.PointTo(gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{ + "Time": recent(maxStatsAge), + "SwapUsageBytes": bounded(1, memoryLimit.Value()), + })) + } + + matchExpectations := gstruct.PointTo(gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{ + "Pods": gstruct.MatchElements(summaryObjectID, gstruct.IgnoreExtras, gstruct.Elements{ + fmt.Sprintf("%s::%s", f.Namespace.Name, stressPod.Name): gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{ + "Containers": gstruct.MatchElements(summaryObjectID, gstruct.IgnoreExtras, gstruct.Elements{ + stressPod.Spec.Containers[0].Name: gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{ + "Swap": getSwapExpectation(), + }), + }), + "Swap": getSwapExpectation(), + }), + }), + })) + + ginkgo.By("Validating /stats/summary") + // Give pods a minute to actually start up. + gomega.Eventually(context.Background(), getNodeSummary, 180*time.Second, 15*time.Second).Should(matchExpectations) + // Then the summary should match the expectations a few more times. + gomega.Consistently(context.Background(), getNodeSummary, 30*time.Second, 15*time.Second).Should(matchExpectations) + }) }) }) })