use super::*;
use crate::test_support::{fixture, git, remove};
use std::path::Path;
use std::time::Duration;
fn argv(parts: &[&str]) -> Vec<OsString> {
return parts.iter().map(OsString::from).collect();
}
fn fixture_environment() -> Vec<(OsString, OsString)> {
let mut environment: Vec<(OsString, OsString)> = [
("PATH", "/usr/bin:/bin"),
("GIT_CONFIG_NOSYSTEM", "1"),
("GIT_CONFIG_GLOBAL", "/nonexistent-global-config"),
("GIT_AUTHOR_NAME", "Fixture"),
("GIT_AUTHOR_EMAIL", "fixture@example.invalid"),
("GIT_COMMITTER_NAME", "Fixture"),
("GIT_COMMITTER_EMAIL", "fixture@example.invalid"),
]
.iter()
.map(|(name, value)| {
return (OsString::from(name), OsString::from(value));
})
.collect();
environment.extend(crate::test_support::scratch_environment());
return environment;
}
fn push_git(root: &Path) -> PushGit {
return PushGit {
real_git: PathBuf::from("/usr/bin/git"),
cwd: root.to_path_buf(),
environment: fixture_environment(),
lfs: false,
};
}
fn repository(name: &str) -> PathBuf {
let root = fixture(name);
git(&root, &["init", "--quiet", "--initial-branch=main"]);
commit(&root, "base");
return root;
}
fn commit(root: &Path, message: &str) -> String {
let message_argument = format!("--message={message}");
git(
root,
&[
"commit",
"--quiet",
"--allow-empty",
message_argument.as_str(),
],
);
return head_of(root, "HEAD");
}
fn head_of(root: &Path, revision: &str) -> String {
return String::from_utf8_lossy(&git(root, &["rev-parse", revision]).stdout)
.trim()
.to_owned();
}
#[test]
fn a_failed_query_names_its_arguments() {
let root = repository("sf-query-failure");
let failure = git_output(
&push_git(&root),
&argv(&["rev-parse", "--verify", "no-such-ref^{commit}"]),
)
.expect_err("an unknown ref fails");
match &failure {
SingleFlightError::Git {
arguments, code, ..
} => {
assert_eq!(arguments, "rev-parse --verify no-such-ref^{commit}");
assert_eq!(*code, Some(128));
}
other => panic!("expected a Git failure, got {other}"),
}
assert!(
failure
.to_string()
.starts_with("git rev-parse --verify no-such-ref^{commit} exited with Some(128): "),
"{failure}"
);
remove(&root);
}
#[test]
fn a_stalled_query_is_reported_instead_of_waited_for() {
use std::os::unix::fs::PermissionsExt;
let root = fixture("sf-stalled-query");
let fake = root.join("fake-git");
std::fs::write(&fake, "#!/bin/sh\nexec sleep 8\n").expect("fake git");
std::fs::set_permissions(&fake, std::fs::Permissions::from_mode(0o755)).expect("mode");
let mut git = push_git(&root);
git.real_git = fake;
git.environment.push((
OsString::from(crate::bounded_push::PUSH_DEADLINE_VARIABLE),
OsString::from("1"),
));
let started = std::time::Instant::now();
let failure = git_output(&git, &argv(&["rev-parse", "HEAD"])).expect_err("stalls");
assert!(started.elapsed() < Duration::from_secs(7), "{:?}", started.elapsed());
assert!(
matches!(&failure, SingleFlightError::TimedOut { arguments, seconds }
if arguments == "rev-parse HEAD" && *seconds == 1),
"{failure}"
);
remove(&root);
}