github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/container-utils/runtime-client/runtimeclient_test.go (about) 1 // Copyright 2023 The Inspektor Gadget authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package runtimeclient_test 16 17 import ( 18 "fmt" 19 "testing" 20 21 "github.com/davecgh/go-spew/spew" 22 "github.com/google/go-cmp/cmp" 23 "github.com/stretchr/testify/require" 24 25 utilstest "github.com/inspektor-gadget/inspektor-gadget/internal/test" 26 containerutils "github.com/inspektor-gadget/inspektor-gadget/pkg/container-utils" 27 runtimeclient "github.com/inspektor-gadget/inspektor-gadget/pkg/container-utils/runtime-client" 28 "github.com/inspektor-gadget/inspektor-gadget/pkg/container-utils/testutils" 29 containerutilsTypes "github.com/inspektor-gadget/inspektor-gadget/pkg/container-utils/types" 30 "github.com/inspektor-gadget/inspektor-gadget/pkg/types" 31 ) 32 33 const ( 34 containerNamePrefix = "test-container" 35 containerImageName = "docker.io/library/alpine:latest" 36 numContainers = 2 37 ) 38 39 func TestRuntimeClientInterface(t *testing.T) { 40 t.Parallel() 41 utilstest.RequireRoot(t) 42 43 for _, runtime := range testutils.SupportedContainerRuntimes { 44 t.Run(runtime.String(), func(t *testing.T) { 45 runtime := runtime 46 t.Parallel() 47 48 // Create test containers and their expected data 49 var expectedData []*runtimeclient.ContainerDetailsData 50 for i := 0; i < numContainers; i++ { 51 cn := fmt.Sprintf("%s-%s-%d", containerNamePrefix, runtime, i) 52 c, err := testutils.NewContainer( 53 runtime, 54 cn, 55 "sleep inf", // We simply want to keep the container running 56 testutils.WithImage(containerImageName), 57 ) 58 require.Nil(t, err) 59 require.NotNil(t, c) 60 61 c.Start(t) 62 t.Cleanup(func() { 63 c.Stop(t) 64 }) 65 66 expectedData = append(expectedData, 67 &runtimeclient.ContainerDetailsData{ 68 ContainerData: runtimeclient.ContainerData{ 69 Runtime: runtimeclient.RuntimeContainerData{ 70 BasicRuntimeMetadata: types.BasicRuntimeMetadata{ 71 RuntimeName: runtime, 72 ContainerName: cn, 73 ContainerID: c.ID(), 74 ContainerImageName: containerImageName, 75 }, 76 State: runtimeclient.StateRunning, 77 }, 78 K8s: runtimeclient.K8sContainerData{}, 79 }, 80 Pid: c.Pid(), 81 // TODO: Is it worth to compare the cgroups path and mounts? 82 }, 83 ) 84 } 85 86 // Initialize runtime client 87 config := &containerutilsTypes.RuntimeConfig{ 88 Name: runtime, 89 } 90 rc, err := containerutils.NewContainerRuntimeClient(config) 91 t.Cleanup(func() { 92 if rc != nil { 93 rc.Close() 94 } 95 }) 96 require.Nil(t, err) 97 require.NotNil(t, rc) 98 99 // Test runtime client methods 100 t.Run("GetContainers", func(t *testing.T) { 101 t.Parallel() 102 103 containers, err := rc.GetContainers() 104 require.Nil(t, err) 105 require.NotNil(t, containers) 106 107 for _, eData := range expectedData { 108 found := false 109 for _, cData := range containers { 110 // ContainerImageDigest may vary among versions, so we do not check it for now 111 cData.Runtime.BasicRuntimeMetadata.ContainerImageDigest = "" 112 if cmp.Equal(*cData, eData.ContainerData) { 113 found = true 114 break 115 } 116 } 117 require.True(t, found, "couldn't find container:\n%s\nin:\n%s", 118 spew.Sdump(eData.ContainerData), spew.Sdump(containers)) 119 } 120 }) 121 122 t.Run("GetContainer", func(t *testing.T) { 123 t.Parallel() 124 125 for _, eData := range expectedData { 126 cData, err := rc.GetContainer(eData.Runtime.ContainerID) 127 // ContainerImageDigest may vary among versions, so we do not check it for now 128 cData.Runtime.BasicRuntimeMetadata.ContainerImageDigest = "" 129 require.Nil(t, err) 130 require.NotNil(t, cData) 131 require.True(t, cmp.Equal(*cData, eData.ContainerData), 132 "unexpected container data:\n%s", cmp.Diff(*cData, eData.ContainerData)) 133 } 134 }) 135 136 t.Run("GetContainerDetails", func(t *testing.T) { 137 t.Parallel() 138 139 for _, eData := range expectedData { 140 cData, err := rc.GetContainerDetails(eData.Runtime.ContainerID) 141 // ContainerImageDigest may vary among versions, so we do not check it for now 142 cData.Runtime.BasicRuntimeMetadata.ContainerImageDigest = "" 143 require.Nil(t, err) 144 require.NotNil(t, cData) 145 146 // TODO: Is it worth to compare the cgroups path and mounts? 147 require.NotEmpty(t, cData.CgroupsPath) 148 cData.CgroupsPath = eData.CgroupsPath 149 cData.Mounts = eData.Mounts 150 151 require.True(t, cmp.Equal(cData, eData), 152 "unexpected container data:\n%s", cmp.Diff(cData, eData)) 153 } 154 }) 155 }) 156 } 157 } 158 159 // TestDeleteContainers is useful to delete containers from 160 // TestRuntimeClientInterface that were not properly deleted because of a bug. 161 // func TestDeleteContainers(t *testing.T) { 162 // t.Parallel() 163 // utilstest.RequireRoot(t) 164 165 // for _, runtime := range testutils.SupportedContainerRuntimes { 166 // t.Run(runtime.String(), func(t *testing.T) { 167 // runtime := runtime 168 // t.Parallel() 169 170 // // Delete test containers from previous runs 171 // for i := 0; i < numContainers; i++ { 172 // cn := fmt.Sprintf("%s-%s-%d", containerNamePrefix, runtime, i) 173 // c, err := testutils.NewContainer(runtime, cn, "sleep inf", testutils.WithForceDelete()) 174 // require.Nil(t, err) 175 // require.NotNil(t, c) 176 // c.Stop(t) 177 // } 178 // }) 179 // } 180 // }