ci(lesavka): isolate hid recovery smoke test

This commit is contained in:
Brad Stein 2026-05-18 12:25:08 -03:00
parent a9ca599bc3
commit 589c7eb978

View File

@ -17,10 +17,25 @@ use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
use temp_env::with_var;
use tempfile::NamedTempFile;
use tempfile::{NamedTempFile, tempdir};
use tokio::runtime::Runtime;
use tokio::sync::Mutex;
fn with_isolated_gadget_roots(f: impl FnOnce()) {
let dir = tempdir().expect("temp gadget roots");
let sys_root = dir.path().join("sys");
let cfg_root = dir.path().join("cfg");
std::fs::create_dir_all(sys_root.join("class/udc")).expect("fake udc root");
std::fs::create_dir_all(sys_root.join("bus/platform/devices")).expect("fake platform root");
std::fs::create_dir_all(&cfg_root).expect("fake configfs root");
let sys_root = sys_root.to_string_lossy().to_string();
let cfg_root = cfg_root.to_string_lossy().to_string();
with_var("LESAVKA_GADGET_SYSFS_ROOT", Some(sys_root.as_str()), || {
with_var("LESAVKA_GADGET_CONFIGFS_ROOT", Some(cfg_root.as_str()), f)
});
}
fn tmp_files_with_prefix(prefix: &str) -> HashSet<PathBuf> {
std::fs::read_dir("/tmp")
.ok()
@ -305,44 +320,53 @@ fn runtime_recover_hid_resets_cycle_flag_after_async_recovery_path() {
#[test]
#[serial]
fn runtime_recover_hid_attempts_cycle_when_enabled() {
with_var("LESAVKA_ALLOW_GADGET_CYCLE", Some("1"), || {
let rt = Runtime::new().expect("create runtime");
rt.block_on(async {
let kb_tmp = NamedTempFile::new().expect("temp keyboard file");
let ms_tmp = NamedTempFile::new().expect("temp mouse file");
with_isolated_gadget_roots(|| {
with_var("LESAVKA_ALLOW_GADGET_CYCLE", Some("1"), || {
with_var("LESAVKA_ALLOW_EXTERNAL_UVC_GADGET_CYCLE", Some("1"), || {
let rt = Runtime::new().expect("create runtime");
rt.block_on(async {
let kb_tmp = NamedTempFile::new().expect("temp keyboard file");
let ms_tmp = NamedTempFile::new().expect("temp mouse file");
let kb = tokio::fs::OpenOptions::new()
.write(true)
.open(kb_tmp.path())
.await
.expect("open temp kb");
let ms = tokio::fs::OpenOptions::new()
.write(true)
.open(ms_tmp.path())
.await
.expect("open temp ms");
let kb = tokio::fs::OpenOptions::new()
.write(true)
.open(kb_tmp.path())
.await
.expect("open temp kb");
let ms = tokio::fs::OpenOptions::new()
.write(true)
.open(ms_tmp.path())
.await
.expect("open temp ms");
let kb = Arc::new(Mutex::new(Some(kb)));
let ms = Arc::new(Mutex::new(Some(ms)));
let did_cycle = Arc::new(AtomicBool::new(false));
let err = std::io::Error::from_raw_os_error(libc::EPIPE);
let kb = Arc::new(Mutex::new(Some(kb)));
let ms = Arc::new(Mutex::new(Some(ms)));
let did_cycle = Arc::new(AtomicBool::new(false));
let err = std::io::Error::from_raw_os_error(libc::EPIPE);
runtime_support::recover_hid_if_needed(
&err,
UsbGadget::new("lesavka"),
kb.clone(),
ms.clone(),
kb_tmp.path().to_string_lossy().to_string(),
ms_tmp.path().to_string_lossy().to_string(),
did_cycle.clone(),
)
.await;
runtime_support::recover_hid_if_needed(
&err,
UsbGadget::new("lesavka"),
kb.clone(),
ms.clone(),
kb_tmp.path().to_string_lossy().to_string(),
ms_tmp.path().to_string_lossy().to_string(),
did_cycle.clone(),
)
.await;
tokio::time::sleep(Duration::from_millis(2_300)).await;
assert!(
!did_cycle.load(Ordering::SeqCst),
"cycle-enabled recovery should eventually clear lock"
);
assert!(
did_cycle.load(Ordering::SeqCst),
"transport error should acquire recovery lock before async recovery"
);
tokio::time::sleep(Duration::from_millis(2_300)).await;
assert!(
!did_cycle.load(Ordering::SeqCst),
"cycle-enabled recovery should eventually clear lock"
);
});
});
});
});
}