| package systemd |
| |
| import ( |
| "os" |
| "reflect" |
| "testing" |
| |
| systemdDbus "github.com/coreos/go-systemd/v22/dbus" |
| "github.com/opencontainers/runc/libcontainer/cgroups" |
| "github.com/opencontainers/runc/libcontainer/configs" |
| ) |
| |
| func newManager(t *testing.T, config *configs.Cgroup) (m cgroups.Manager) { |
| t.Helper() |
| var err error |
| |
| if cgroups.IsCgroup2UnifiedMode() { |
| m, err = NewUnifiedManager(config, "") |
| } else { |
| m, err = NewLegacyManager(config, nil) |
| } |
| if err != nil { |
| t.Fatal(err) |
| } |
| t.Cleanup(func() { _ = m.Destroy() }) |
| |
| return m |
| } |
| |
| func TestSystemdVersion(t *testing.T) { |
| systemdVersionTests := []struct { |
| verStr string |
| expectedVer int |
| expectErr bool |
| }{ |
| {`"219"`, 219, false}, |
| {`"v245.4-1.fc32"`, 245, false}, |
| {`"241-1"`, 241, false}, |
| {`"v241-1"`, 241, false}, |
| {`333.45"`, 333, false}, |
| {`v321-0`, 321, false}, |
| {"NaN", -1, true}, |
| {"", -1, true}, |
| {"v", -1, true}, |
| } |
| for _, sdTest := range systemdVersionTests { |
| ver, err := systemdVersionAtoi(sdTest.verStr) |
| if !sdTest.expectErr && err != nil { |
| t.Errorf("systemdVersionAtoi(%s); want nil; got %v", sdTest.verStr, err) |
| } |
| if sdTest.expectErr && err == nil { |
| t.Errorf("systemdVersionAtoi(%s); wanted failure; got nil", sdTest.verStr) |
| } |
| if ver != sdTest.expectedVer { |
| t.Errorf("systemdVersionAtoi(%s); want %d; got %d", sdTest.verStr, sdTest.expectedVer, ver) |
| } |
| } |
| } |
| |
| func TestValidUnitTypes(t *testing.T) { |
| testCases := []struct { |
| unitName string |
| expectedUnitType string |
| }{ |
| {"system.slice", "Slice"}, |
| {"kubepods.slice", "Slice"}, |
| {"testing-container:ab.scope", "Scope"}, |
| } |
| for _, sdTest := range testCases { |
| unitType := getUnitType(sdTest.unitName) |
| if unitType != sdTest.expectedUnitType { |
| t.Errorf("getUnitType(%s); want %q; got %q", sdTest.unitName, sdTest.expectedUnitType, unitType) |
| } |
| } |
| } |
| |
| func TestUnitExistsIgnored(t *testing.T) { |
| if !IsRunningSystemd() { |
| t.Skip("Test requires systemd.") |
| } |
| if os.Geteuid() != 0 { |
| t.Skip("Test requires root.") |
| } |
| |
| podConfig := &configs.Cgroup{ |
| Parent: "system.slice", |
| Name: "system-runc_test_exists.slice", |
| Resources: &configs.Resources{}, |
| } |
| // Create "pods" cgroup (a systemd slice to hold containers). |
| pm := newManager(t, podConfig) |
| |
| // create twice to make sure "UnitExists" error is ignored. |
| for i := 0; i < 2; i++ { |
| if err := pm.Apply(-1); err != nil { |
| t.Fatal(err) |
| } |
| } |
| } |
| |
| func TestUnifiedResToSystemdProps(t *testing.T) { |
| if !IsRunningSystemd() { |
| t.Skip("Test requires systemd.") |
| } |
| if !cgroups.IsCgroup2UnifiedMode() { |
| t.Skip("cgroup v2 is required") |
| } |
| |
| cm := newDbusConnManager(os.Geteuid() != 0) |
| |
| testCases := []struct { |
| name string |
| minVer int |
| res map[string]string |
| expError bool |
| expProps []systemdDbus.Property |
| }{ |
| { |
| name: "empty map", |
| res: map[string]string{}, |
| }, |
| { |
| name: "only cpu.idle=1", |
| minVer: cpuIdleSupportedVersion, |
| res: map[string]string{ |
| "cpu.idle": "1", |
| }, |
| expProps: []systemdDbus.Property{ |
| newProp("CPUWeight", uint64(0)), |
| }, |
| }, |
| { |
| name: "only cpu.idle=0", |
| minVer: cpuIdleSupportedVersion, |
| res: map[string]string{ |
| "cpu.idle": "0", |
| }, |
| }, |
| { |
| name: "cpu.idle=1 and cpu.weight=1000", |
| minVer: cpuIdleSupportedVersion, |
| res: map[string]string{ |
| "cpu.idle": "1", |
| "cpu.weight": "1000", |
| }, |
| expProps: []systemdDbus.Property{ |
| newProp("CPUWeight", uint64(0)), |
| }, |
| }, |
| { |
| name: "cpu.idle=0 and cpu.weight=1000", |
| minVer: cpuIdleSupportedVersion, |
| res: map[string]string{ |
| "cpu.idle": "0", |
| "cpu.weight": "1000", |
| }, |
| expProps: []systemdDbus.Property{ |
| newProp("CPUWeight", uint64(1000)), |
| }, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| tc := tc |
| t.Run(tc.name, func(t *testing.T) { |
| if tc.minVer != 0 && systemdVersion(cm) < tc.minVer { |
| t.Skipf("requires systemd >= %d", tc.minVer) |
| } |
| props, err := unifiedResToSystemdProps(cm, tc.res) |
| if err != nil && !tc.expError { |
| t.Fatalf("expected no error, got: %v", err) |
| } |
| if err == nil && tc.expError { |
| t.Fatal("expected error, got nil") |
| } |
| if !reflect.DeepEqual(tc.expProps, props) { |
| t.Errorf("wrong properties (exp %+v, got %+v)", tc.expProps, props) |
| } |
| }) |
| } |
| } |