Sebastian Thielthanks clippy749ceba5 years agoHistory
297 lines · 8.4 KB · Rust
RawDownload
use crate::fixture_bytes;use bstr::ByteSlice;use git_transport::{    client::{self, git, Transport, TransportV2Ext},    Protocol, Service,};use std::{    cell::RefCell,    io::{BufRead, Read, Write},    ops::Deref,    rc::Rc,}; #[test]fn handshake_v1_and_request() -> crate::Result {    let mut out = Vec::new();    let server_response = fixture_bytes("v1/clone.response");    let mut c = git::Connection::new(        server_response.as_slice(),        &mut out,        Protocol::V1,        "/foo.git",        Some(("example.org", None)),        git::ConnectMode::Daemon,    );    assert!(c.is_stateful(), "tcp connections are stateful");    assert_eq!(c.to_url(), "file:///foo.git");    let mut res = c.handshake(Service::UploadPack)?;    assert_eq!(res.actual_protocol, Protocol::V1);    assert_eq!(        res.capabilities            .iter()            .map(|c| (c.name().to_owned(), c.value().map(ToOwned::to_owned)))            .collect::<Vec<_>>(),        [            ("multi_ack", None),            ("thin-pack", None),            ("side-band", None),            ("side-band-64k", None),            ("ofs-delta", None),            ("shallow", None),            ("deepen-since", None),            ("deepen-not", None),            ("deepen-relative", None),            ("no-progress", None),            ("include-tag", None),            ("multi_ack_detailed", None),            ("symref", Some("HEAD:refs/heads/master")),            ("object-format", Some("sha1")),            ("agent", Some("git/2.28.0"))        ]        .iter()        .map(|(n, v)| (            n.as_bytes().as_bstr().to_owned(),            v.map(|v| v.as_bytes().as_bstr().to_owned())        ))        .collect::<Vec<_>>()    );    let refs = res        .refs        .as_mut()        .expect("v1 protocol provides refs")        .lines()        .flat_map(Result::ok)        .collect::<Vec<_>>();    assert_eq!(        refs,        vec![            "808e50d724f604f69ab93c6da2919c014667bedb HEAD",            "808e50d724f604f69ab93c6da2919c014667bedb refs/heads/master"        ]    );    drop(res);     let writer = c.request(client::WriteMode::Binary, client::MessageKind::Flush)?;    assert_eq!(writer.into_read()?.lines().next().expect("exactly one line")?, "NAK");     let mut writer = c.request(        client::WriteMode::OneLfTerminatedLinePerWriteCall,        client::MessageKind::Text(b"done"),    )?;     writer.write_all(b"hello")?;    writer.write_all(b"world")?;     let mut reader = writer.into_read()?;    let messages = Rc::new(RefCell::new(Vec::<String>::new()));    reader.set_progress_handler(Some(Box::new({        let sb = messages.clone();        move |is_err, data| {            assert!(!is_err);            sb.deref()                .borrow_mut()                .push(std::str::from_utf8(data).expect("valid utf8").to_owned())        }    })));    let mut pack = Vec::new();    reader.read_to_end(&mut pack)?;    assert_eq!(pack.len(), 876, "we receive the whole pack…");     drop(reader);    let sidebands = Rc::try_unwrap(messages).expect("no other handle").into_inner();    assert_eq!(sidebands.len(), 6, "…along with some status messages");    c.close()?;     assert_eq!(        out.as_slice().as_bstr(),        b"002egit-upload-pack /foo.git\0host=example.org\00000000ahello\n\        000aworld\n\        0009done\n0000"            .as_bstr(),        "it sends the correct request"    );    Ok(())} #[test]fn handshake_v1_process_mode() -> crate::Result {    let mut out = Vec::new();    let server_response = fixture_bytes("v1/clone.response");    let mut c = git::Connection::new(        server_response.as_slice(),        &mut out,        Protocol::V1,        "/foo.git",        Some(("example.org", None)),        git::ConnectMode::Process,    );    c.handshake(Service::UploadPack)?;     assert_eq!(        out.as_slice().as_bstr(),        b"".as_bstr(),        "it sends no introductory line to help the daemon start the right thing"    );    Ok(())} #[test]fn handshake_v2_and_request() -> crate::Result {    let mut out = Vec::new();    let input = fixture_bytes("v2/clone.response");    let mut c = git::Connection::new(        input.as_slice(),        &mut out,        Protocol::V2,        "/bar.git",        Some(("example.org", None)),        git::ConnectMode::Daemon,    );    assert!(        c.is_stateful(),        "tcp connections are stateful despite the protocol version"    );    let res = c.handshake(Service::UploadPack)?;    assert_eq!(res.actual_protocol, Protocol::V2);    assert!(        res.refs.is_none(),        "V2 needs a separate trip for getting refs (with additional capabilities)"    );    assert_eq!(        res.capabilities            .iter()            .map(|c| (c.name().to_owned(), c.value().map(ToOwned::to_owned)))            .collect::<Vec<_>>(),        [            ("agent", Some("git/2.28.0")),            ("ls-refs", None),            ("fetch", Some("shallow")),            ("server-option", None),            ("object-format", Some("sha1"))        ]        .iter()        .map(|(k, v)| (k.as_bytes().into(), v.map(|v| v.as_bytes().into())))        .collect::<Vec<_>>()    );    drop(res);     let res = c.invoke(        "ls-refs",        [("agent", Some("git/2.28.0")), ("object-format", Some("sha1"))]            .iter()            .cloned(),        Some(            [                "peel",                "symrefs",                "ref-prefix HEAD",                "ref-prefix refs/heads/",                "ref-prefix refs/tags",            ]            .iter()            .map(|s| s.as_bytes().as_bstr().to_owned()),        ),    )?;     assert_eq!(        res.lines().collect::<Result<Vec<_>, _>>()?,        vec![            "808e50d724f604f69ab93c6da2919c014667bedb HEAD symref-target:refs/heads/master".to_string(),            "808e50d724f604f69ab93c6da2919c014667bedb refs/heads/master".into()        ]    );     let mut res = c.invoke(        "fetch",        [            ("agent", Some("git/2.28.0")),            ("something-without-value", None),            ("object-format", Some("sha1")),        ]        .iter()        .cloned(),        Some(            [                "thin-pack",                "ofs-delta",                "want 808e50d724f604f69ab93c6da2919c014667bedb",                "done",            ]            .iter()            .map(|s| s.as_bytes().as_bstr().to_owned()),        ),    )?;     let mut line = String::new();    res.read_line(&mut line)?;    assert_eq!(line, "packfile\n");     let messages = Rc::new(RefCell::new(Vec::<String>::new()));    res.set_progress_handler(Some(Box::new({        let sb = messages.clone();        move |is_err, data| {            assert!(!is_err);            sb.deref()                .borrow_mut()                .push(std::str::from_utf8(data).expect("valid utf8").to_owned())        }    })));     let mut pack = Vec::new();    res.read_to_end(&mut pack)?;    assert_eq!(pack.len(), 876);     drop(res);    let messages = Rc::try_unwrap(messages).expect("no other handle").into_inner();    assert_eq!(messages.len(), 4);    c.close()?;     assert_eq!(        out.as_slice().as_bstr(),        b"0039git-upload-pack /bar.git\0host=example.org\0\0version=2\00014command=ls-refs0015agent=git/2.28.00017object-format=sha100010009peel000csymrefs0014ref-prefix HEAD001bref-prefix refs/heads/0019ref-prefix refs/tags00000012command=fetch0015agent=git/2.28.0001csomething-without-value0017object-format=sha10001000ethin-pack000eofs-delta0032want 808e50d724f604f69ab93c6da2919c014667bedb0009done00000000"            .as_bstr(),        "it sends the correct request, including the adjusted version"    );    Ok(())} #[test]fn handshake_v2_downgrade_to_v1() -> crate::Result {    let mut out = Vec::new();    let input = fixture_bytes("v1/clone.response");    let mut c = git::Connection::new(        input.as_slice(),        &mut out,        Protocol::V2,        "/bar.git",        Some(("example.org", None)),        git::ConnectMode::Daemon,    );    let res = c.handshake(Service::UploadPack)?;    assert_eq!(res.actual_protocol, Protocol::V1);    assert!(        res.refs.is_some(),        "V1 downgrades 'just happen', so we should have refs as part of the handshake"    );    drop(res);     assert_eq!(c.desired_protocol_version(), Protocol::V2);    Ok(())}