coliru

A minimal, flexible, dotfile installer
git clone https://git.ashermorgan.net/coliru/
Log | Files | Refs | README

commit c9c1afb4784b1d3daa651f4ac23e4749633cf65b
parent c654f6f8b1ab8033d096b4d2500b56511139e2b0
Author: Asher Morgan <59518073+ashermorgan@users.noreply.github.com>
Date:   Mon,  8 Jul 2024 16:34:04 -0700

Hide SCP stdout and add more SSH tests

Diffstat:
MCargo.lock | 45+++++++++++++++++++++++++++++++++++++++++++++
MCargo.toml | 3+++
Msrc/ssh.rs | 37++++++++++++++++++++++++++++++++++++-
Mtests/ssh.rs | 48++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 132 insertions(+), 1 deletion(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -3,6 +3,15 @@ version = 3 [[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] name = "anstream" version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -116,6 +125,7 @@ dependencies = [ "anyhow", "clap", "colored", + "regex", "serde", "serde_yaml", "shellexpand", @@ -255,6 +265,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -290,6 +306,35 @@ dependencies = [ ] [[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] name = "rustix" version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml @@ -11,3 +11,6 @@ serde = { version = "1.0", features = ["derive"] } serde_yaml = "0.9" shellexpand = "3.0" tempfile = "3" + +[dev-dependencies] +regex = "1.10.5" diff --git a/src/ssh.rs b/src/ssh.rs @@ -16,7 +16,7 @@ use std::env; use shellexpand::tilde_with_context; use std::fs::{read_dir, remove_dir_all}; use std::path::{MAIN_SEPARATOR_STR, Path, PathBuf}; -use std::process::Command; +use std::process::{Command, Stdio}; use super::local::copy_file; /// Makes a relative path absolute according to a certain base directory @@ -141,6 +141,7 @@ fn send_dir(src: &str, dst: &str, host: &str) -> Result<()> { })?.path(); let mut cmd = Command::new("scp"); + cmd.stdout(Stdio::null()); if env::var("COLIRU_TEST").is_ok() { cmd.args(["-o", "StrictHostKeyChecking=no", "-P", "2222"]); @@ -187,6 +188,7 @@ mod tests { use super::*; use crate::test_utils::{SSH_HOST, read_file, setup_integration, write_file}; + use regex::Regex; use std::fs; #[test] @@ -407,6 +409,24 @@ mod tests { } #[test] + fn test_send_dir_bad_host() { + let tmp = setup_integration("test_send_dir_bad_host"); + + write_file(&tmp.local.join("foo"), "contents of foo"); + write_file(&tmp.local.join("bar"), "contents of bar"); + + let dst = "~/test_send_dir_bad_host"; + let bad_host = "fake@coliru.test.internal"; // Will be a DNS error + + let result = send_dir(tmp.local.to_str().unwrap(), dst, bad_host); + let expected = Regex::new("SCP terminated unsuccessfully: \ + exit (status|code): \\d+").unwrap(); + + assert_eq!(result.is_ok(), false); + assert_eq!(expected.is_match(&result.unwrap_err().to_string()), true); + } + + #[test] #[cfg(target_family = "unix")] fn test_send_command_basic() { let tmp = setup_integration("test_send_command_basic"); @@ -421,4 +441,19 @@ mod tests { assert_eq!(dst_real.exists(), true); assert_eq!(read_file(&dst_real), "contents of foo\n"); } + + #[test] + fn test_send_command_bad_host() { + let _tmp = setup_integration("test_send_command_bad_host"); + + let cmd = format!("echo Hello World"); + let bad_host = "fake@coliru.test.internal"; // Will be a DNS error + + let result = send_command(&cmd, bad_host); + let expected = Regex::new("SSH terminated unsuccessfully: \ + exit (status|code): \\d+").unwrap(); + + assert_eq!(result.is_ok(), false); + assert_eq!(expected.is_match(&result.unwrap_err().to_string()), true); + } } diff --git a/tests/ssh.rs b/tests/ssh.rs @@ -5,6 +5,7 @@ mod test_utils; use test_utils::*; +use regex::Regex; use std::fs::remove_file; #[test] @@ -282,3 +283,50 @@ foo! assert_eq!(foo_contents, "foo!\n"); assert_eq!(log_contents, "script.sh called with arg1 linux\n"); } + +#[test] +fn test_ssh_bad_host() { + // Use setup_e2e_local instead of setup_e2e_ssh to avoid regular --host + let (_dirs, mut cmd) = setup_e2e_local("test_ssh_bad_host"); + let bad_host = "fake@coliru.test.internal"; // Will be a DNS error + cmd.args(["manifest.yml", "-t", "linux", "--host", bad_host]); + + // setup_e2e_local will install to CWD instead of $HOME on Windows: + let expected_stdout = Regex::new(&format!("\ +\\[1/3] Copy gitconfig to {bad_host}:~/(.coliru/)?.gitconfig +\\[2/3] Copy foo to {bad_host}:~/.coliru/foo +\\[2/3] Copy bashrc to {bad_host}:~/(.coliru/)?.bashrc +\\[2/3] Copy vimrc to {bad_host}:~/(.coliru/)?.vimrc +\\[2/3] Copy script.sh to {bad_host}:~/.coliru/script.sh +\\[2/3] Run sh script.sh arg1 linux on {bad_host} +")).unwrap(); + // Exact std output varies significantly across machines; + let expected_stderr = Regex::new("\ +ssh: Could not resolve hostname coliru.test.internal: [\\w \\.]+\r?( +[\\w :]+\r?)? + Error: Failed to transfer staged files: SCP terminated unsuccessfully: \ + exit (status|code): \\d+ +ssh: Could not resolve hostname coliru.test.internal: [\\w \\.]+\r?( +[\\w :]+\r?)? + Error: Failed to transfer staged files: SCP terminated unsuccessfully: \ + exit (status|code): \\d+ +ssh: Could not resolve hostname coliru.test.internal: [\\w \\.]+\r?( +[\\w :]+\r?)? + Error: Failed to transfer staged files: SCP terminated unsuccessfully: \ + exit (status|code): \\d+ +ssh: Could not resolve hostname coliru.test.internal: [\\w \\.]+\r?( +[\\w :]+\r?)? + Error: Failed to transfer staged files: SCP terminated unsuccessfully: \ + exit (status|code): \\d+ +ssh: Could not resolve hostname coliru.test.internal: [\\w \\.]+\r?( +[\\w :]+\r?)? + Error: Failed to transfer staged files: SCP terminated unsuccessfully: \ + exit (status|code): \\d+ +ssh: Could not resolve hostname coliru.test.internal: [\\w \\.]+\r? + Error: SSH terminated unsuccessfully: exit (status|code): \\d+ +").unwrap(); + let (stdout, stderr, exitcode) = run_command(&mut cmd); + assert_eq!(expected_stderr.is_match(&stderr), true); + assert_eq!(expected_stdout.is_match(&stdout), true); + assert_eq!(exitcode, Some(1)); +}