Run the stand-in ssh for tests without writing a script file
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use serde::Serialize;
|
||||
use crate::location::{Location, remote_command};
|
||||
use std::ffi::OsStr;
|
||||
use std::ffi::OsString;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
@@ -53,13 +53,14 @@ pub fn git(loc: &Location, args: &[&str]) -> Result<String, String> {
|
||||
// Tests swap in a script that acts like ssh.
|
||||
#[cfg(test)]
|
||||
if let Some(fake) = crate::test_ssh::SSH_OVERRIDE.get() {
|
||||
return git_via(fake.as_os_str(), loc, args);
|
||||
return git_via(fake, loc, args);
|
||||
}
|
||||
git_via(OsStr::new("ssh"), loc, args)
|
||||
git_via(&[OsString::from("ssh")], loc, args)
|
||||
}
|
||||
|
||||
/// Does the work of `git`, starting the program `ssh` for a remote location.
|
||||
pub fn git_via(ssh: &OsStr, loc: &Location, args: &[&str]) -> Result<String, String> {
|
||||
/// Does the work of `git`. For a remote location it starts `ssh`: the first word of `ssh` is
|
||||
/// the program and the other words come before the ssh options (tests use them).
|
||||
pub fn git_via(ssh: &[OsString], loc: &Location, args: &[&str]) -> Result<String, String> {
|
||||
let mut cmd = match loc {
|
||||
Location::Local(dir) => {
|
||||
let mut cmd = Command::new("git");
|
||||
@@ -67,7 +68,8 @@ pub fn git_via(ssh: &OsStr, loc: &Location, args: &[&str]) -> Result<String, Str
|
||||
cmd
|
||||
}
|
||||
Location::Ssh { target, path } => {
|
||||
let mut cmd = Command::new(ssh);
|
||||
let mut cmd = Command::new(&ssh[0]);
|
||||
cmd.args(&ssh[1..]);
|
||||
// Never ask for a password: gites has no terminal to ask on.
|
||||
cmd.args(["-o", "BatchMode=yes", "-o", "ConnectTimeout=10"]);
|
||||
// Later commands to the same server reuse one connection for a while. Windows ssh
|
||||
@@ -294,7 +296,7 @@ mod tests {
|
||||
#[test]
|
||||
fn reports_a_missing_ssh_program() {
|
||||
let loc = Location::Ssh { target: "myserver".into(), path: "/x".into() };
|
||||
let err = git_via(OsStr::new("/no/such/ssh"), &loc, &["status"]).unwrap_err();
|
||||
let err = git_via(&[OsString::from("/no/such/ssh")], &loc, &["status"]).unwrap_err();
|
||||
assert!(err.starts_with("could not run ssh:"), "{err}");
|
||||
}
|
||||
}
|
||||
|
||||
+22
-19
@@ -1,25 +1,28 @@
|
||||
//! A stand-in for ssh, so tests can run the remote code path without a server.
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::ffi::OsString;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
/// The program `git::git` starts instead of `ssh` while tests run.
|
||||
pub static SSH_OVERRIDE: OnceLock<PathBuf> = OnceLock::new();
|
||||
/// The words `git::git` starts instead of `ssh` while tests run: a program, then its arguments.
|
||||
pub static SSH_OVERRIDE: OnceLock<Vec<OsString>> = OnceLock::new();
|
||||
|
||||
/// Writes (once per test run) a script that acts like ssh: it skips the `-o` options,
|
||||
/// the `--` and the target, then runs the command on this machine. Returns its path.
|
||||
pub fn fake_ssh() -> PathBuf {
|
||||
SSH_OVERRIDE
|
||||
.get_or_init(|| {
|
||||
let path = std::env::temp_dir().join(format!("gites-fake-ssh-{}", std::process::id()));
|
||||
let script = "#!/bin/sh\nwhile [ \"$1\" = \"-o\" ]; do shift 2; done\nshift 2\nexec sh -c \"$1\"\n";
|
||||
std::fs::write(&path, script).unwrap();
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o755)).unwrap();
|
||||
}
|
||||
path
|
||||
})
|
||||
.clone()
|
||||
/// The shell script that acts like ssh. It checks the arguments the way a real ssh would
|
||||
/// need them (so a wrong argument list fails a test), skips the options and the target,
|
||||
/// then runs the command on this machine.
|
||||
const SCRIPT: &str = r#"
|
||||
ok=
|
||||
while [ "$1" = "-o" ]; do
|
||||
[ "$2" = "BatchMode=yes" ] && ok=1
|
||||
shift 2
|
||||
done
|
||||
[ -n "$ok" ] || { echo "fake ssh: BatchMode=yes is missing" >&2; exit 98; }
|
||||
[ "$1" = "--" ] || { echo "fake ssh: expected -- before the target" >&2; exit 99; }
|
||||
shift 2
|
||||
exec sh -c "$1"
|
||||
"#;
|
||||
|
||||
/// Makes `git::git` use the stand-in for the rest of the test run. No file is written:
|
||||
/// the script is given to `sh` on its command line.
|
||||
pub fn fake_ssh() {
|
||||
SSH_OVERRIDE.get_or_init(|| ["sh", "-c", SCRIPT, "fake-ssh"].map(OsString::from).to_vec());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user