use super::*;
use crate::fs_btrfs_test_support::btrfs_fixture;
use crate::fs_kind::is_subvolume_root;
use crate::test_support::{git_context, remove, repository};
use crate::worktree_copy_stage_claim::stage_claims_exist;
use crate::worktree_ladder_test_support::{main_identity, plan_to, subvolume_repository};
const FAILED: GitStatus = GitStatus { code: Some(128) };
fn no_runner() -> impl FnMut(Option<&str>, &GitStep<'_>) -> Result<GitStatus, super::super::worktree_copy_error::WorktreeCopyError> {
return |_token, _step| { panic!("no Git run is expected"); };
}
#[test]
fn no_plan_means_the_persons_run() {
let ladder: Ladder = begin_ladder(None, &git_context(), &WorktreeIdentity::OutsideWorktree);
assert_eq!(ladder.first_step(), GitStep::Person);
let mut runner = no_runner();
let result: LadderResult = ladder.finish(GitStatus { code: Some(0) }, None, &mut runner, &git_context(), &mut std::io::sink());
assert_eq!(result, LadderResult { git: GitStatus { code: Some(0) }, carried: None });
}
#[test]
fn btrfs_a_refused_source_gets_a_subvolume_that_a_failed_git_leaves_no_trace_of() {
let Some(root) = btrfs_fixture("run-bootstrap") else { return };
let repo: PathBuf = std::fs::canonicalize(repository(root.as_path(), "ordinary")).expect("canonical");
std::fs::write(repo.join("untracked.txt"), b"u").expect("an untracked file rules every source out");
let plan = plan_to(root.join("topic"));
let ladder: Ladder = begin_ladder(Some(&plan), &git_context(), &main_identity(repo.as_path()));
assert_eq!(ladder.first_step(), GitStep::Person);
assert!(is_subvolume_root(plan.destination.as_path()).expect("probe"));
let mut runner = no_runner();
let result: LadderResult = ladder.finish(FAILED, None, &mut runner, &git_context(), &mut std::io::sink());
assert_eq!(result, LadderResult { git: FAILED, carried: None });
assert!(!plan.destination.exists());
remove(root.as_path());
}
#[test]
fn btrfs_a_clean_ordinary_source_gets_the_clone_rung_and_a_subvolume() {
let Some(root) = btrfs_fixture("run-clone") else { return };
let repo: PathBuf = std::fs::canonicalize(repository(root.as_path(), "ordinary")).expect("canonical");
let plan = plan_to(root.join("topic"));
let ladder: Ladder = begin_ladder(Some(&plan), &git_context(), &main_identity(repo.as_path()));
assert_eq!(ladder.first_step(), GitStep::WithoutCheckout(plan.insert_at));
assert!(is_subvolume_root(plan.destination.as_path()).expect("probe"));
assert!(stage_claims_exist(repo.join(".git").as_path()).expect("claims"), "the clone rung records the add durably, so a killed add can be removed");
assert!(!plan.destination.with_file_name(".cli-git-worktree-copy-stage").exists(), "the clone rung stages nothing");
let mut runner = no_runner();
let result: LadderResult = ladder.finish(FAILED, None, &mut runner, &git_context(), &mut std::io::sink());
assert_eq!(result, LadderResult { git: FAILED, carried: None });
assert!(!plan.destination.exists(), "the empty subvolume is removed after a failed Git");
assert!(!stage_claims_exist(repo.join(".git").as_path()).expect("claims"), "the record is released");
remove(root.as_path());
}
#[test]
fn btrfs_an_eligible_source_runs_git_without_a_checkout_and_a_failure_releases_the_claim() {
let Some(root) = btrfs_fixture("run-snapshot") else { return };
let repo: PathBuf = subvolume_repository(root.as_path());
let plan = plan_to(root.join("topic"));
let ladder: Ladder = begin_ladder(Some(&plan), &git_context(), &main_identity(repo.as_path()));
assert_eq!(ladder.first_step(), GitStep::WithoutCheckout(plan.insert_at));
assert!(!plan.destination.exists(), "a snapshot rung makes no subvolume before Git");
assert!(stage_claims_exist(repo.join(".git").as_path()).expect("claims"), "the stage name is claimed durably");
let mut runner = no_runner();
let result: LadderResult = ladder.finish(FAILED, None, &mut runner, &git_context(), &mut std::io::sink());
assert_eq!(result, LadderResult { git: FAILED, carried: None });
assert!(!stage_claims_exist(repo.join(".git").as_path()).expect("claims"), "the claim is released");
remove(root.as_path());
}
#[test]
fn btrfs_a_stage_is_discarded_only_while_it_is_the_one_that_was_made() {
let Some(root) = btrfs_fixture("run-discard-identity") else { return };
let base: PathBuf = std::fs::canonicalize(root.as_path()).expect("canonical");
let made = |name: &str| -> (PathBuf, crate::fs_beneath::ObjectId) {
let stage: PathBuf = base.join(name);
crate::fs_btrfs_ioctl::subvolume_create_at(stage.as_path()).expect("stage");
std::fs::write(stage.join("file"), b"x").expect("content");
let parent = crate::fs_beneath::open_root(base.as_path()).expect("parent");
let id = crate::fs_beneath::identity_at(&parent, std::ffi::OsStr::new(name)).expect("identity");
return (stage, id);
};
let (stage, id) = made("stage-one");
discard_stage(stage.as_path(), Some(id));
assert!(!stage.exists(), "the stage that was made goes");
let (other, id_two) = made("stage-two");
std::fs::create_dir(base.join("stage-three")).expect("somebody's directory");
std::fs::write(base.join("stage-three/theirs"), b"theirs").expect("their file");
discard_stage(base.join("stage-three").as_path(), Some(id_two));
assert!(base.join("stage-three/theirs").exists(), "a directory that is not the one made stays");
discard_stage(other.as_path(), None);
assert!(other.join("file").exists(), "an unidentified stage stays");
remove(root.as_path());
}