mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-09-17 23:07:55 +00:00
agent: Move common unit tests about device
Move common unit tests about device to mod.rs Signed-off-by: ChengyuZhu6 <chengyu.zhu@intel.com>
This commit is contained in:
@@ -11,572 +11,7 @@ fn sl() -> slog::Logger {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::uevent::spawn_test_watcher;
|
||||
use oci::{
|
||||
Linux, LinuxBuilder, LinuxDeviceBuilder, LinuxDeviceCgroupBuilder, LinuxDeviceType,
|
||||
LinuxResources, LinuxResourcesBuilder, SpecBuilder,
|
||||
};
|
||||
use oci_spec::runtime as oci;
|
||||
use std::iter::FromIterator;
|
||||
use tempfile::tempdir;
|
||||
|
||||
const VM_ROOTFS: &str = "/";
|
||||
|
||||
#[test]
|
||||
fn test_update_device_cgroup() {
|
||||
let mut linux = Linux::default();
|
||||
linux.set_resources(Some(LinuxResources::default()));
|
||||
let mut spec = SpecBuilder::default().linux(linux).build().unwrap();
|
||||
|
||||
let dev_info = DeviceInfo::new(VM_ROOTFS, false).unwrap();
|
||||
insert_devices_cgroup_rule(&mut spec, &dev_info, false, "rw").unwrap();
|
||||
|
||||
let devices = spec
|
||||
.linux()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.resources()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.devices()
|
||||
.clone()
|
||||
.unwrap();
|
||||
assert_eq!(devices.len(), 1);
|
||||
|
||||
let meta = fs::metadata(VM_ROOTFS).unwrap();
|
||||
let rdev = meta.dev();
|
||||
let major = stat::major(rdev) as i64;
|
||||
let minor = stat::minor(rdev) as i64;
|
||||
|
||||
assert_eq!(devices[0].major(), Some(major));
|
||||
assert_eq!(devices[0].minor(), Some(minor));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_spec_devices() {
|
||||
let (major, minor) = (7, 2);
|
||||
let mut spec = Spec::default();
|
||||
|
||||
// vm_path empty
|
||||
let update = DeviceInfo::new("", true);
|
||||
assert!(update.is_err());
|
||||
|
||||
// linux is empty
|
||||
let container_path = "/dev/null";
|
||||
let vm_path = "/dev/null";
|
||||
let res = update_spec_devices(
|
||||
&mut spec,
|
||||
HashMap::from_iter(vec![(
|
||||
container_path,
|
||||
DeviceInfo::new(vm_path, true).unwrap().into(),
|
||||
)]),
|
||||
);
|
||||
assert!(res.is_err());
|
||||
|
||||
spec.set_linux(Some(Linux::default()));
|
||||
|
||||
// linux.devices doesn't contain the updated device
|
||||
let res = update_spec_devices(
|
||||
&mut spec,
|
||||
HashMap::from_iter(vec![(
|
||||
container_path,
|
||||
DeviceInfo::new(vm_path, true).unwrap().into(),
|
||||
)]),
|
||||
);
|
||||
assert!(res.is_err());
|
||||
|
||||
spec.linux_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.set_devices(Some(vec![LinuxDeviceBuilder::default()
|
||||
.path(PathBuf::from("/dev/null2"))
|
||||
.major(major)
|
||||
.minor(minor)
|
||||
.build()
|
||||
.unwrap()]));
|
||||
|
||||
// guest and host path are not the same
|
||||
let res = update_spec_devices(
|
||||
&mut spec,
|
||||
HashMap::from_iter(vec![(
|
||||
container_path,
|
||||
DeviceInfo::new(vm_path, true).unwrap().into(),
|
||||
)]),
|
||||
);
|
||||
assert!(
|
||||
res.is_err(),
|
||||
"container_path={:?} vm_path={:?} spec={:?}",
|
||||
container_path,
|
||||
vm_path,
|
||||
spec
|
||||
);
|
||||
|
||||
spec.linux_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.devices_mut()
|
||||
.as_mut()
|
||||
.unwrap()[0]
|
||||
.set_path(PathBuf::from(container_path));
|
||||
|
||||
// spec.linux.resources is empty
|
||||
let res = update_spec_devices(
|
||||
&mut spec,
|
||||
HashMap::from_iter(vec![(
|
||||
container_path,
|
||||
DeviceInfo::new(vm_path, true).unwrap().into(),
|
||||
)]),
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
|
||||
// update both devices and cgroup lists
|
||||
spec.linux_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.set_devices(Some(vec![LinuxDeviceBuilder::default()
|
||||
.path(PathBuf::from(container_path))
|
||||
.major(major)
|
||||
.minor(minor)
|
||||
.build()
|
||||
.unwrap()]));
|
||||
|
||||
spec.linux_mut().as_mut().unwrap().set_resources(Some(
|
||||
oci::LinuxResourcesBuilder::default()
|
||||
.devices(vec![LinuxDeviceCgroupBuilder::default()
|
||||
.major(major)
|
||||
.minor(minor)
|
||||
.build()
|
||||
.unwrap()])
|
||||
.build()
|
||||
.unwrap(),
|
||||
));
|
||||
|
||||
let res = update_spec_devices(
|
||||
&mut spec,
|
||||
HashMap::from_iter(vec![(
|
||||
container_path,
|
||||
DeviceInfo::new(vm_path, true).unwrap().into(),
|
||||
)]),
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_spec_devices_guest_host_conflict() {
|
||||
let null_rdev = fs::metadata("/dev/null").unwrap().rdev();
|
||||
let zero_rdev = fs::metadata("/dev/zero").unwrap().rdev();
|
||||
let full_rdev = fs::metadata("/dev/full").unwrap().rdev();
|
||||
|
||||
let host_major_a = stat::major(null_rdev) as i64;
|
||||
let host_minor_a = stat::minor(null_rdev) as i64;
|
||||
let host_major_b = stat::major(zero_rdev) as i64;
|
||||
let host_minor_b = stat::minor(zero_rdev) as i64;
|
||||
|
||||
let mut spec = SpecBuilder::default()
|
||||
.linux(
|
||||
LinuxBuilder::default()
|
||||
.devices(vec![
|
||||
LinuxDeviceBuilder::default()
|
||||
.path(PathBuf::from("/dev/a"))
|
||||
.typ(LinuxDeviceType::C)
|
||||
.major(host_major_a)
|
||||
.minor(host_minor_a)
|
||||
.build()
|
||||
.unwrap(),
|
||||
LinuxDeviceBuilder::default()
|
||||
.path(PathBuf::from("/dev/b"))
|
||||
.typ(LinuxDeviceType::C)
|
||||
.major(host_major_b)
|
||||
.minor(host_minor_b)
|
||||
.build()
|
||||
.unwrap(),
|
||||
])
|
||||
.resources(
|
||||
LinuxResourcesBuilder::default()
|
||||
.devices(vec![
|
||||
LinuxDeviceCgroupBuilder::default()
|
||||
.typ(LinuxDeviceType::C)
|
||||
.major(host_major_a)
|
||||
.minor(host_minor_a)
|
||||
.build()
|
||||
.unwrap(),
|
||||
LinuxDeviceCgroupBuilder::default()
|
||||
.typ(LinuxDeviceType::C)
|
||||
.major(host_major_b)
|
||||
.minor(host_minor_b)
|
||||
.build()
|
||||
.unwrap(),
|
||||
])
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let container_path_a = "/dev/a";
|
||||
let vm_path_a = "/dev/zero";
|
||||
|
||||
let guest_major_a = stat::major(zero_rdev) as i64;
|
||||
let guest_minor_a = stat::minor(zero_rdev) as i64;
|
||||
|
||||
let container_path_b = "/dev/b";
|
||||
let vm_path_b = "/dev/full";
|
||||
|
||||
let guest_major_b = stat::major(full_rdev) as i64;
|
||||
let guest_minor_b = stat::minor(full_rdev) as i64;
|
||||
|
||||
let specdevices = &spec.linux().as_ref().unwrap().devices().clone().unwrap();
|
||||
assert_eq!(host_major_a, specdevices[0].major());
|
||||
assert_eq!(host_minor_a, specdevices[0].minor());
|
||||
assert_eq!(host_major_b, specdevices[1].major());
|
||||
assert_eq!(host_minor_b, specdevices[1].minor());
|
||||
|
||||
let specresources_devices = spec
|
||||
.linux()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.resources()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.devices()
|
||||
.clone()
|
||||
.unwrap();
|
||||
assert_eq!(Some(host_major_a), specresources_devices[0].major());
|
||||
assert_eq!(Some(host_minor_a), specresources_devices[0].minor());
|
||||
assert_eq!(Some(host_major_b), specresources_devices[1].major());
|
||||
assert_eq!(Some(host_minor_b), specresources_devices[1].minor());
|
||||
|
||||
let updates = HashMap::from_iter(vec![
|
||||
(
|
||||
container_path_a,
|
||||
DeviceInfo::new(vm_path_a, true).unwrap().into(),
|
||||
),
|
||||
(
|
||||
container_path_b,
|
||||
DeviceInfo::new(vm_path_b, true).unwrap().into(),
|
||||
),
|
||||
]);
|
||||
let res = update_spec_devices(&mut spec, updates);
|
||||
assert!(res.is_ok());
|
||||
|
||||
let specdevices = &spec.linux().as_ref().unwrap().devices().clone().unwrap();
|
||||
assert_eq!(guest_major_a, specdevices[0].major());
|
||||
assert_eq!(guest_minor_a, specdevices[0].minor());
|
||||
assert_eq!(guest_major_b, specdevices[1].major());
|
||||
assert_eq!(guest_minor_b, specdevices[1].minor());
|
||||
|
||||
let specresources_devices = spec
|
||||
.linux()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.resources()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.devices()
|
||||
.clone()
|
||||
.unwrap();
|
||||
assert_eq!(Some(guest_major_a), specresources_devices[0].major());
|
||||
assert_eq!(Some(guest_minor_a), specresources_devices[0].minor());
|
||||
assert_eq!(Some(guest_major_b), specresources_devices[1].major());
|
||||
assert_eq!(Some(guest_minor_b), specresources_devices[1].minor());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_spec_devices_char_block_conflict() {
|
||||
let null_rdev = fs::metadata("/dev/null").unwrap().rdev();
|
||||
|
||||
let guest_major = stat::major(null_rdev) as i64;
|
||||
let guest_minor = stat::minor(null_rdev) as i64;
|
||||
let host_major: i64 = 99;
|
||||
let host_minor: i64 = 99;
|
||||
|
||||
let mut spec = SpecBuilder::default()
|
||||
.linux(
|
||||
LinuxBuilder::default()
|
||||
.devices(vec![
|
||||
LinuxDeviceBuilder::default()
|
||||
.path(PathBuf::from("/dev/char"))
|
||||
.typ(LinuxDeviceType::C)
|
||||
.major(host_major)
|
||||
.minor(host_minor)
|
||||
.build()
|
||||
.unwrap(),
|
||||
LinuxDeviceBuilder::default()
|
||||
.path(PathBuf::from("/dev/block"))
|
||||
.typ(LinuxDeviceType::B)
|
||||
.major(host_major)
|
||||
.minor(host_minor)
|
||||
.build()
|
||||
.unwrap(),
|
||||
])
|
||||
.resources(
|
||||
LinuxResourcesBuilder::default()
|
||||
.devices(vec![
|
||||
LinuxDeviceCgroupBuilder::default()
|
||||
.typ(LinuxDeviceType::C)
|
||||
.major(host_major)
|
||||
.minor(host_minor)
|
||||
.build()
|
||||
.unwrap(),
|
||||
LinuxDeviceCgroupBuilder::default()
|
||||
.typ(LinuxDeviceType::B)
|
||||
.major(host_major)
|
||||
.minor(host_minor)
|
||||
.build()
|
||||
.unwrap(),
|
||||
])
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let container_path = "/dev/char";
|
||||
let vm_path = "/dev/null";
|
||||
|
||||
let specresources_devices = spec
|
||||
.linux()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.resources()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.devices()
|
||||
.clone()
|
||||
.unwrap();
|
||||
assert_eq!(Some(host_major), specresources_devices[0].major());
|
||||
assert_eq!(Some(host_minor), specresources_devices[0].minor());
|
||||
assert_eq!(Some(host_major), specresources_devices[1].major());
|
||||
assert_eq!(Some(host_minor), specresources_devices[1].minor());
|
||||
|
||||
let res = update_spec_devices(
|
||||
&mut spec,
|
||||
HashMap::from_iter(vec![(
|
||||
container_path,
|
||||
DeviceInfo::new(vm_path, true).unwrap().into(),
|
||||
)]),
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
|
||||
// Only the char device, not the block device should be updated
|
||||
let specresources_devices = spec
|
||||
.linux()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.resources()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.devices()
|
||||
.clone()
|
||||
.unwrap();
|
||||
assert_eq!(Some(guest_major), specresources_devices[0].major());
|
||||
assert_eq!(Some(guest_minor), specresources_devices[0].minor());
|
||||
assert_eq!(Some(host_major), specresources_devices[1].major());
|
||||
assert_eq!(Some(host_minor), specresources_devices[1].minor());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_spec_devices_final_path() {
|
||||
let null_rdev = fs::metadata("/dev/null").unwrap().rdev();
|
||||
let guest_major = stat::major(null_rdev) as i64;
|
||||
let guest_minor = stat::minor(null_rdev) as i64;
|
||||
|
||||
let container_path = "/dev/original";
|
||||
let host_major: i64 = 99;
|
||||
let host_minor: i64 = 99;
|
||||
|
||||
let mut spec = SpecBuilder::default()
|
||||
.linux(
|
||||
LinuxBuilder::default()
|
||||
.devices(vec![LinuxDeviceBuilder::default()
|
||||
.path(PathBuf::from(container_path))
|
||||
.typ(LinuxDeviceType::C)
|
||||
.major(host_major)
|
||||
.minor(host_minor)
|
||||
.build()
|
||||
.unwrap()])
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let vm_path = "/dev/null";
|
||||
let final_path = "/dev/new";
|
||||
|
||||
let res = update_spec_devices(
|
||||
&mut spec,
|
||||
HashMap::from_iter(vec![(
|
||||
container_path,
|
||||
DevUpdate::new(vm_path, final_path).unwrap(),
|
||||
)]),
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
|
||||
let specdevices = &spec.linux().as_ref().unwrap().devices().clone().unwrap();
|
||||
assert_eq!(guest_major, specdevices[0].major());
|
||||
assert_eq!(guest_minor, specdevices[0].minor());
|
||||
assert_eq!(&PathBuf::from(final_path), specdevices[0].path());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_env_pci() {
|
||||
let example_map = [
|
||||
// Each is a host,guest pair of pci addresses
|
||||
("0000:1a:01.0", "0000:01:01.0"),
|
||||
("0000:1b:02.0", "0000:01:02.0"),
|
||||
// This one has the same host address as guest address
|
||||
// above, to test that we're not double-translating
|
||||
("0000:01:01.0", "ffff:02:1f.7"),
|
||||
];
|
||||
|
||||
let pci_dev_info_original = r#"PCIDEVICE_x_INFO={"0000:1a:01.0":{"generic":{"deviceID":"0000:1a:01.0"}},"0000:1b:02.0":{"generic":{"deviceID":"0000:1b:02.0"}}}"#;
|
||||
let pci_dev_info_expected = r#"PCIDEVICE_x_INFO={"0000:01:01.0":{"generic":{"deviceID":"0000:01:01.0"}},"0000:01:02.0":{"generic":{"deviceID":"0000:01:02.0"}}}"#;
|
||||
let mut env = vec![
|
||||
"PCIDEVICE_x=0000:1a:01.0,0000:1b:02.0".to_string(),
|
||||
pci_dev_info_original.to_string(),
|
||||
"PCIDEVICE_y=0000:01:01.0".to_string(),
|
||||
"NOTAPCIDEVICE_blah=abcd:ef:01.0".to_string(),
|
||||
];
|
||||
|
||||
let pci_fixups = example_map
|
||||
.iter()
|
||||
.map(|(h, g)| {
|
||||
(
|
||||
pci::Address::from_str(h).unwrap(),
|
||||
pci::Address::from_str(g).unwrap(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let res = update_env_pci(&mut env, &pci_fixups);
|
||||
assert!(res.is_ok(), "error: {}", res.err().unwrap());
|
||||
|
||||
assert_eq!(env[0], "PCIDEVICE_x=0000:01:01.0,0000:01:02.0");
|
||||
assert_eq!(env[1], pci_dev_info_expected);
|
||||
assert_eq!(env[2], "PCIDEVICE_y=ffff:02:1f.7");
|
||||
assert_eq!(env[3], "NOTAPCIDEVICE_blah=abcd:ef:01.0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pcipath_to_sysfs() {
|
||||
let testdir = tempdir().expect("failed to create tmpdir");
|
||||
let rootbuspath = testdir.path().to_str().unwrap();
|
||||
|
||||
let path2 = pci::Path::from_str("02").unwrap();
|
||||
let path23 = pci::Path::from_str("02/03").unwrap();
|
||||
let path234 = pci::Path::from_str("02/03/04").unwrap();
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path2);
|
||||
assert_eq!(relpath.unwrap(), "/0000:00:02.0");
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path23);
|
||||
assert!(relpath.is_err());
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path234);
|
||||
assert!(relpath.is_err());
|
||||
|
||||
// Create mock sysfs files for the device at 0000:00:02.0
|
||||
let bridge2path = format!("{}{}", rootbuspath, "/0000:00:02.0");
|
||||
|
||||
fs::create_dir_all(&bridge2path).unwrap();
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path2);
|
||||
assert_eq!(relpath.unwrap(), "/0000:00:02.0");
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path23);
|
||||
assert!(relpath.is_err());
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path234);
|
||||
assert!(relpath.is_err());
|
||||
|
||||
// Create mock sysfs files to indicate that 0000:00:02.0 is a bridge to bus 01
|
||||
let bridge2bus = "0000:01";
|
||||
let bus2path = format!("{}/pci_bus/{}", bridge2path, bridge2bus);
|
||||
|
||||
fs::create_dir_all(bus2path).unwrap();
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path2);
|
||||
assert_eq!(relpath.unwrap(), "/0000:00:02.0");
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path23);
|
||||
assert_eq!(relpath.unwrap(), "/0000:00:02.0/0000:01:03.0");
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path234);
|
||||
assert!(relpath.is_err());
|
||||
|
||||
// Create mock sysfs files for a bridge at 0000:01:03.0 to bus 02
|
||||
let bridge3path = format!("{}/0000:01:03.0", bridge2path);
|
||||
let bridge3bus = "0000:02";
|
||||
let bus3path = format!("{}/pci_bus/{}", bridge3path, bridge3bus);
|
||||
|
||||
fs::create_dir_all(bus3path).unwrap();
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path2);
|
||||
assert_eq!(relpath.unwrap(), "/0000:00:02.0");
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path23);
|
||||
assert_eq!(relpath.unwrap(), "/0000:00:02.0/0000:01:03.0");
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path234);
|
||||
assert_eq!(relpath.unwrap(), "/0000:00:02.0/0000:01:03.0/0000:02:04.0");
|
||||
}
|
||||
|
||||
// We use device specific variants of this for real cases, but
|
||||
// they have some complications that make them troublesome to unit
|
||||
// test
|
||||
async fn example_get_device_name(
|
||||
sandbox: &Arc<Mutex<Sandbox>>,
|
||||
relpath: &str,
|
||||
) -> Result<String> {
|
||||
let matcher = VirtioBlkPciMatcher::new(relpath);
|
||||
|
||||
let uev = wait_for_uevent(sandbox, matcher).await?;
|
||||
|
||||
Ok(uev.devname)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_device_name() {
|
||||
let devname = "vda";
|
||||
let root_bus = create_pci_root_bus_path();
|
||||
let relpath = "/0000:00:0a.0/0000:03:0b.0";
|
||||
let devpath = format!("{}{}/virtio4/block/{}", root_bus, relpath, devname);
|
||||
|
||||
let mut uev = crate::uevent::Uevent::default();
|
||||
uev.action = crate::linux_abi::U_EVENT_ACTION_ADD.to_string();
|
||||
uev.subsystem = BLOCK.to_string();
|
||||
uev.devpath = devpath.clone();
|
||||
uev.devname = devname.to_string();
|
||||
|
||||
let logger = slog::Logger::root(slog::Discard, o!());
|
||||
let sandbox = Arc::new(Mutex::new(Sandbox::new(&logger).unwrap()));
|
||||
|
||||
let mut sb = sandbox.lock().await;
|
||||
sb.uevent_map.insert(devpath.clone(), uev);
|
||||
drop(sb); // unlock
|
||||
|
||||
let name = example_get_device_name(&sandbox, relpath).await;
|
||||
assert!(name.is_ok(), "{}", name.unwrap_err());
|
||||
assert_eq!(name.unwrap(), devname);
|
||||
|
||||
let mut sb = sandbox.lock().await;
|
||||
let uev = sb.uevent_map.remove(&devpath).unwrap();
|
||||
drop(sb); // unlock
|
||||
|
||||
spawn_test_watcher(sandbox.clone(), uev);
|
||||
|
||||
let name = example_get_device_name(&sandbox, relpath).await;
|
||||
assert!(name.is_ok(), "{}", name.unwrap_err());
|
||||
assert_eq!(name.unwrap(), devname);
|
||||
}
|
||||
|
||||
|
||||
#[tokio::test]
|
||||
#[allow(clippy::redundant_clone)]
|
||||
async fn test_virtio_blk_matcher() {
|
||||
|
@@ -525,3 +525,589 @@ pub fn online_device(path: &str) -> Result<()> {
|
||||
fs::write(path, "1")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::linux_abi::create_pci_root_bus_path;
|
||||
use crate::uevent::{spawn_test_watcher, wait_for_uevent};
|
||||
use oci::{
|
||||
Linux, LinuxBuilder, LinuxDeviceBuilder, LinuxDeviceCgroupBuilder, LinuxDeviceType,
|
||||
LinuxResources, LinuxResourcesBuilder, SpecBuilder,
|
||||
};
|
||||
use oci_spec::runtime as oci;
|
||||
use std::iter::FromIterator;
|
||||
use tempfile::tempdir;
|
||||
|
||||
const VM_ROOTFS: &str = "/";
|
||||
|
||||
#[test]
|
||||
fn test_update_device_cgroup() {
|
||||
let logger = slog::Logger::root(slog::Discard, o!());
|
||||
let mut linux = Linux::default();
|
||||
linux.set_resources(Some(LinuxResources::default()));
|
||||
let mut spec = SpecBuilder::default().linux(linux).build().unwrap();
|
||||
|
||||
let dev_info = DeviceInfo::new(VM_ROOTFS, false).unwrap();
|
||||
insert_devices_cgroup_rule(&logger, &mut spec, &dev_info, false, "rw").unwrap();
|
||||
|
||||
let devices = spec
|
||||
.linux()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.resources()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.devices()
|
||||
.clone()
|
||||
.unwrap();
|
||||
assert_eq!(devices.len(), 1);
|
||||
|
||||
let meta = fs::metadata(VM_ROOTFS).unwrap();
|
||||
let rdev = meta.dev();
|
||||
let major = stat::major(rdev) as i64;
|
||||
let minor = stat::minor(rdev) as i64;
|
||||
|
||||
assert_eq!(devices[0].major(), Some(major));
|
||||
assert_eq!(devices[0].minor(), Some(minor));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_spec_devices() {
|
||||
let logger = slog::Logger::root(slog::Discard, o!());
|
||||
let (major, minor) = (7, 2);
|
||||
let mut spec = Spec::default();
|
||||
|
||||
// vm_path empty
|
||||
let update = DeviceInfo::new("", true);
|
||||
assert!(update.is_err());
|
||||
|
||||
// linux is empty
|
||||
let container_path = "/dev/null";
|
||||
let vm_path = "/dev/null";
|
||||
let res = update_spec_devices(
|
||||
&logger,
|
||||
&mut spec,
|
||||
HashMap::from_iter(vec![(
|
||||
container_path,
|
||||
DeviceInfo::new(vm_path, true).unwrap().into(),
|
||||
)]),
|
||||
);
|
||||
assert!(res.is_err());
|
||||
|
||||
spec.set_linux(Some(Linux::default()));
|
||||
|
||||
// linux.devices doesn't contain the updated device
|
||||
let res = update_spec_devices(
|
||||
&logger,
|
||||
&mut spec,
|
||||
HashMap::from_iter(vec![(
|
||||
container_path,
|
||||
DeviceInfo::new(vm_path, true).unwrap().into(),
|
||||
)]),
|
||||
);
|
||||
assert!(res.is_err());
|
||||
|
||||
spec.linux_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.set_devices(Some(vec![LinuxDeviceBuilder::default()
|
||||
.path(PathBuf::from("/dev/null2"))
|
||||
.major(major)
|
||||
.minor(minor)
|
||||
.build()
|
||||
.unwrap()]));
|
||||
|
||||
// guest and host path are not the same
|
||||
let res = update_spec_devices(
|
||||
&logger,
|
||||
&mut spec,
|
||||
HashMap::from_iter(vec![(
|
||||
container_path,
|
||||
DeviceInfo::new(vm_path, true).unwrap().into(),
|
||||
)]),
|
||||
);
|
||||
assert!(
|
||||
res.is_err(),
|
||||
"container_path={:?} vm_path={:?} spec={:?}",
|
||||
container_path,
|
||||
vm_path,
|
||||
spec
|
||||
);
|
||||
|
||||
spec.linux_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.devices_mut()
|
||||
.as_mut()
|
||||
.unwrap()[0]
|
||||
.set_path(PathBuf::from(container_path));
|
||||
|
||||
// spec.linux.resources is empty
|
||||
let res = update_spec_devices(
|
||||
&logger,
|
||||
&mut spec,
|
||||
HashMap::from_iter(vec![(
|
||||
container_path,
|
||||
DeviceInfo::new(vm_path, true).unwrap().into(),
|
||||
)]),
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
|
||||
// update both devices and cgroup lists
|
||||
spec.linux_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.set_devices(Some(vec![LinuxDeviceBuilder::default()
|
||||
.path(PathBuf::from(container_path))
|
||||
.major(major)
|
||||
.minor(minor)
|
||||
.build()
|
||||
.unwrap()]));
|
||||
|
||||
spec.linux_mut().as_mut().unwrap().set_resources(Some(
|
||||
oci::LinuxResourcesBuilder::default()
|
||||
.devices(vec![LinuxDeviceCgroupBuilder::default()
|
||||
.major(major)
|
||||
.minor(minor)
|
||||
.build()
|
||||
.unwrap()])
|
||||
.build()
|
||||
.unwrap(),
|
||||
));
|
||||
|
||||
let res = update_spec_devices(
|
||||
&logger,
|
||||
&mut spec,
|
||||
HashMap::from_iter(vec![(
|
||||
container_path,
|
||||
DeviceInfo::new(vm_path, true).unwrap().into(),
|
||||
)]),
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_spec_devices_guest_host_conflict() {
|
||||
let logger = slog::Logger::root(slog::Discard, o!());
|
||||
|
||||
let null_rdev = fs::metadata("/dev/null").unwrap().rdev();
|
||||
let zero_rdev = fs::metadata("/dev/zero").unwrap().rdev();
|
||||
let full_rdev = fs::metadata("/dev/full").unwrap().rdev();
|
||||
|
||||
let host_major_a = stat::major(null_rdev) as i64;
|
||||
let host_minor_a = stat::minor(null_rdev) as i64;
|
||||
let host_major_b = stat::major(zero_rdev) as i64;
|
||||
let host_minor_b = stat::minor(zero_rdev) as i64;
|
||||
|
||||
let mut spec = SpecBuilder::default()
|
||||
.linux(
|
||||
LinuxBuilder::default()
|
||||
.devices(vec![
|
||||
LinuxDeviceBuilder::default()
|
||||
.path(PathBuf::from("/dev/a"))
|
||||
.typ(LinuxDeviceType::C)
|
||||
.major(host_major_a)
|
||||
.minor(host_minor_a)
|
||||
.build()
|
||||
.unwrap(),
|
||||
LinuxDeviceBuilder::default()
|
||||
.path(PathBuf::from("/dev/b"))
|
||||
.typ(LinuxDeviceType::C)
|
||||
.major(host_major_b)
|
||||
.minor(host_minor_b)
|
||||
.build()
|
||||
.unwrap(),
|
||||
])
|
||||
.resources(
|
||||
LinuxResourcesBuilder::default()
|
||||
.devices(vec![
|
||||
LinuxDeviceCgroupBuilder::default()
|
||||
.typ(LinuxDeviceType::C)
|
||||
.major(host_major_a)
|
||||
.minor(host_minor_a)
|
||||
.build()
|
||||
.unwrap(),
|
||||
LinuxDeviceCgroupBuilder::default()
|
||||
.typ(LinuxDeviceType::C)
|
||||
.major(host_major_b)
|
||||
.minor(host_minor_b)
|
||||
.build()
|
||||
.unwrap(),
|
||||
])
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let container_path_a = "/dev/a";
|
||||
let vm_path_a = "/dev/zero";
|
||||
|
||||
let guest_major_a = stat::major(zero_rdev) as i64;
|
||||
let guest_minor_a = stat::minor(zero_rdev) as i64;
|
||||
|
||||
let container_path_b = "/dev/b";
|
||||
let vm_path_b = "/dev/full";
|
||||
|
||||
let guest_major_b = stat::major(full_rdev) as i64;
|
||||
let guest_minor_b = stat::minor(full_rdev) as i64;
|
||||
|
||||
let specdevices = &spec.linux().as_ref().unwrap().devices().clone().unwrap();
|
||||
assert_eq!(host_major_a, specdevices[0].major());
|
||||
assert_eq!(host_minor_a, specdevices[0].minor());
|
||||
assert_eq!(host_major_b, specdevices[1].major());
|
||||
assert_eq!(host_minor_b, specdevices[1].minor());
|
||||
|
||||
let specresources_devices = spec
|
||||
.linux()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.resources()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.devices()
|
||||
.clone()
|
||||
.unwrap();
|
||||
assert_eq!(Some(host_major_a), specresources_devices[0].major());
|
||||
assert_eq!(Some(host_minor_a), specresources_devices[0].minor());
|
||||
assert_eq!(Some(host_major_b), specresources_devices[1].major());
|
||||
assert_eq!(Some(host_minor_b), specresources_devices[1].minor());
|
||||
|
||||
let updates = HashMap::from_iter(vec![
|
||||
(
|
||||
container_path_a,
|
||||
DeviceInfo::new(vm_path_a, true).unwrap().into(),
|
||||
),
|
||||
(
|
||||
container_path_b,
|
||||
DeviceInfo::new(vm_path_b, true).unwrap().into(),
|
||||
),
|
||||
]);
|
||||
let res = update_spec_devices(&logger, &mut spec, updates);
|
||||
assert!(res.is_ok());
|
||||
|
||||
let specdevices = &spec.linux().as_ref().unwrap().devices().clone().unwrap();
|
||||
assert_eq!(guest_major_a, specdevices[0].major());
|
||||
assert_eq!(guest_minor_a, specdevices[0].minor());
|
||||
assert_eq!(guest_major_b, specdevices[1].major());
|
||||
assert_eq!(guest_minor_b, specdevices[1].minor());
|
||||
|
||||
let specresources_devices = spec
|
||||
.linux()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.resources()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.devices()
|
||||
.clone()
|
||||
.unwrap();
|
||||
assert_eq!(Some(guest_major_a), specresources_devices[0].major());
|
||||
assert_eq!(Some(guest_minor_a), specresources_devices[0].minor());
|
||||
assert_eq!(Some(guest_major_b), specresources_devices[1].major());
|
||||
assert_eq!(Some(guest_minor_b), specresources_devices[1].minor());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_spec_devices_char_block_conflict() {
|
||||
let logger = slog::Logger::root(slog::Discard, o!());
|
||||
|
||||
let null_rdev = fs::metadata("/dev/null").unwrap().rdev();
|
||||
|
||||
let guest_major = stat::major(null_rdev) as i64;
|
||||
let guest_minor = stat::minor(null_rdev) as i64;
|
||||
let host_major: i64 = 99;
|
||||
let host_minor: i64 = 99;
|
||||
|
||||
let mut spec = SpecBuilder::default()
|
||||
.linux(
|
||||
LinuxBuilder::default()
|
||||
.devices(vec![
|
||||
LinuxDeviceBuilder::default()
|
||||
.path(PathBuf::from("/dev/char"))
|
||||
.typ(LinuxDeviceType::C)
|
||||
.major(host_major)
|
||||
.minor(host_minor)
|
||||
.build()
|
||||
.unwrap(),
|
||||
LinuxDeviceBuilder::default()
|
||||
.path(PathBuf::from("/dev/block"))
|
||||
.typ(LinuxDeviceType::B)
|
||||
.major(host_major)
|
||||
.minor(host_minor)
|
||||
.build()
|
||||
.unwrap(),
|
||||
])
|
||||
.resources(
|
||||
LinuxResourcesBuilder::default()
|
||||
.devices(vec![
|
||||
LinuxDeviceCgroupBuilder::default()
|
||||
.typ(LinuxDeviceType::C)
|
||||
.major(host_major)
|
||||
.minor(host_minor)
|
||||
.build()
|
||||
.unwrap(),
|
||||
LinuxDeviceCgroupBuilder::default()
|
||||
.typ(LinuxDeviceType::B)
|
||||
.major(host_major)
|
||||
.minor(host_minor)
|
||||
.build()
|
||||
.unwrap(),
|
||||
])
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let container_path = "/dev/char";
|
||||
let vm_path = "/dev/null";
|
||||
|
||||
let specresources_devices = spec
|
||||
.linux()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.resources()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.devices()
|
||||
.clone()
|
||||
.unwrap();
|
||||
assert_eq!(Some(host_major), specresources_devices[0].major());
|
||||
assert_eq!(Some(host_minor), specresources_devices[0].minor());
|
||||
assert_eq!(Some(host_major), specresources_devices[1].major());
|
||||
assert_eq!(Some(host_minor), specresources_devices[1].minor());
|
||||
|
||||
let res = update_spec_devices(
|
||||
&logger,
|
||||
&mut spec,
|
||||
HashMap::from_iter(vec![(
|
||||
container_path,
|
||||
DeviceInfo::new(vm_path, true).unwrap().into(),
|
||||
)]),
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
|
||||
// Only the char device, not the block device should be updated
|
||||
let specresources_devices = spec
|
||||
.linux()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.resources()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.devices()
|
||||
.clone()
|
||||
.unwrap();
|
||||
assert_eq!(Some(guest_major), specresources_devices[0].major());
|
||||
assert_eq!(Some(guest_minor), specresources_devices[0].minor());
|
||||
assert_eq!(Some(host_major), specresources_devices[1].major());
|
||||
assert_eq!(Some(host_minor), specresources_devices[1].minor());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_spec_devices_final_path() {
|
||||
let logger = slog::Logger::root(slog::Discard, o!());
|
||||
|
||||
let null_rdev = fs::metadata("/dev/null").unwrap().rdev();
|
||||
let guest_major = stat::major(null_rdev) as i64;
|
||||
let guest_minor = stat::minor(null_rdev) as i64;
|
||||
|
||||
let container_path = "/dev/original";
|
||||
let host_major: i64 = 99;
|
||||
let host_minor: i64 = 99;
|
||||
|
||||
let mut spec = SpecBuilder::default()
|
||||
.linux(
|
||||
LinuxBuilder::default()
|
||||
.devices(vec![LinuxDeviceBuilder::default()
|
||||
.path(PathBuf::from(container_path))
|
||||
.typ(LinuxDeviceType::C)
|
||||
.major(host_major)
|
||||
.minor(host_minor)
|
||||
.build()
|
||||
.unwrap()])
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let vm_path = "/dev/null";
|
||||
let final_path = "/dev/new";
|
||||
|
||||
let res = update_spec_devices(
|
||||
&logger,
|
||||
&mut spec,
|
||||
HashMap::from_iter(vec![(
|
||||
container_path,
|
||||
DevUpdate::new(vm_path, final_path).unwrap(),
|
||||
)]),
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
|
||||
let specdevices = &spec.linux().as_ref().unwrap().devices().clone().unwrap();
|
||||
assert_eq!(guest_major, specdevices[0].major());
|
||||
assert_eq!(guest_minor, specdevices[0].minor());
|
||||
assert_eq!(&PathBuf::from(final_path), specdevices[0].path());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_env_pci() {
|
||||
let example_map = [
|
||||
// Each is a host,guest pair of pci addresses
|
||||
("0000:1a:01.0", "0000:01:01.0"),
|
||||
("0000:1b:02.0", "0000:01:02.0"),
|
||||
// This one has the same host address as guest address
|
||||
// above, to test that we're not double-translating
|
||||
("0000:01:01.0", "ffff:02:1f.7"),
|
||||
];
|
||||
|
||||
let pci_dev_info_original = r#"PCIDEVICE_x_INFO={"0000:1a:01.0":{"generic":{"deviceID":"0000:1a:01.0"}},"0000:1b:02.0":{"generic":{"deviceID":"0000:1b:02.0"}}}"#;
|
||||
let pci_dev_info_expected = r#"PCIDEVICE_x_INFO={"0000:01:01.0":{"generic":{"deviceID":"0000:01:01.0"}},"0000:01:02.0":{"generic":{"deviceID":"0000:01:02.0"}}}"#;
|
||||
let mut env = vec![
|
||||
"PCIDEVICE_x=0000:1a:01.0,0000:1b:02.0".to_string(),
|
||||
pci_dev_info_original.to_string(),
|
||||
"PCIDEVICE_y=0000:01:01.0".to_string(),
|
||||
"NOTAPCIDEVICE_blah=abcd:ef:01.0".to_string(),
|
||||
];
|
||||
|
||||
let pci_fixups = example_map
|
||||
.iter()
|
||||
.map(|(h, g)| {
|
||||
(
|
||||
pci::Address::from_str(h).unwrap(),
|
||||
pci::Address::from_str(g).unwrap(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let res = update_env_pci(&mut env, &pci_fixups);
|
||||
assert!(res.is_ok(), "error: {}", res.err().unwrap());
|
||||
|
||||
assert_eq!(env[0], "PCIDEVICE_x=0000:01:01.0,0000:01:02.0");
|
||||
assert_eq!(env[1], pci_dev_info_expected);
|
||||
assert_eq!(env[2], "PCIDEVICE_y=ffff:02:1f.7");
|
||||
assert_eq!(env[3], "NOTAPCIDEVICE_blah=abcd:ef:01.0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pcipath_to_sysfs() {
|
||||
let testdir = tempdir().expect("failed to create tmpdir");
|
||||
let rootbuspath = testdir.path().to_str().unwrap();
|
||||
|
||||
let path2 = pci::Path::from_str("02").unwrap();
|
||||
let path23 = pci::Path::from_str("02/03").unwrap();
|
||||
let path234 = pci::Path::from_str("02/03/04").unwrap();
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path2);
|
||||
assert_eq!(relpath.unwrap(), "/0000:00:02.0");
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path23);
|
||||
assert!(relpath.is_err());
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path234);
|
||||
assert!(relpath.is_err());
|
||||
|
||||
// Create mock sysfs files for the device at 0000:00:02.0
|
||||
let bridge2path = format!("{}{}", rootbuspath, "/0000:00:02.0");
|
||||
|
||||
fs::create_dir_all(&bridge2path).unwrap();
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path2);
|
||||
assert_eq!(relpath.unwrap(), "/0000:00:02.0");
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path23);
|
||||
assert!(relpath.is_err());
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path234);
|
||||
assert!(relpath.is_err());
|
||||
|
||||
// Create mock sysfs files to indicate that 0000:00:02.0 is a bridge to bus 01
|
||||
let bridge2bus = "0000:01";
|
||||
let bus2path = format!("{}/pci_bus/{}", bridge2path, bridge2bus);
|
||||
|
||||
fs::create_dir_all(bus2path).unwrap();
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path2);
|
||||
assert_eq!(relpath.unwrap(), "/0000:00:02.0");
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path23);
|
||||
assert_eq!(relpath.unwrap(), "/0000:00:02.0/0000:01:03.0");
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path234);
|
||||
assert!(relpath.is_err());
|
||||
|
||||
// Create mock sysfs files for a bridge at 0000:01:03.0 to bus 02
|
||||
let bridge3path = format!("{}/0000:01:03.0", bridge2path);
|
||||
let bridge3bus = "0000:02";
|
||||
let bus3path = format!("{}/pci_bus/{}", bridge3path, bridge3bus);
|
||||
|
||||
fs::create_dir_all(bus3path).unwrap();
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path2);
|
||||
assert_eq!(relpath.unwrap(), "/0000:00:02.0");
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path23);
|
||||
assert_eq!(relpath.unwrap(), "/0000:00:02.0/0000:01:03.0");
|
||||
|
||||
let relpath = pcipath_to_sysfs(rootbuspath, &path234);
|
||||
assert_eq!(relpath.unwrap(), "/0000:00:02.0/0000:01:03.0/0000:02:04.0");
|
||||
}
|
||||
|
||||
// We use device specific variants of this for real cases, but
|
||||
// they have some complications that make them troublesome to unit
|
||||
// test
|
||||
async fn example_get_device_name(
|
||||
sandbox: &Arc<Mutex<Sandbox>>,
|
||||
relpath: &str,
|
||||
) -> Result<String> {
|
||||
let matcher = crate::device::block_device_handler::VirtioBlkPciMatcher::new(relpath);
|
||||
|
||||
let uev = wait_for_uevent(sandbox, matcher).await?;
|
||||
|
||||
Ok(uev.devname)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_device_name() {
|
||||
let devname = "vda";
|
||||
let root_bus = create_pci_root_bus_path();
|
||||
let relpath = "/0000:00:0a.0/0000:03:0b.0";
|
||||
let devpath = format!("{}{}/virtio4/block/{}", root_bus, relpath, devname);
|
||||
|
||||
let mut uev = crate::uevent::Uevent::default();
|
||||
uev.action = crate::linux_abi::U_EVENT_ACTION_ADD.to_string();
|
||||
uev.subsystem = BLOCK.to_string();
|
||||
uev.devpath = devpath.clone();
|
||||
uev.devname = devname.to_string();
|
||||
|
||||
let logger = slog::Logger::root(slog::Discard, o!());
|
||||
let sandbox = Arc::new(Mutex::new(Sandbox::new(&logger).unwrap()));
|
||||
|
||||
let mut sb = sandbox.lock().await;
|
||||
sb.uevent_map.insert(devpath.clone(), uev);
|
||||
drop(sb); // unlock
|
||||
|
||||
let name = example_get_device_name(&sandbox, relpath).await;
|
||||
assert!(name.is_ok(), "{}", name.unwrap_err());
|
||||
assert_eq!(name.unwrap(), devname);
|
||||
|
||||
let mut sb = sandbox.lock().await;
|
||||
let uev = sb.uevent_map.remove(&devpath).unwrap();
|
||||
drop(sb); // unlock
|
||||
|
||||
spawn_test_watcher(sandbox.clone(), uev);
|
||||
|
||||
let name = example_get_device_name(&sandbox, relpath).await;
|
||||
assert!(name.is_ok(), "{}", name.unwrap_err());
|
||||
assert_eq!(name.unwrap(), devname);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user