#[allow(dead_code)]
mod support;
use self::support::{with_mounted_timefs, RepositoryFixture};
use std::fs;
use std::os::unix::ffi::OsStringExt;
use std::thread;
use std::time::Duration;
#[test]
fn ref_snapshot_freezes_moving_references_and_history() {
let live_fixture = release_fixture("timefs-task10-live");
let (_value, live_mount) = with_mounted_timefs(live_fixture.path(), &[], &["-f"], |mounted| {
assert_eq!(
fs::read(mounted.path().join("now").join("README.md"))
.expect("live now/README.md should be readable"),
b"release v1\n"
);
advance_release_fixture(&live_fixture);
thread::sleep(Duration::from_secs(2));
assert_eq!(
fs::read(mounted.path().join("now").join("fresh.txt"))
.expect("live now/fresh.txt should appear after HEAD advances"),
b"fresh from v2\n"
);
assert_eq!(
fs::read(
mounted
.path()
.join("refs")
.join("heads")
.join("main")
.join("fresh.txt"),
)
.expect("live refs/heads/main/fresh.txt should appear after HEAD advances"),
b"fresh from v2\n"
);
assert_eq!(
sorted_dir_entries(&mounted.path().join("history").join("README.md")).len(),
2
);
assert_eq!(
sorted_dir_entries(&mounted.path().join("history").join("fresh.txt")).len(),
1
);
});
assert!(
live_mount.stderr.is_empty(),
"live release mount emitted unexpected stderr: {}",
live_mount.stderr
);
let snapshot_fixture = release_fixture("timefs-task10-snapshot");
let before_head = snapshot_fixture.git_rev_parse("HEAD");
let (_value, snapshot_mount) = with_mounted_timefs(
snapshot_fixture.path(),
&[],
&["-f", "--ref-snapshot"],
|mounted| {
assert_eq!(
fs::read(mounted.path().join("now").join("README.md"))
.expect("snapshotted now/README.md should be readable"),
b"release v1\n"
);
advance_release_fixture(&snapshot_fixture);
let after_head = snapshot_fixture.git_rev_parse("HEAD");
thread::sleep(Duration::from_secs(2));
assert_eq!(
fs::read(mounted.path().join("now").join("README.md"))
.expect("snapshotted now/README.md should stay frozen"),
b"release v1\n"
);
assert_eq!(
fs::read(mounted.path().join("at").join("HEAD").join("README.md"),)
.expect("snapshotted at/HEAD/README.md should stay frozen"),
b"release v1\n"
);
assert_eq!(
fs::metadata(mounted.path().join("now").join("fresh.txt"))
.expect_err("snapshotted now/fresh.txt should stay absent")
.raw_os_error(),
Some(libc::ENOENT)
);
assert_eq!(
fs::metadata(
mounted
.path()
.join("refs")
.join("heads")
.join("main")
.join("fresh.txt"),
)
.expect_err("snapshotted refs/heads/main/fresh.txt should stay absent")
.raw_os_error(),
Some(libc::ENOENT)
);
assert_eq!(
sorted_dir_entries(&mounted.path().join("history").join("README.md")).len(),
1
);
assert_eq!(
fs::metadata(mounted.path().join("history").join("fresh.txt"))
.expect_err("snapshotted history/fresh.txt should stay absent")
.raw_os_error(),
Some(libc::ENOENT)
);
assert_eq!(
fs::read(
mounted
.path()
.join("commits")
.join(before_head.as_str())
.join("README.md"),
)
.expect("commit-addressed snapshot should remain readable"),
b"release v1\n"
);
assert_eq!(
fs::read(
mounted
.path()
.join("commits")
.join(after_head.as_str())
.join("fresh.txt"),
)
.expect("commit-addressed fresh file should remain reachable by SHA"),
b"fresh from v2\n"
);
},
);
assert!(
snapshot_mount.stderr.is_empty(),
"snapshot release mount emitted unexpected stderr: {}",
snapshot_mount.stderr
);
}
fn release_fixture(prefix: &str) -> RepositoryFixture {
let fixture = RepositoryFixture::new(prefix);
fs::write(fixture.path().join("README.md"), b"release v1\n")
.expect("release fixture write should succeed");
fixture.git(["add", "README.md"]);
fixture.git(["commit", "-m", "Create release fixture"]);
fixture
}
fn advance_release_fixture(fixture: &RepositoryFixture) {
fs::write(fixture.path().join("README.md"), b"release v2\n")
.expect("release fixture update should succeed");
fs::write(fixture.path().join("fresh.txt"), b"fresh from v2\n")
.expect("release fixture fresh file write should succeed");
fixture.git(["add", "README.md", "fresh.txt"]);
fixture.git(["commit", "-m", "Advance release fixture"]);
}
fn sorted_dir_entries(path: &std::path::Path) -> Vec<Vec<u8>> {
let mut entries = fs::read_dir(path)
.expect("directory should be readable")
.filter_map(Result::ok)
.map(|entry| entry.file_name().into_vec())
.collect::<Vec<_>>();
entries.sort();
entries
}