mod common;
use agent_os_client::fs::{BatchWriteEntry, DeleteOptions, FileContent, MkdirOptions};
use agent_os_client::ClientError;
#[tokio::test]
async fn filesystem_surface_round_trips() {
if !common::sidecar_available() {
eprintln!("skipping filesystem_surface_round_trips: sidecar binary not built");
return;
}
let os = common::new_vm().await;
os.write_file("/tmp/a.txt", FileContent::Text("hello".to_string()))
.await
.expect("write text");
assert_eq!(os.read_file("/tmp/a.txt").await.expect("read text"), b"hello");
let blob: Vec<u8> = vec![0, 159, 146, 150, 255, 254, 0, 1, 2];
os.write_file("/tmp/blob.bin", FileContent::Bytes(blob.clone()))
.await
.expect("write binary");
assert_eq!(
os.read_file("/tmp/blob.bin").await.expect("read binary"),
blob,
"binary content must round-trip byte-for-byte"
);
os.mkdir("/tmp/d1/d2", MkdirOptions { recursive: true })
.await
.expect("mkdir -p");
assert!(os.exists("/tmp/d1/d2").await.expect("exists dir"));
assert!(os.stat("/tmp/d1/d2").await.expect("stat dir").is_directory);
let results = os
.write_files(vec![
BatchWriteEntry {
path: "/tmp/d1/d2/x.txt".to_string(),
content: FileContent::Text("x".to_string()),
},
BatchWriteEntry {
path: "relative-bad".to_string(),
content: FileContent::Text("y".to_string()),
},
])
.await;
assert!(results[0].success, "valid entry should succeed");
assert!(
!results[1].success && results[1].error.is_some(),
"guarded entry should fail per-entry, not reject the batch"
);
let entries = os.readdir("/tmp/d1/d2").await.expect("readdir");
assert!(entries.iter().any(|e| e == "x.txt"));
let recursive = os
.readdir_recursive("/tmp/d1", Default::default())
.await
.expect("readdir_recursive");
assert!(recursive.iter().any(|e| e.path == "/tmp/d1/d2/x.txt"));
os.move_path("/tmp/a.txt", "/tmp/a2.txt")
.await
.expect("move file");
assert!(!os.exists("/tmp/a.txt").await.expect("old gone"));
assert!(os.exists("/tmp/a2.txt").await.expect("new present"));
os.delete("/tmp/a2.txt", DeleteOptions { recursive: false })
.await
.expect("delete file");
assert!(!os.exists("/tmp/a2.txt").await.expect("deleted"));
os.delete("/tmp/d1", DeleteOptions { recursive: true })
.await
.expect("delete -r");
assert!(!os.exists("/tmp/d1").await.expect("dir removed"));
let guard_err = os
.read_file("relative")
.await
.expect_err("relative path must error");
assert!(
matches!(
guard_err.downcast_ref::<ClientError>(),
Some(ClientError::PathNotAbsolute(_))
),
"expected PathNotAbsolute, got {guard_err:?}"
);
os.shutdown().await.expect("shutdown");
}