From 3187b6dc81e0f33745e415bdf4303843ec406c1b Mon Sep 17 00:00:00 2001 From: Claudiu Belu Date: Tue, 27 Apr 2021 13:51:05 +0000 Subject: [PATCH] tests: Adds consumed memory stats test We can check that the reported containers stats are not lower than it should by using the resource-consumer image. This image contains stress / testlimit.exe which can consume a specified amount of memory. Signed-off-by: Claudiu Belu --- integration/common.go | 25 +++++---- integration/container_stats_test.go | 78 +++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 10 deletions(-) diff --git a/integration/common.go b/integration/common.go index 24cb7de82..81995b091 100644 --- a/integration/common.go +++ b/integration/common.go @@ -29,11 +29,12 @@ import ( // ImageList holds public image references type ImageList struct { - Alpine string - BusyBox string - Pause string - VolumeCopyUp string - VolumeOwnership string + Alpine string + BusyBox string + Pause string + ResourceConsumer string + VolumeCopyUp string + VolumeOwnership string } var ( @@ -45,11 +46,12 @@ var ( func initImages(imageListFile string) { imageList = ImageList{ - Alpine: "docker.io/library/alpine:latest", - BusyBox: "docker.io/library/busybox:latest", - Pause: "k8s.gcr.io/pause:3.5", - VolumeCopyUp: "gcr.io/k8s-cri-containerd/volume-copy-up:2.0", - VolumeOwnership: "gcr.io/k8s-cri-containerd/volume-ownership:2.0", + Alpine: "docker.io/library/alpine:latest", + BusyBox: "docker.io/library/busybox:latest", + Pause: "k8s.gcr.io/pause:3.5", + ResourceConsumer: "k8s.gcr.io/e2e-test-images/resource-consumer:1.9", + VolumeCopyUp: "gcr.io/k8s-cri-containerd/volume-copy-up:2.0", + VolumeOwnership: "gcr.io/k8s-cri-containerd/volume-ownership:2.0", } if imageListFile != "" { @@ -79,6 +81,8 @@ const ( BusyBox // Pause image Pause + // ResourceConsumer image + ResourceConsumer // VolumeCopyUp image VolumeCopyUp // VolumeOwnership image @@ -90,6 +94,7 @@ func initImageMap(imageList ImageList) map[int]string { images[Alpine] = imageList.Alpine images[BusyBox] = imageList.BusyBox images[Pause] = imageList.Pause + images[ResourceConsumer] = imageList.ResourceConsumer images[VolumeCopyUp] = imageList.VolumeCopyUp images[VolumeOwnership] = imageList.VolumeOwnership return images diff --git a/integration/container_stats_test.go b/integration/container_stats_test.go index 6752b523f..a3d402217 100644 --- a/integration/container_stats_test.go +++ b/integration/container_stats_test.go @@ -20,6 +20,7 @@ package integration import ( "fmt" + goruntime "runtime" "testing" "time" @@ -74,6 +75,83 @@ func TestContainerStats(t *testing.T) { testStats(t, s, containerConfig) } +// Test to verify if the consumed stats are correct. +func TestContainerConsumedStats(t *testing.T) { + t.Logf("Create a pod config and run sandbox container") + sbConfig := PodSandboxConfig("sandbox1", "stats") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + + testImage := GetImage(ResourceConsumer) + img, err := imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil, sbConfig) + require.NoError(t, err) + defer func() { + assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img})) + }() + + t.Logf("Create a container config and run container in a pod") + containerConfig := ContainerConfig( + "container1", + testImage, + WithTestLabels(), + WithTestAnnotations(), + ) + cn, err := runtimeService.CreateContainer(sb, containerConfig, sbConfig) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.RemoveContainer(cn)) + }() + require.NoError(t, runtimeService.StartContainer(cn)) + defer func() { + assert.NoError(t, runtimeService.StopContainer(cn, 10)) + }() + + t.Logf("Fetch initial stats for container") + var s *runtime.ContainerStats + require.NoError(t, Eventually(func() (bool, error) { + s, err = runtimeService.ContainerStats(cn) + if err != nil { + return false, err + } + if s.GetMemory().GetWorkingSetBytes().GetValue() > 0 { + return true, nil + } + return false, nil + }, time.Second, 30*time.Second)) + + initialMemory := s.GetMemory().GetWorkingSetBytes().GetValue() + t.Logf("Initial container memory consumption is %f MB. Consume 100 MB and expect the reported stats to increase accordingly", float64(initialMemory)/(1024*1024)) + + // consume 100 MB memory for 30 seconds. + var command []string + if goruntime.GOOS == "windows" { + // -d: Leak and touch memory in specified MBs + // -c: Count of number of objects to allocate + command = []string{"testlimit.exe", "-accepteula", "-d", "25", "-c", "4"} + } else { + command = []string{"stress", "-m", "1", "--vm-bytes", "100M", "--vm-hang", "0", "-t", "30"} + } + + go func() { + _, _, err = runtimeService.ExecSync(cn, command, 30*time.Second) + }() + + require.NoError(t, Eventually(func() (bool, error) { + s, err = runtimeService.ContainerStats(cn) + if err != nil { + return false, err + } + if s.GetMemory().GetWorkingSetBytes().GetValue() > initialMemory+100*1024*1024 { + return true, nil + } + return false, nil + }, time.Second, 30*time.Second)) +} + // Test to verify filtering without any filter func TestContainerListStats(t *testing.T) { t.Logf("Create a pod config and run sandbox container")