1// +build functional
2
3package cri_containerd
4
5import (
6	"context"
7	"testing"
8
9	runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
10)
11
12func runContainerAndQueryStats(t *testing.T, client runtime.RuntimeServiceClient, ctx context.Context, request *runtime.CreateContainerRequest) {
13	containerID := createContainer(t, client, ctx, request)
14	defer removeContainer(t, client, ctx, containerID)
15	startContainer(t, client, ctx, containerID)
16	defer stopContainer(t, client, ctx, containerID)
17
18	statsRequest := &runtime.ContainerStatsRequest{
19		ContainerId: containerID,
20	}
21
22	stats, err := client.ContainerStats(ctx, statsRequest)
23	if err != nil {
24		t.Fatal(err)
25	}
26
27	stat := stats.Stats
28	verifyStatsContent(t, stat)
29}
30
31func runContainerAndQueryListStats(t *testing.T, client runtime.RuntimeServiceClient, ctx context.Context, request *runtime.CreateContainerRequest) {
32	containerID := createContainer(t, client, ctx, request)
33	defer removeContainer(t, client, ctx, containerID)
34	startContainer(t, client, ctx, containerID)
35	defer stopContainer(t, client, ctx, containerID)
36
37	statsRequest := &runtime.ListContainerStatsRequest{
38		Filter: &runtime.ContainerStatsFilter{
39			Id: containerID,
40		},
41	}
42
43	stats, err := client.ListContainerStats(ctx, statsRequest)
44	if err != nil {
45		t.Fatal(err)
46	}
47
48	if len(stats.Stats) != 1 {
49		t.Fatalf("expected 1 stats result but got %d", len(stats.Stats))
50	}
51	stat := stats.Stats[0]
52	verifyStatsContent(t, stat)
53}
54
55func verifyStatsContent(t *testing.T, stat *runtime.ContainerStats) {
56	if stat == nil {
57		t.Fatal("expected stat to be non nil")
58	}
59	if stat.Cpu.Timestamp == 0 {
60		t.Fatalf("expected cpu stat timestamp != 0 but got %d", stat.Cpu.Timestamp)
61	}
62	if stat.Cpu.UsageCoreNanoSeconds.Value == 0 {
63		t.Fatalf("expected cpu usage != 0 but got %d", stat.Cpu.UsageCoreNanoSeconds.Value)
64	}
65	if stat.Memory.Timestamp == 0 {
66		t.Fatalf("expected memory stat timestamp != 0 but got %d", stat.Memory.Timestamp)
67	}
68	if stat.Memory.WorkingSetBytes.Value == 0 {
69		t.Fatalf("expected memory usage != 0 but got %d", stat.Memory.WorkingSetBytes.Value)
70	}
71}
72
73func Test_SandboxStats_Single_LCOW(t *testing.T) {
74	pullRequiredLcowImages(t, []string{imageLcowK8sPause})
75
76	request := &runtime.RunPodSandboxRequest{
77		Config: &runtime.PodSandboxConfig{
78			Metadata: &runtime.PodSandboxMetadata{
79				Name:      t.Name(),
80				Namespace: testNamespace,
81			},
82		},
83		RuntimeHandler: lcowRuntimeHandler,
84	}
85
86	client := newTestRuntimeClient(t)
87	ctx, cancel := context.WithCancel(context.Background())
88	defer cancel()
89
90	podID := runPodSandbox(t, client, ctx, request)
91	defer removePodSandbox(t, client, ctx, podID)
92	defer stopPodSandbox(t, client, ctx, podID)
93
94	statsRequest := &runtime.ContainerStatsRequest{
95		ContainerId: podID,
96	}
97
98	stats, err := client.ContainerStats(ctx, statsRequest)
99	if err != nil {
100		t.Fatal(err)
101	}
102
103	stat := stats.Stats
104	verifyStatsContent(t, stat)
105}
106
107func Test_SandboxStats_List_ContainerID_LCOW(t *testing.T) {
108	pullRequiredLcowImages(t, []string{imageLcowK8sPause})
109
110	request := &runtime.RunPodSandboxRequest{
111		Config: &runtime.PodSandboxConfig{
112			Metadata: &runtime.PodSandboxMetadata{
113				Name:      t.Name(),
114				Namespace: testNamespace,
115			},
116		},
117		RuntimeHandler: lcowRuntimeHandler,
118	}
119
120	client := newTestRuntimeClient(t)
121	ctx, cancel := context.WithCancel(context.Background())
122	defer cancel()
123
124	podID := runPodSandbox(t, client, ctx, request)
125	defer removePodSandbox(t, client, ctx, podID)
126	defer stopPodSandbox(t, client, ctx, podID)
127
128	statsRequest := &runtime.ListContainerStatsRequest{
129		Filter: &runtime.ContainerStatsFilter{
130			Id: podID,
131		},
132	}
133
134	stats, err := client.ListContainerStats(ctx, statsRequest)
135	if err != nil {
136		t.Fatal(err)
137	}
138
139	if len(stats.Stats) != 1 {
140		t.Fatalf("expected 1 stats result but got %d", len(stats.Stats))
141	}
142	stat := stats.Stats[0]
143	verifyStatsContent(t, stat)
144}
145
146func Test_SandboxStats_List_PodID_LCOW(t *testing.T) {
147	pullRequiredLcowImages(t, []string{imageLcowK8sPause})
148
149	request := &runtime.RunPodSandboxRequest{
150		Config: &runtime.PodSandboxConfig{
151			Metadata: &runtime.PodSandboxMetadata{
152				Name:      t.Name(),
153				Namespace: testNamespace,
154			},
155		},
156		RuntimeHandler: lcowRuntimeHandler,
157	}
158
159	client := newTestRuntimeClient(t)
160	ctx, cancel := context.WithCancel(context.Background())
161	defer cancel()
162
163	podID := runPodSandbox(t, client, ctx, request)
164	defer removePodSandbox(t, client, ctx, podID)
165	defer stopPodSandbox(t, client, ctx, podID)
166
167	statsRequest := &runtime.ListContainerStatsRequest{
168		Filter: &runtime.ContainerStatsFilter{
169			PodSandboxId: podID,
170		},
171	}
172
173	stats, err := client.ListContainerStats(ctx, statsRequest)
174	if err != nil {
175		t.Fatal(err)
176	}
177
178	if len(stats.Stats) != 1 {
179		t.Fatalf("expected 1 stats result but got %d", len(stats.Stats))
180	}
181	stat := stats.Stats[0]
182	verifyStatsContent(t, stat)
183}
184
185func Test_ContainerStats_ContainerID(t *testing.T) {
186	type config struct {
187		name string
188
189		runtimeHandler string
190		sandboxImage   string
191		containerImage string
192		cmd            []string
193	}
194	tests := []config{
195		{
196			name:           "WCOW_Process",
197			runtimeHandler: wcowProcessRuntimeHandler,
198			sandboxImage:   imageWindowsNanoserver,
199			containerImage: imageWindowsNanoserver,
200			cmd:            []string{"cmd", "/c", "ping", "-t", "127.0.0.1"},
201		},
202		{
203			name:           "WCOW_Hypervisor",
204			runtimeHandler: wcowHypervisorRuntimeHandler,
205			sandboxImage:   imageWindowsNanoserver,
206			containerImage: imageWindowsNanoserver,
207			cmd:            []string{"cmd", "/c", "ping", "-t", "127.0.0.1"},
208		},
209		{
210			name:           "LCOW",
211			runtimeHandler: lcowRuntimeHandler,
212			sandboxImage:   imageLcowK8sPause,
213			containerImage: imageLcowAlpine,
214			cmd:            []string{"top"},
215		},
216	}
217
218	for _, test := range tests {
219		t.Run(test.name, func(t *testing.T) {
220			if test.runtimeHandler == lcowRuntimeHandler {
221				pullRequiredLcowImages(t, []string{test.sandboxImage, test.containerImage})
222			} else {
223				pullRequiredImages(t, []string{test.sandboxImage, test.containerImage})
224			}
225
226			podRequest := &runtime.RunPodSandboxRequest{
227				Config: &runtime.PodSandboxConfig{
228					Metadata: &runtime.PodSandboxMetadata{
229						Name:      t.Name(),
230						Uid:       "0",
231						Namespace: testNamespace,
232					},
233				},
234				RuntimeHandler: test.runtimeHandler,
235			}
236
237			client := newTestRuntimeClient(t)
238			ctx, cancel := context.WithCancel(context.Background())
239			defer cancel()
240
241			podID := runPodSandbox(t, client, ctx, podRequest)
242			defer removePodSandbox(t, client, ctx, podID)
243			defer stopPodSandbox(t, client, ctx, podID)
244
245			request := &runtime.CreateContainerRequest{
246				Config: &runtime.ContainerConfig{
247					Metadata: &runtime.ContainerMetadata{
248						Name: t.Name() + "-Container",
249					},
250					Image: &runtime.ImageSpec{
251						Image: test.containerImage,
252					},
253					Command: test.cmd,
254				},
255				PodSandboxId:  podID,
256				SandboxConfig: podRequest.Config,
257			}
258			runContainerAndQueryStats(t, client, ctx, request)
259		})
260	}
261
262}
263
264func Test_ContainerStats_List_ContainerID(t *testing.T) {
265	type config struct {
266		name string
267
268		runtimeHandler string
269		sandboxImage   string
270		containerImage string
271		cmd            []string
272	}
273	tests := []config{
274		{
275			name:           "WCOW_Process",
276			runtimeHandler: wcowProcessRuntimeHandler,
277			sandboxImage:   imageWindowsNanoserver,
278			containerImage: imageWindowsNanoserver,
279			cmd:            []string{"cmd", "/c", "ping", "-t", "127.0.0.1"},
280		},
281		{
282			name:           "WCOW_Hypervisor",
283			runtimeHandler: wcowHypervisorRuntimeHandler,
284			sandboxImage:   imageWindowsNanoserver,
285			containerImage: imageWindowsNanoserver,
286			cmd:            []string{"cmd", "/c", "ping", "-t", "127.0.0.1"},
287		},
288		{
289			name:           "LCOW",
290			runtimeHandler: lcowRuntimeHandler,
291			sandboxImage:   imageLcowK8sPause,
292			containerImage: imageLcowAlpine,
293			cmd:            []string{"top"},
294		},
295	}
296
297	for _, test := range tests {
298		t.Run(test.name, func(t *testing.T) {
299			if test.runtimeHandler == lcowRuntimeHandler {
300				pullRequiredLcowImages(t, []string{test.sandboxImage, test.containerImage})
301			} else {
302				pullRequiredImages(t, []string{test.sandboxImage, test.containerImage})
303			}
304
305			podRequest := &runtime.RunPodSandboxRequest{
306				Config: &runtime.PodSandboxConfig{
307					Metadata: &runtime.PodSandboxMetadata{
308						Name:      t.Name(),
309						Uid:       "0",
310						Namespace: testNamespace,
311					},
312				},
313				RuntimeHandler: test.runtimeHandler,
314			}
315
316			client := newTestRuntimeClient(t)
317			ctx, cancel := context.WithCancel(context.Background())
318			defer cancel()
319
320			podID := runPodSandbox(t, client, ctx, podRequest)
321			defer removePodSandbox(t, client, ctx, podID)
322			defer stopPodSandbox(t, client, ctx, podID)
323
324			request := &runtime.CreateContainerRequest{
325				Config: &runtime.ContainerConfig{
326					Metadata: &runtime.ContainerMetadata{
327						Name: t.Name() + "-Container",
328					},
329					Image: &runtime.ImageSpec{
330						Image: test.containerImage,
331					},
332					Command: test.cmd,
333				},
334				PodSandboxId:  podID,
335				SandboxConfig: podRequest.Config,
336			}
337			runContainerAndQueryListStats(t, client, ctx, request)
338		})
339	}
340}
341