From 091d694c00dda4e3f5aa61aade4d319875ff46db Mon Sep 17 00:00:00 2001 From: Xuewei Niu Date: Tue, 28 Jul 2026 05:07:37 -0500 Subject: [PATCH] tests: Make cgroup tests hierarchy-aware Resolve cgroup filesystem paths according to the active hierarchy and assert systemd's expected cgroup v1 limitations. This lets the existing manager and D-Bus tests run in both guest modes without changing library behavior. Signed-off-by: Xuewei Niu --- src/manager/fs.rs | 32 ++++++++++++++++++-------------- src/manager/systemd.rs | 16 +++++++++++++++- src/systemd/dbus/client.rs | 28 ++++++++++++++++++++++------ 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/src/manager/fs.rs b/src/manager/fs.rs index f865594..30609ee 100644 --- a/src/manager/fs.rs +++ b/src/manager/fs.rs @@ -1167,6 +1167,19 @@ mod tests { FsManager::new(TEST_BASE).unwrap() } + fn managed_cgroup_path(manager: &FsManager, subsystem: Option<&str>) -> String { + if manager.v2() { + return join_path(UNIFIED_MOUNTPOINT, &manager.base); + } + + let subsystem = subsystem.expect("cgroup v1 requires a subsystem"); + let mountpoint = manager + .mounts + .get(subsystem) + .expect("cgroup v1 subsystem mountpoint should exist"); + join_path(mountpoint, &manager.base) + } + fn run_set_resources_failed(resources: LinuxResources) { let mut child = spawn_sleep_inf(); let mut manager = new_manager(); @@ -1218,14 +1231,8 @@ mod tests { let mut manager = new_manager(); for (subsystem, mountpoint) in manager.mounts() { - let subsys = if subsystem.is_empty() { - assert!(manager.v2()); - None - } else { - Some(subsystem.as_str()) - }; - let path = manager.cgroup_path(subsys).unwrap(); - let path = join_path(mountpoint, &path); + let path = manager.paths().get(subsystem).unwrap(); + let path = join_path(mountpoint, path.trim_start_matches('/')); assert!(Path::new(&path).exists(), "Cgroup {} does not exist", path); } @@ -1237,11 +1244,7 @@ mod tests { let mut manager = new_manager(); manager.create_cgroups().unwrap(); - let cgroup_path = if manager.v2() { - manager.cgroup_path(None).unwrap() - } else { - manager.cgroup_path(Some("memory")).unwrap() - }; + let cgroup_path = managed_cgroup_path(&manager, (!manager.v2()).then_some("memory")); assert!( Path::new(&cgroup_path).exists(), "Cgroup should exist before destroy" @@ -1380,7 +1383,6 @@ mod tests { #[test] fn test_enable_cpus_topdown() { - let cpuset_cpus_path = format!("/sys/fs/cgroup/{}/cpuset.cpus", TEST_BASE); let online_cpus = fs::read_to_string("/sys/devices/system/cpu/online").unwrap(); let cpus = parse_cpu_list(&online_cpus); @@ -1398,6 +1400,8 @@ mod tests { .build() .unwrap(); run_set_resources(linux_resources, |manager| { + let managed_path = managed_cgroup_path(manager, (!manager.v2()).then_some("cpuset")); + let cpuset_cpus_path = join_path(&managed_path, "cpuset.cpus"); let cpus1 = fs::read_to_string(&cpuset_cpus_path).unwrap(); let cpus1 = parse_cpu_list(&cpus1); assert_eq!(cpus[..1], cpus1); diff --git a/src/manager/systemd.rs b/src/manager/systemd.rs index 6cb160d..3cf1a1b 100644 --- a/src/manager/systemd.rs +++ b/src/manager/systemd.rs @@ -370,6 +370,20 @@ mod tests { SystemdManager::new(&format!("{}:{}:{}", slice, scope_prefix, name)).unwrap() } + fn managed_cgroup_path(manager: &SystemdManager<'_>, subsystem: Option<&str>) -> String { + if manager.v2() { + return manager.cgroup_path(None).unwrap(); + } + + let subsystem = subsystem.expect("cgroup v1 requires a subsystem"); + let mountpoint = manager + .mounts() + .get(subsystem) + .expect("cgroup v1 subsystem mountpoint should exist"); + let slice_base = expand_slice(manager.slice()).unwrap(); + join_path(mountpoint, &join_path(&slice_base, manager.unit())) + } + fn run_set_resources_failed(resources: LinuxResources) { let mut child = spawn_sleep_inf(); let mut manager = new_systemd_manager(); @@ -431,7 +445,7 @@ mod tests { let mut manager = SystemdManager::new(&format!("{}:{}:{}", slice, scope_prefix, name)).unwrap(); - let cgroup_path = manager.cgroup_path(Some("memory")).unwrap(); + let cgroup_path = managed_cgroup_path(&manager, (!manager.v2()).then_some("memory")); // Before starting the unit, no cgroup should exist. assert!(!Path::new(&cgroup_path).exists()); diff --git a/src/systemd/dbus/client.rs b/src/systemd/dbus/client.rs index b5732b9..6ac62ec 100644 --- a/src/systemd/dbus/client.rs +++ b/src/systemd/dbus/client.rs @@ -452,12 +452,23 @@ pub mod tests { fn test_freeze_and_thaw() { skip_if_no_systemd!(); + let v2 = hierarchies::is_cgroup2_unified_mode(); let unit = test_unit(); let mut child = spawn_yes(); let cgroup = start_default_cgroup(CgroupPid::from(child.id() as u64), &unit); // Freeze the unit - cgroup.freeze().unwrap(); + let freeze_result = cgroup.freeze(); + if !v2 { + assert!( + freeze_result.is_err(), + "systemd should reject FreezeUnit on cgroup v1" + ); + stop_cgroup(&cgroup); + child.wait().unwrap(); + return; + } + freeze_result.unwrap(); let pid = child.id() as u64; @@ -507,6 +518,7 @@ pub mod tests { fn test_add_process() { skip_if_no_systemd!(); + let v2 = hierarchies::is_cgroup2_unified_mode(); let unit = test_unit(); let mut child = spawn_sleep_inf(); let cgroup = start_default_cgroup(CgroupPid::from(child.id() as u64), &unit); @@ -515,11 +527,15 @@ pub mod tests { let pid1 = CgroupPid::from(child1.id() as u64); cgroup.add_process(pid1, "/").unwrap(); - let cgroup_procs_path = format!( - "/sys/fs/cgroup/{}/{}/cgroup.procs", - expand_slice(TEST_SLICE).unwrap(), - unit - ); + let cgroup_root = if v2 { + Path::new("/sys/fs/cgroup") + } else { + Path::new("/sys/fs/cgroup/memory") + }; + let cgroup_procs_path = cgroup_root + .join(expand_slice(TEST_SLICE).unwrap()) + .join(&unit) + .join("cgroup.procs"); for i in 0..5 { let content = fs::read_to_string(&cgroup_procs_path); if let Ok(content) = content {