1
16
17 package cgroups
18
19 import (
20 "fmt"
21 "os"
22 "path/filepath"
23 "strconv"
24 "testing"
25
26 specs "github.com/opencontainers/runtime-spec/specs-go"
27 )
28
29
30
31 func TestCreate(t *testing.T) {
32 mock, err := newMock(t)
33 if err != nil {
34 t.Fatal(err)
35 }
36 defer mock.delete()
37 control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
38 if err != nil {
39 t.Error(err)
40 return
41 }
42 if control == nil {
43 t.Error("control is nil")
44 return
45 }
46 for _, s := range Subsystems() {
47 if _, err := os.Stat(filepath.Join(mock.root, string(s), "test")); err != nil {
48 if os.IsNotExist(err) {
49 t.Errorf("group %s was not created", s)
50 return
51 }
52 t.Errorf("group %s was not created correctly %s", s, err)
53 return
54 }
55 }
56 }
57
58 func TestStat(t *testing.T) {
59 mock, err := newMock(t)
60 if err != nil {
61 t.Fatal(err)
62 }
63 defer mock.delete()
64 control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
65 if err != nil {
66 t.Error(err)
67 return
68 }
69 s, err := control.Stat(IgnoreNotExist)
70 if err != nil {
71 t.Error(err)
72 return
73 }
74 if s == nil {
75 t.Error("stat result is nil")
76 return
77 }
78 }
79
80 func TestAdd(t *testing.T) {
81 mock, err := newMock(t)
82 if err != nil {
83 t.Fatal(err)
84 }
85 defer mock.delete()
86 control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
87 if err != nil {
88 t.Error(err)
89 return
90 }
91 if err := control.Add(Process{Pid: 1234}); err != nil {
92 t.Error(err)
93 return
94 }
95 for _, s := range Subsystems() {
96 if err := checkPid(mock, filepath.Join(string(s), "test"), 1234); err != nil {
97 t.Error(err)
98 return
99 }
100 }
101 }
102
103 func TestAddFilteredSubsystems(t *testing.T) {
104 mock, err := newMock(t)
105 if err != nil {
106 t.Fatal(err)
107 }
108 defer mock.delete()
109 control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
110 if err != nil {
111 t.Error(err)
112 return
113 }
114
115 filteredSubsystems := []Name{"memory", "cpu"}
116 if err := control.Add(Process{Pid: 1234}, filteredSubsystems...); err != nil {
117 t.Error(err)
118 return
119 }
120
121 for _, s := range filteredSubsystems {
122 if err := checkPid(mock, filepath.Join(string(s), "test"), 1234); err != nil {
123 t.Error(err)
124 return
125 }
126 }
127
128 if err := checkPid(mock, filepath.Join("devices", "test"), 1234); err == nil {
129 t.Error("Pid should not be added to the devices subsystem")
130 return
131 }
132
133 bogusSubsystems := append(filteredSubsystems, "bogus")
134 if err := control.Add(Process{Pid: 5678}, bogusSubsystems...); err != nil {
135 t.Error(err)
136 return
137 }
138
139 for _, s := range filteredSubsystems {
140 if err := checkPid(mock, filepath.Join(string(s), "test"), 5678); err != nil {
141 t.Error(err)
142 return
143 }
144 }
145
146 nilSubsystems := []Name{}
147 if err := control.Add(Process{Pid: 9012}, nilSubsystems...); err != nil {
148 t.Error(err)
149 return
150 }
151
152 for _, s := range Subsystems() {
153 if err := checkPid(mock, filepath.Join(string(s), "test"), 9012); err != nil {
154 t.Error(err)
155 return
156 }
157 }
158 }
159
160 func TestAddTask(t *testing.T) {
161 mock, err := newMock(t)
162 if err != nil {
163 t.Fatal(err)
164 }
165 defer mock.delete()
166 control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
167 if err != nil {
168 t.Error(err)
169 return
170 }
171 if err := control.AddTask(Process{Pid: 1234}); err != nil {
172 t.Error(err)
173 return
174 }
175 for _, s := range Subsystems() {
176 if err := checkTaskid(mock, filepath.Join(string(s), "test"), 1234); err != nil {
177 t.Error(err)
178 return
179 }
180 }
181 }
182
183 func TestAddTaskFilteredSubsystems(t *testing.T) {
184 mock, err := newMock(t)
185 if err != nil {
186 t.Fatal(err)
187 }
188 defer mock.delete()
189 control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
190 if err != nil {
191 t.Error(err)
192 return
193 }
194 filteredSubsystems := []Name{"memory", "cpu"}
195 if err := control.AddTask(Process{Pid: 1234}, filteredSubsystems...); err != nil {
196 t.Error(err)
197 return
198 }
199 for _, s := range filteredSubsystems {
200 if err := checkTaskid(mock, filepath.Join(string(s), "test"), 1234); err != nil {
201 t.Error(err)
202 return
203 }
204 }
205
206 if err := checkTaskid(mock, filepath.Join("devices", "test"), 1234); err == nil {
207 t.Error("Task should not be added to the devices subsystem")
208 return
209 }
210
211 bogusSubsystems := append(filteredSubsystems, "bogus")
212 if err := control.AddTask(Process{Pid: 5678}, bogusSubsystems...); err != nil {
213 t.Error(err)
214 return
215 }
216
217 for _, s := range filteredSubsystems {
218 if err := checkTaskid(mock, filepath.Join(string(s), "test"), 5678); err != nil {
219 t.Error(err)
220 return
221 }
222 }
223 }
224
225 func TestListPids(t *testing.T) {
226 mock, err := newMock(t)
227 if err != nil {
228 t.Fatal(err)
229 }
230 defer mock.delete()
231 control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
232 if err != nil {
233 t.Error(err)
234 return
235 }
236 if err := control.Add(Process{Pid: 1234}); err != nil {
237 t.Error(err)
238 return
239 }
240 for _, s := range Subsystems() {
241 if err := checkPid(mock, filepath.Join(string(s), "test"), 1234); err != nil {
242 t.Error(err)
243 return
244 }
245 }
246 procs, err := control.Processes(Freezer, false)
247 if err != nil {
248 t.Error(err)
249 return
250 }
251 if l := len(procs); l != 1 {
252 t.Errorf("should have one process but received %d", l)
253 return
254 }
255 if procs[0].Pid != 1234 {
256 t.Errorf("expected pid %d but received %d", 1234, procs[0].Pid)
257 }
258 }
259
260 func TestListTasksPids(t *testing.T) {
261 mock, err := newMock(t)
262 if err != nil {
263 t.Fatal(err)
264 }
265 defer mock.delete()
266 control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
267 if err != nil {
268 t.Error(err)
269 return
270 }
271 if err := control.AddTask(Process{Pid: 1234}); err != nil {
272 t.Error(err)
273 return
274 }
275 for _, s := range Subsystems() {
276 if err := checkTaskid(mock, filepath.Join(string(s), "test"), 1234); err != nil {
277 t.Error(err)
278 return
279 }
280 }
281 tasks, err := control.Tasks(Freezer, false)
282 if err != nil {
283 t.Error(err)
284 return
285 }
286 if l := len(tasks); l != 1 {
287 t.Errorf("should have one task but received %d", l)
288 return
289 }
290 if tasks[0].Pid != 1234 {
291 t.Errorf("expected task pid %d but received %d", 1234, tasks[0].Pid)
292 }
293 }
294
295 func readValue(mock *mockCgroup, path string) (string, error) {
296 data, err := os.ReadFile(filepath.Join(mock.root, path))
297 if err != nil {
298 return "", err
299 }
300 return string(data), nil
301 }
302
303 func checkPid(mock *mockCgroup, path string, expected int) error {
304 data, err := readValue(mock, filepath.Join(path, cgroupProcs))
305 if err != nil {
306 return err
307 }
308 v, err := strconv.Atoi(data)
309 if err != nil {
310 return err
311 }
312 if v != expected {
313 return fmt.Errorf("expected pid %d but received %d", expected, v)
314 }
315 return nil
316 }
317
318 func checkTaskid(mock *mockCgroup, path string, expected int) error {
319 data, err := readValue(mock, filepath.Join(path, cgroupTasks))
320 if err != nil {
321 return err
322 }
323 v, err := strconv.Atoi(data)
324 if err != nil {
325 return err
326 }
327 if v != expected {
328 return fmt.Errorf("expected task id %d but received %d", expected, v)
329 }
330 return nil
331 }
332
333 func mockNewNotInRdma(subsystems []Subsystem, path Path, resources *specs.LinuxResources) (Cgroup, error) {
334 for _, s := range subsystems {
335 if s.Name() != Rdma {
336 if err := initializeSubsystem(s, path, resources); err != nil {
337 return nil, err
338 }
339 }
340 }
341 return &cgroup{
342 path: path,
343 subsystems: subsystems,
344 }, nil
345 }
346
347 func TestLoad(t *testing.T) {
348 mock, err := newMock(t)
349 if err != nil {
350 t.Fatal(err)
351 }
352 defer mock.delete()
353 control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
354 if err != nil {
355 t.Error(err)
356 return
357 }
358 if control, err = Load(mock.hierarchy, StaticPath("test")); err != nil {
359 t.Error(err)
360 return
361 }
362 if control == nil {
363 t.Error("control is nil")
364 return
365 }
366 }
367
368 func TestLoadWithMissingSubsystems(t *testing.T) {
369 mock, err := newMock(t)
370 if err != nil {
371 t.Fatal(err)
372 }
373 defer mock.delete()
374 subsystems, err := mock.hierarchy()
375 if err != nil {
376 t.Error(err)
377 return
378 }
379 control, err := mockNewNotInRdma(subsystems, StaticPath("test"), &specs.LinuxResources{})
380 if err != nil {
381 t.Error(err)
382 return
383 }
384 if control == nil {
385 t.Error("control is nil")
386 return
387 }
388 if control, err = Load(mock.hierarchy, StaticPath("test")); err != nil {
389 t.Error(err)
390 return
391 }
392 if control == nil {
393 t.Error("control is nil")
394 return
395 }
396 if len(control.Subsystems()) != len(subsystems)-1 {
397 t.Error("wrong number of active subsystems")
398 return
399 }
400 }
401
402 func TestDelete(t *testing.T) {
403 mock, err := newMock(t)
404 if err != nil {
405 t.Fatal(err)
406 }
407 defer mock.delete()
408 control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
409 if err != nil {
410 t.Error(err)
411 return
412 }
413 if err := control.Delete(); err != nil {
414 t.Error(err)
415 }
416 }
417
418 func TestCreateSubCgroup(t *testing.T) {
419 mock, err := newMock(t)
420 if err != nil {
421 t.Fatal(err)
422 }
423 defer mock.delete()
424 control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
425 if err != nil {
426 t.Error(err)
427 return
428 }
429 sub, err := control.New("child", &specs.LinuxResources{})
430 if err != nil {
431 t.Error(err)
432 return
433 }
434 if err := sub.Add(Process{Pid: 1234}); err != nil {
435 t.Error(err)
436 return
437 }
438 for _, s := range Subsystems() {
439 if err := checkPid(mock, filepath.Join(string(s), "test", "child"), 1234); err != nil {
440 t.Error(err)
441 return
442 }
443 }
444 if err := sub.AddTask(Process{Pid: 5678}); err != nil {
445 t.Error(err)
446 return
447 }
448 for _, s := range Subsystems() {
449 if err := checkTaskid(mock, filepath.Join(string(s), "test", "child"), 5678); err != nil {
450 t.Error(err)
451 return
452 }
453 }
454 }
455
456 func TestFreezeThaw(t *testing.T) {
457 mock, err := newMock(t)
458 if err != nil {
459 t.Fatal(err)
460 }
461 defer mock.delete()
462 control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
463 if err != nil {
464 t.Error(err)
465 return
466 }
467 if err := control.Freeze(); err != nil {
468 t.Error(err)
469 return
470 }
471 if state := control.State(); state != Frozen {
472 t.Errorf("expected %q but received %q", Frozen, state)
473 return
474 }
475 if err := control.Thaw(); err != nil {
476 t.Error(err)
477 return
478 }
479 if state := control.State(); state != Thawed {
480 t.Errorf("expected %q but received %q", Thawed, state)
481 return
482 }
483 }
484
485 func TestSubsystems(t *testing.T) {
486 mock, err := newMock(t)
487 if err != nil {
488 t.Fatal(err)
489 }
490 defer mock.delete()
491 control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
492 if err != nil {
493 t.Error(err)
494 return
495 }
496 cache := make(map[Name]struct{})
497 for _, s := range control.Subsystems() {
498 cache[s.Name()] = struct{}{}
499 }
500 for _, s := range Subsystems() {
501 if _, ok := cache[s]; !ok {
502 t.Errorf("expected subsystem %q but not found", s)
503 }
504 }
505 }
506
507 func TestCpusetParent(t *testing.T) {
508 const expected = "0-3"
509 mock, err := newMock(t)
510 if err != nil {
511 t.Fatal(err)
512 }
513 defer mock.delete()
514 control, err := New(mock.hierarchy, StaticPath("/parent/child"), &specs.LinuxResources{})
515 if err != nil {
516 t.Error(err)
517 return
518 }
519 defer control.Delete()
520 for _, file := range []string{
521 "parent/cpuset.cpus",
522 "parent/cpuset.mems",
523 "parent/child/cpuset.cpus",
524 "parent/child/cpuset.mems",
525 } {
526 v, err := readValue(mock, filepath.Join(string(Cpuset), file))
527 if err != nil {
528 t.Error(err)
529 return
530 }
531 if v != expected {
532 t.Errorf("expected %q for %s but received %q", expected, file, v)
533 }
534 }
535 }
536
View as plain text