Files
sausage/host/tests/undo.rs
T

113 lines
3.3 KiB
Rust

//! Undo snapshots and reversible namespace changes through a real world.
use sausage::world::World;
use sausage_vfs::{
Layer, Open,
journal::{Tag, Undo},
};
use std::sync::Arc;
fn tag(id: &str) -> Tag {
Tag {
id: id.into(),
pid: 1,
program: "/bin/test".into(),
conversations: vec!["conversation".into()],
}
}
async fn write(root: &Arc<dyn Layer>, path: &str, bytes: &[u8]) {
root.open(
path,
Open {
write: true,
create: true,
truncate: true,
..Default::default()
},
)
.await
.unwrap()
.write(0, bytes.to_vec())
.await
.unwrap();
}
async fn read(root: &Arc<dyn Layer>, path: &str) -> Vec<u8> {
root.open(path, Open::default())
.await
.unwrap()
.read(0, 100)
.await
.unwrap()
}
#[tokio::test]
async fn conflicts_force_and_undo_of_undo() {
let temp = tempfile::tempdir().unwrap();
let world = World::open(temp.path()).unwrap();
write(&world.root, "/a", b"old").await;
let journal = world.root.journal().unwrap();
let a = journal.layer(tag("A"));
let b = journal.layer(tag("B"));
write(&a, "/a", b"A").await;
write(&a, "/only-a", b"A").await;
write(&b, "/a", b"B").await;
write(&b, "/only-b", b"B").await;
let request = Undo {
tag: Some("A".into()),
..Default::default()
};
let blocked = journal.undo(request.clone(), tag("blocked")).await.unwrap();
assert_eq!(blocked.conflicts, ["/a"]);
assert!(blocked.tag.is_none());
assert_eq!(read(&world.root, "/a").await, b"B");
let result = journal
.undo(
Undo {
force: true,
..request
},
tag("restore"),
)
.await
.unwrap();
assert_eq!(read(&world.root, "/a").await, b"old");
assert!(world.root.stat("/only-a", false).await.is_err());
assert_eq!(read(&world.root, "/only-b").await, b"B");
journal
.undo(
Undo {
tag: result.tag,
..Default::default()
},
tag("redo"),
)
.await
.unwrap();
assert_eq!(read(&world.root, "/a").await, b"B");
assert_eq!(read(&world.root, "/only-a").await, b"A");
}
#[tokio::test]
async fn remove_rename_folder_and_inclusive_since() {
let temp = tempfile::tempdir().unwrap();
let world = World::open(temp.path()).unwrap();
write(&world.root, "/old", b"old").await;
write(&world.root, "/removed", b"removed").await;
let journal = world.root.journal().unwrap();
let a = journal.layer(tag("A"));
a.mkdir("/new").await.unwrap();
a.rename("/old", "/new/moved").await.unwrap();
a.remove_file("/removed").await.unwrap();
let entry = journal.list(None).await.unwrap()[0].entry;
write(&journal.layer(tag("B")), "/new/child", b"child").await;
journal
.undo(
Undo {
since: Some(entry),
..Default::default()
},
tag("restore"),
)
.await
.unwrap();
assert_eq!(read(&world.root, "/old").await, b"old");
assert_eq!(read(&world.root, "/removed").await, b"removed");
assert!(world.root.stat("/new", false).await.is_err());
}