@@ -33,6 +33,7 @@ import (
33
33
34
34
"github.com/onsi/ginkgo/v2"
35
35
"github.com/onsi/gomega"
36
+ "github.com/onsi/gomega/gstruct"
36
37
v1 "k8s.io/api/core/v1"
37
38
"k8s.io/apimachinery/pkg/api/resource"
38
39
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
56
57
noLimits * resource.Quantity = nil
57
58
)
58
59
59
- var _ = SIGDescribe ("Swap" , "[LinuxOnly]" , feature .Swap , framework .WithSerial (), func () {
60
+ var _ = SIGDescribe ("Swap" , "[LinuxOnly]" , ginkgo . Ordered , feature .Swap , framework .WithSerial (), func () {
60
61
f := framework .NewDefaultFramework ("swap-qos" )
61
62
addAfterEachForCleaningUpPods (f )
62
63
f .NamespacePodSecurityLevel = admissionapi .LevelBaseline
@@ -287,6 +288,69 @@ var _ = SIGDescribe("Swap", "[LinuxOnly]", feature.Swap, framework.WithSerial(),
287
288
err := podClient .Delete (context .Background (), stressPod .Name , metav1.DeleteOptions {})
288
289
framework .ExpectNoError (err )
289
290
})
291
+
292
+ ginkgo .It ("ensure summary API properly reports swap" , func () {
293
+ stressSize := divideQuantity (nodeTotalMemory , 5 )
294
+ ginkgo .By ("Creating a stress pod with stress size: " + stressSize .String ())
295
+ stressPod := getStressPod (stressSize )
296
+
297
+ memoryLimit := cloneQuantity (stressSize )
298
+ memoryLimit .Sub (resource .MustParse ("50Mi" ))
299
+ memoryRequest := divideQuantity (memoryLimit , 2 )
300
+ ginkgo .By ("Adding memory request of " + memoryRequest .String () + " and memory limit of " + memoryLimit .String ())
301
+ setPodMemoryResources (stressPod , memoryRequest , memoryLimit )
302
+ gomega .Expect (qos .GetPodQOS (stressPod )).To (gomega .Equal (v1 .PodQOSBurstable ))
303
+
304
+ stressPod = runPodAndWaitUntilScheduled (f , stressPod )
305
+
306
+ ginkgo .By ("Ensuring the pod is using swap" )
307
+ var swapUsage * resource.Quantity
308
+ gomega .Eventually (func () error {
309
+ stressPod = getUpdatedPod (f , stressPod )
310
+ gomega .Expect (stressPod .Status .Phase ).To (gomega .Equal (v1 .PodRunning ), "pod should be running" )
311
+
312
+ var err error
313
+ swapUsage , err = getSwapUsage (f , stressPod )
314
+ if err != nil {
315
+ return err
316
+ }
317
+
318
+ if swapUsage .IsZero () {
319
+ return fmt .Errorf ("swap usage is zero" )
320
+ }
321
+
322
+ return nil
323
+ }, 5 * time .Minute , 1 * time .Second ).Should (gomega .Succeed ())
324
+
325
+ ginkgo .By ("Waiting 15 seconds for cAdvisor to collect 2 stats points" )
326
+ time .Sleep (15 * time .Second )
327
+
328
+ getSwapExpectation := func () gomega.OmegaMatcher {
329
+ return gstruct .PointTo (gstruct .MatchFields (gstruct .IgnoreExtras , gstruct.Fields {
330
+ "Time" : recent (maxStatsAge ),
331
+ "SwapUsageBytes" : bounded (1 , memoryLimit .Value ()),
332
+ }))
333
+ }
334
+
335
+ matchExpectations := gstruct .PointTo (gstruct .MatchFields (gstruct .IgnoreExtras , gstruct.Fields {
336
+ "Pods" : gstruct .MatchElements (summaryObjectID , gstruct .IgnoreExtras , gstruct.Elements {
337
+ fmt .Sprintf ("%s::%s" , f .Namespace .Name , stressPod .Name ): gstruct .MatchFields (gstruct .IgnoreExtras , gstruct.Fields {
338
+ "Containers" : gstruct .MatchElements (summaryObjectID , gstruct .IgnoreExtras , gstruct.Elements {
339
+ stressPod .Spec .Containers [0 ].Name : gstruct .MatchFields (gstruct .IgnoreExtras , gstruct.Fields {
340
+ "Swap" : getSwapExpectation (),
341
+ }),
342
+ }),
343
+ "Swap" : getSwapExpectation (),
344
+ }),
345
+ }),
346
+ }))
347
+
348
+ ginkgo .By ("Validating /stats/summary" )
349
+ // Give pods a minute to actually start up.
350
+ gomega .Eventually (context .Background (), getNodeSummary , 180 * time .Second , 15 * time .Second ).Should (matchExpectations )
351
+ // Then the summary should match the expectations a few more times.
352
+ gomega .Consistently (context .Background (), getNodeSummary , 30 * time .Second , 15 * time .Second ).Should (matchExpectations )
353
+ })
290
354
})
291
355
})
292
356
})
0 commit comments