cmd/gitbay-runner/cgroup_test.go
92 lines · 2683 bytes
1package main
2
3import (
4 "os"
5 "path/filepath"
6 "testing"
7)
8
9// Podman's --memory and --cpus never applied under rootless cgroupfs: the
10// container ran in the service's own cgroup and crun could not create a
11// child (#188). The runner now owns the build cgroups itself and places
12// podman inside one, so the limits are written by the runner in cgroup
13// v2's own units.
14func TestMemoryBytes(t *testing.T) {
15 cases := map[string]int64{
16 "64m": 64 << 20,
17 "6g": 6 << 30,
18 "512k": 512 << 10,
19 "100b": 100,
20 "4096": 4096,
21 "1G": 1 << 30,
22 }
23 for in, want := range cases {
24 got, err := memoryBytes(in)
25 if err != nil || got != want {
26 t.Errorf("memoryBytes(%q) = %d, %v; want %d", in, got, err, want)
27 }
28 }
29 for _, bad := range []string{"", "lots", "6gb", "-1g", "1.5g"} {
30 if _, err := memoryBytes(bad); err == nil {
31 t.Errorf("memoryBytes(%q) accepted", bad)
32 }
33 }
34}
35
36func TestCPUMax(t *testing.T) {
37 cases := map[string]string{
38 "3": "300000 100000",
39 "1": "100000 100000",
40 "1.5": "150000 100000",
41 "0.25": "25000 100000",
42 }
43 for in, want := range cases {
44 got, err := cpuMax(in)
45 if err != nil || got != want {
46 t.Errorf("cpuMax(%q) = %q, %v; want %q", in, got, err, want)
47 }
48 }
49 for _, bad := range []string{"", "0", "-1", "two"} {
50 if _, err := cpuMax(bad); err == nil {
51 t.Errorf("cpuMax(%q) accepted", bad)
52 }
53 }
54}
55
56// /proc/self/cgroup on cgroup v2 is one line, "0::<path>".
57func TestOwnCgroupPath(t *testing.T) {
58 got, err := ownCgroupPath("0::/system.slice/gitbay-runner.service\n")
59 if err != nil || got != "/system.slice/gitbay-runner.service" {
60 t.Fatalf("ownCgroupPath = %q, %v", got, err)
61 }
62 // A v1 hierarchy, or anything else, is not something the runner
63 // manages.
64 if _, err := ownCgroupPath("12:memory:/user.slice\n0::/init.scope\n"); err == nil {
65 t.Fatal("v1 hierarchy accepted")
66 }
67}
68
69// Limits land as cgroup v2 interface files in the build's directory;
70// an unset limit writes nothing, which means "inherit", not "max".
71func TestWriteLimits(t *testing.T) {
72 dir := t.TempDir()
73 if err := writeLimits(dir, "6g", "3"); err != nil {
74 t.Fatal(err)
75 }
76 if got, _ := os.ReadFile(filepath.Join(dir, "memory.max")); string(got) != "6442450944" {
77 t.Errorf("memory.max = %q", got)
78 }
79 if got, _ := os.ReadFile(filepath.Join(dir, "cpu.max")); string(got) != "300000 100000" {
80 t.Errorf("cpu.max = %q", got)
81 }
82 empty := t.TempDir()
83 if err := writeLimits(empty, "", ""); err != nil {
84 t.Fatal(err)
85 }
86 if entries, _ := os.ReadDir(empty); len(entries) != 0 {
87 t.Errorf("unset limits wrote %v", entries)
88 }
89 if err := writeLimits(t.TempDir(), "lots", ""); err == nil {
90 t.Error("a bad memory limit was accepted")
91 }
92}