Sebastian Thielmake fmte22080e3 years agoHistory
285 lines · 10.0 KB · Rust
RawDownload
mod options {    mod ssh_command {        use crate::client::ssh::{connect::Options, ProgramKind};         #[test]        fn no_field_means_ssh() {            assert_eq!(Options::default().ssh_command(), "ssh");        }         #[test]        fn command_field_determines_ssh_command() {            assert_eq!(                Options {                    command: Some("field-value".into()),                    ..Default::default()                }                .ssh_command(),                "field-value"            );            assert_eq!(                Options {                    command: Some("field-value".into()),                    kind: Some(ProgramKind::TortoisePlink),                    ..Default::default()                }                .ssh_command(),                "field-value"            );        }         #[test]        fn kind_serves_as_fallback() {            assert_eq!(                Options {                    kind: Some(ProgramKind::TortoisePlink),                    ..Default::default()                }                .ssh_command(),                "tortoiseplink.exe"            );        }    }} mod program_kind {    mod from_os_str {        use std::ffi::OsStr;         use crate::client::ssh::ProgramKind;         #[test]        fn known_variants_are_derived_from_basename() {            for name_or_path in [                "ssh",                "ssh.exe",                "SSH",                "SSH.exe",                "/bin/ssh",                "/bin/SSH",                #[cfg(windows)]                "c:\\bin\\ssh.exe",            ] {                assert_eq!(                    ProgramKind::from(OsStr::new(name_or_path)),                    ProgramKind::Ssh,                    "{name_or_path:?} could not be identified correctly"                );            }            assert_eq!(                ProgramKind::from(OsStr::new("TortoisePlink.exe")),                ProgramKind::TortoisePlink            );            assert_eq!(ProgramKind::from(OsStr::new("putty")), ProgramKind::Putty);            assert_eq!(                ProgramKind::from(OsStr::new("../relative/Plink.exe")),                ProgramKind::Plink            );        }         #[test]        fn unknown_variants_fallback_to_simple() {            assert_eq!(                ProgramKind::from(OsStr::new("something-unknown-that-does-not-exist-for-sure-foobar")),                ProgramKind::Simple,                "in theory, we could fail right here but we don't and leave non-existing programs to fail during handshake"            );        }         #[test]        fn ssh_disguised_within_a_script_cannot_be_detected_due_to_invocation_with_dash_g() {            assert_eq!(                ProgramKind::from(OsStr::new("ssh -VVV")),                ProgramKind::Simple,                "we don't execute the command here but assume simple, even though we could determine it's ssh if we would do what git does here"            );        }    }     mod prepare_invocation {        use std::ffi::OsStr;         use crate::{            client::{ssh, ssh::ProgramKind},            Protocol,        };         #[test]        fn ssh() {            for (url, protocol, expected) in [                ("ssh://user@host:42/p", Protocol::V1, &["ssh", "-p42", "user@host"][..]),                ("ssh://user@host/p", Protocol::V1, &["ssh", "user@host"][..]),                ("ssh://host/p", Protocol::V1, &["ssh", "host"][..]),                (                    "ssh://user@host:42/p",                    Protocol::V2,                    &["ssh", "-o", "SendEnv=GIT_PROTOCOL", "-p42", "user@host"][..],                ),                (                    "ssh://user@host/p",                    Protocol::V2,                    &["ssh", "-o", "SendEnv=GIT_PROTOCOL", "user@host"][..],                ),                (                    "ssh://host/p",                    Protocol::V2,                    &["ssh", "-o", "SendEnv=GIT_PROTOCOL", "host"][..],                ),            ] {                assert_eq!(call_args(ProgramKind::Ssh, url, protocol), quoted(expected));            }        }         #[test]        fn tortoise_plink_has_batch_command() {            assert_eq!(                call_args(ProgramKind::TortoisePlink, "ssh://user@host:42/p", Protocol::V2),                quoted(&["tortoiseplink.exe", "-batch", "-P", "42", "user@host"])            );        }         #[test]        fn port_for_all() {            for kind in [ProgramKind::TortoisePlink, ProgramKind::Plink, ProgramKind::Putty] {                assert!(call_args(kind, "ssh://user@host:43/p", Protocol::V2).ends_with(r#""-P" "43" "user@host""#));            }        }         #[test]        fn simple_cannot_handle_any_arguments() {            match try_call(ProgramKind::Simple, "ssh://user@host:42/p", Protocol::V2) {                Err(ssh::invocation::Error { .. }) => {}                _ => panic!("BUG: unexpected outcome"),            }            assert_eq!(                call_args(ProgramKind::Simple, "ssh://user@host/p", Protocol::V2),                quoted(&["simple", "user@host"]),                "simple can only do simple invocations"            );        }         #[test]        fn ssh_env_v2() {            let prepare = call(ProgramKind::Ssh, "ssh://host/p", Protocol::V2);            assert_eq!(                prepare.env,                &[                    ("GIT_PROTOCOL".into(), "version=2".into()),                    ("LANG".into(), "C".into()),                    ("LC_ALL".into(), "C".into())                ]            );            assert!(!prepare.use_shell);        }         #[test]        fn disallow_shell_is_honored() -> Result {            let url = git_url::parse("ssh://host/path".into()).expect("valid url");             let disallow_shell = false;            let prepare =                ProgramKind::Ssh.prepare_invocation(OsStr::new("echo hi"), &url, Protocol::V1, disallow_shell)?;            assert!(prepare.use_shell, "shells are used when needed");             let disallow_shell = true;            let prepare =                ProgramKind::Ssh.prepare_invocation(OsStr::new("echo hi"), &url, Protocol::V1, disallow_shell)?;            assert!(                !prepare.use_shell,                "but we can enforce it not to be used as well for historical reasons"            );            Ok(())        }         fn quoted(input: &[&str]) -> String {            input.iter().map(|s| format!("\"{s}\"")).collect::<Vec<_>>().join(" ")        }        fn try_call(            kind: ProgramKind,            url: &str,            version: Protocol,        ) -> std::result::Result<git_command::Prepare, ssh::invocation::Error> {            let ssh_cmd = kind.exe().unwrap_or_else(|| OsStr::new("simple"));            let url = git_url::parse(url.into()).expect("valid url");            kind.prepare_invocation(ssh_cmd, &url, version, false)        }        fn call(kind: ProgramKind, url: &str, version: Protocol) -> git_command::Prepare {            try_call(kind, url, version).expect("no error")        }        fn call_args(kind: ProgramKind, url: &str, version: Protocol) -> String {            format!("{:?}", std::process::Command::from(call(kind, url, version)))        }         type Result = std::result::Result<(), ssh::invocation::Error>;    }     mod line_to_err {        use std::io::ErrorKind;         use crate::client::ssh::ProgramKind;         #[test]        fn all() {            for (kind, line, expected) in [                (                    ProgramKind::Ssh,                    "byron@github.com: Permission denied (publickey).",                    ErrorKind::PermissionDenied,                ),                (                    ProgramKind::Ssh,                    "ssh: Could not resolve hostname hostfoobar: nodename nor servname provided, or not known",                    ErrorKind::ConnectionRefused,                ),                (                    ProgramKind::Ssh,                    "ssh: connect to host example.org port 22: No route to host",                    ErrorKind::NotFound,                ),                // connection closed by remote on windows                (                    ProgramKind::Ssh,                    "banner exchange: Connection to 127.0.0.1 port 61024: Software caused connection abort",                    ErrorKind::NotFound,                ),                // connection closed by remote on unix                (                    ProgramKind::Ssh,                    "Connection closed by 127.0.0.1 port 8888", //                    ErrorKind::NotFound,                ),                // this kind is basically unknown but we try our best, and simple equals ssh                (                    ProgramKind::Simple,                    "something permission denied something",                    ErrorKind::PermissionDenied,                ),                (                    ProgramKind::Simple,                    "something resolve hostname hostfoobar: nodename nor servname something",                    ErrorKind::ConnectionRefused,                ),                (                    ProgramKind::Simple,                    "something connect to host something",                    ErrorKind::NotFound,                ),            ] {                assert_eq!(kind.line_to_err(line.into()).map(|err| err.kind()), Ok(expected));            }        }         #[test]        fn tortoiseplink_putty_plink() {            for kind in [ProgramKind::TortoisePlink, ProgramKind::Plink, ProgramKind::Putty] {                assert_eq!(                    kind                        .line_to_err("publickey".into())                        .map(|err| err.kind()),                    Ok(std::io::ErrorKind::PermissionDenied),                    "this program pops up error messages in a window, no way to extract information from it. Maybe there is other ways to use it, 'publickey' they mention all"                );            }        }    }}