History

[git-protocol] move everything into `blocking_io` for later translation…

…into async-io, as usual.

Sebastian Thiel committed 5 years ago

Commit fa033741 parent 0d39b5d12 files · +295 −254Browse files

Showing the changes to git-protocol/src/fetch/blocking_io/tests (4 of 12 files). Show all

Unified · Split

4 files
  1. git-protocol/src/fetch/blocking_io/tests/arguments.rs +236 −0
  2. git-protocol/src/fetch/blocking_io/tests/command.rs +165 −0
  3. git-protocol/src/fetch/blocking_io/tests/mod.rs +3 −0
  4. git-protocol/src/fetch/blocking_io/tests/refs.rs +108 −0
git-protocol/src/fetch/blocking_io/tests/arguments.rs+236−0
@@ -0,0 +1,236 @@
1use crate::fetch;
2use bstr::ByteSlice;
3use git_transport::{
4 client,
5 client::{Error, Identity, MessageKind, RequestWriter, SetServiceResponse, WriteMode},
6 Protocol, Service,
7};
8use std::io;
9
10fn arguments_v1(features: impl IntoIterator<Item = &'static str>) -> fetch::Arguments {
11 fetch::Arguments::new(Protocol::V1, features.into_iter().map(|n| (n, None)).collect())
12}
13
14fn arguments_v2(features: impl IntoIterator<Item = &'static str>) -> fetch::Arguments {
15 fetch::Arguments::new(Protocol::V2, features.into_iter().map(|n| (n, None)).collect())
16}
17
18struct Transport<T: client::Transport> {
19 inner: T,
20 stateful: bool,
21}
22
23impl<T: client::Transport> client::Transport for Transport<T> {
24 fn handshake(&mut self, service: Service) -> Result<SetServiceResponse<'_>, Error> {
25 self.inner.handshake(service)
26 }
27
28 fn set_identity(&mut self, identity: Identity) -> Result<(), Error> {
29 self.inner.set_identity(identity)
30 }
31
32 fn request(&mut self, write_mode: WriteMode, on_into_read: MessageKind) -> Result<RequestWriter<'_>, Error> {
33 self.inner.request(write_mode, on_into_read)
34 }
35
36 fn close(&mut self) -> Result<(), Error> {
37 self.inner.close()
38 }
39
40 fn to_url(&self) -> String {
41 self.inner.to_url()
42 }
43
44 fn desired_protocol_version(&self) -> Protocol {
45 self.inner.desired_protocol_version()
46 }
47
48 fn is_stateful(&self) -> bool {
49 self.stateful
50 }
51}
52
53fn transport(
54 out: &mut Vec<u8>,
55 stateful: bool,
56) -> Transport<git_transport::client::git::Connection<io::Cursor<Vec<u8>>, &mut Vec<u8>>> {
57 Transport {
58 inner: git_transport::client::git::Connection::new(
59 io::Cursor::new(Vec::new()),
60 out,
61 Protocol::V1, // does not matter
62 b"does/not/matter".as_bstr().to_owned(),
63 None::<(&str, _)>,
64 git_transport::client::git::ConnectMode::Process, // avoid header to be sent
65 ),
66 stateful,
67 }
68}
69
70fn id(hex: &str) -> git_hash::ObjectId {
71 git_hash::ObjectId::from_hex(hex.as_bytes()).expect("expect valid hex id")
72}
73
74mod v1 {
75 use crate::fetch::blocking_io::tests::arguments::{arguments_v1, id, transport};
76 use bstr::ByteSlice;
77
78 #[test]
79 fn haves_and_wants_for_clone() {
80 let mut out = Vec::new();
81 let mut t = transport(&mut out, true);
82 let mut arguments = arguments_v1(["feature-a", "feature-b"].iter().cloned());
83
84 arguments.want(id("7b333369de1221f9bfbbe03a3a13e9a09bc1c907"));
85 arguments.want(id("ff333369de1221f9bfbbe03a3a13e9a09bc1ffff"));
86 arguments.send(&mut t, true).expect("sending to buffer to work");
87 assert_eq!(
88 out.as_bstr(),
89 b"0046want 7b333369de1221f9bfbbe03a3a13e9a09bc1c907 feature-a feature-b
900032want ff333369de1221f9bfbbe03a3a13e9a09bc1ffff
9100000009done
92"
93 .as_bstr()
94 );
95 }
96
97 #[test]
98 fn haves_and_wants_for_fetch_stateless() {
99 let mut out = Vec::new();
100 let mut t = transport(&mut out, false);
101 let mut arguments = arguments_v1(["feature-a", "shallow", "deepen-since", "deepen-not"].iter().copied());
102
103 arguments.deepen(1);
104 arguments.shallow(id("7b333369de1221f9bfbbe03a3a13e9a09bc1c9ff"));
105 arguments.want(id("7b333369de1221f9bfbbe03a3a13e9a09bc1c907"));
106 arguments.deepen_since(12345);
107 arguments.deepen_not("refs/heads/main".into());
108 arguments.have(id("0000000000000000000000000000000000000000"));
109 arguments.send(&mut t, false).expect("sending to buffer to work");
110
111 arguments.have(id("1111111111111111111111111111111111111111"));
112 arguments.send(&mut t, true).expect("sending to buffer to work");
113 assert_eq!(
114 out.as_bstr(),
115 b"005cwant 7b333369de1221f9bfbbe03a3a13e9a09bc1c907 feature-a shallow deepen-since deepen-not
1160035shallow 7b333369de1221f9bfbbe03a3a13e9a09bc1c9ff
117000ddeepen 1
1180017deepen-since 12345
119001fdeepen-not refs/heads/main
12000000032have 0000000000000000000000000000000000000000
1210000005cwant 7b333369de1221f9bfbbe03a3a13e9a09bc1c907 feature-a shallow deepen-since deepen-not
1220035shallow 7b333369de1221f9bfbbe03a3a13e9a09bc1c9ff
123000ddeepen 1
1240017deepen-since 12345
125001fdeepen-not refs/heads/main
12600000032have 1111111111111111111111111111111111111111
1270009done
128"
129 .as_bstr()
130 );
131 }
132
133 #[test]
134 fn haves_and_wants_for_fetch_stateful() {
135 let mut out = Vec::new();
136 let mut t = transport(&mut out, true);
137 let mut arguments = arguments_v1(["feature-a", "shallow"].iter().copied());
138
139 arguments.deepen(1);
140 arguments.want(id("7b333369de1221f9bfbbe03a3a13e9a09bc1c907"));
141 arguments.have(id("0000000000000000000000000000000000000000"));
142 arguments.send(&mut t, false).expect("sending to buffer to work");
143
144 arguments.have(id("1111111111111111111111111111111111111111"));
145 arguments.send(&mut t, true).expect("sending to buffer to work");
146 assert_eq!(
147 out.as_bstr(),
148 b"0044want 7b333369de1221f9bfbbe03a3a13e9a09bc1c907 feature-a shallow
149000ddeepen 1
15000000032have 0000000000000000000000000000000000000000
15100000032have 1111111111111111111111111111111111111111
1520009done
153"
154 .as_bstr()
155 );
156 }
157}
158
159mod v2 {
160 use crate::fetch::blocking_io::tests::arguments::{arguments_v2, id, transport};
161 use bstr::ByteSlice;
162
163 #[test]
164 fn haves_and_wants_for_clone_stateful() {
165 let mut out = Vec::new();
166 let mut t = transport(&mut out, true);
167 let mut arguments = arguments_v2(["feature-a", "shallow"].iter().copied());
168
169 arguments.deepen(1);
170 arguments.deepen_relative();
171 arguments.want(id("7b333369de1221f9bfbbe03a3a13e9a09bc1c907"));
172 arguments.want(id("ff333369de1221f9bfbbe03a3a13e9a09bc1ffff"));
173 arguments.send(&mut t, true).expect("sending to buffer to work");
174 assert_eq!(
175 out.as_bstr(),
176 b"0012command=fetch
1770001000ethin-pack
1780010include-tag
179000eofs-delta
180000ddeepen 1
1810014deepen-relative
1820032want 7b333369de1221f9bfbbe03a3a13e9a09bc1c907
1830032want ff333369de1221f9bfbbe03a3a13e9a09bc1ffff
1840009done
1850000"
186 .as_bstr(), "we filter features/capabilities without value as these apparently sholdn't be listed (remote dies otherwise)"
187 );
188 }
189
190 #[test]
191 fn haves_and_wants_for_fetch_stateless_and_stateful() {
192 for is_stateful in &[false, true] {
193 let mut out = Vec::new();
194 let mut t = transport(&mut out, *is_stateful);
195 let mut arguments = arguments_v2(Some("shallow"));
196
197 arguments.deepen(1);
198 arguments.deepen_since(12345);
199 arguments.shallow(id("7b333369de1221f9bfbbe03a3a13e9a09bc1c9ff"));
200 arguments.want(id("7b333369de1221f9bfbbe03a3a13e9a09bc1c907"));
201 arguments.deepen_not("refs/heads/main".into());
202 arguments.have(id("0000000000000000000000000000000000000000"));
203 arguments.send(&mut t, false).expect("sending to buffer to work");
204
205 arguments.have(id("1111111111111111111111111111111111111111"));
206 arguments.send(&mut t, true).expect("sending to buffer to work");
207 assert_eq!(
208 out.as_bstr(),
209 b"0012command=fetch
2100001000ethin-pack
2110010include-tag
212000eofs-delta
213000ddeepen 1
2140017deepen-since 12345
2150035shallow 7b333369de1221f9bfbbe03a3a13e9a09bc1c9ff
2160032want 7b333369de1221f9bfbbe03a3a13e9a09bc1c907
217001fdeepen-not refs/heads/main
2180032have 0000000000000000000000000000000000000000
21900000012command=fetch
2200001000ethin-pack
2210010include-tag
222000eofs-delta
223000ddeepen 1
2240017deepen-since 12345
2250035shallow 7b333369de1221f9bfbbe03a3a13e9a09bc1c9ff
2260032want 7b333369de1221f9bfbbe03a3a13e9a09bc1c907
227001fdeepen-not refs/heads/main
2280032have 1111111111111111111111111111111111111111
2290009done
2300000"
231 .as_bstr(),
232 "V2 is stateless by default, so it repeats all but 'haves' in each request"
233 );
234 }
235 }
236}
git-protocol/src/fetch/blocking_io/tests/command.rs+165−0
@@ -0,0 +1,165 @@
1mod v1 {
2 fn capabilities(input: &str) -> git_transport::client::Capabilities {
3 git_transport::client::Capabilities::from_bytes(format!("\0{}", input).as_bytes())
4 .expect("valid input capabilities")
5 .0
6 }
7
8 const GITHUB_CAPABILITIES: &str = "multi_ack thin-pack side-band ofs-delta shallow deepen-since deepen-not deepen-relative no-progress include-tag allow-tip-sha1-in-want allow-reachable-sha1-in-want no-done symref=HEAD:refs/heads/main filter agent=git/github-gdf51a71f0236";
9 mod fetch {
10 mod default_features {
11 use crate::fetch::blocking_io::tests::command::v1::{capabilities, GITHUB_CAPABILITIES};
12 use crate::fetch::{self, Command};
13
14 #[test]
15 fn it_chooses_the_best_multi_ack_and_sideband() {
16 assert_eq!(
17 Command::Fetch.default_features(
18 git_transport::Protocol::V1,
19 &capabilities("multi_ack side-band side-band-64k multi_ack_detailed")
20 ),
21 &[("side-band-64k", None), ("multi_ack_detailed", None), fetch::agent()]
22 );
23 }
24
25 #[test]
26 fn it_chooses_all_supported_non_stacking_capabilities_and_leaves_no_progress() {
27 assert_eq!(
28 Command::Fetch.default_features(git_transport::Protocol::V1, &capabilities(GITHUB_CAPABILITIES)),
29 &[
30 ("multi_ack", None),
31 ("thin-pack", None),
32 ("side-band", None),
33 ("ofs-delta", None),
34 ("shallow", None),
35 ("deepen-since", None),
36 ("deepen-not", None),
37 ("deepen-relative", None),
38 ("allow-tip-sha1-in-want", None),
39 ("allow-reachable-sha1-in-want", None),
40 ("no-done", None),
41 ("filter", None),
42 fetch::agent()
43 ],
44 "we don't enforce include-tag or no-progress"
45 );
46 }
47 }
48 }
49}
50
51mod v2 {
52 use git_transport::client::Capabilities;
53
54 fn capabilities(command: &str, input: &str) -> Capabilities {
55 Capabilities::from_lines(Some(Ok("version 2".into())), format!("{}={}", command, input))
56 .expect("valid input for V2 capabilities")
57 }
58
59 mod fetch {
60 mod default_features {
61 use crate::fetch::blocking_io::tests::command::v2::capabilities;
62 use crate::fetch::{self, Command};
63
64 #[test]
65 fn all_features() {
66 assert_eq!(
67 Command::Fetch.default_features(
68 git_transport::Protocol::V2,
69 &capabilities("fetch", "shallow filter ref-in-want sideband-all packfile-uris")
70 ),
71 ["shallow", "filter", "ref-in-want", "sideband-all", "packfile-uris"]
72 .iter()
73 .map(|s| (*s, None))
74 .chain(Some(fetch::agent()))
75 .collect::<Vec<_>>()
76 )
77 }
78 }
79
80 mod initial_arguments {
81 use bstr::ByteSlice;
82
83 use crate::fetch::blocking_io::tests::command::v2::capabilities;
84 use crate::fetch::Command;
85
86 #[test]
87 fn for_all_features() {
88 assert_eq!(
89 Command::Fetch.initial_arguments(&Command::Fetch.default_features(
90 git_transport::Protocol::V2,
91 &capabilities("fetch", "shallow filter ref-in-want sideband-all packfile-uris")
92 )),
93 [
94 "thin-pack",
95 "include-tag",
96 "ofs-delta",
97 "sideband-all",
98 "ref-in-want",
99 "packfile-uris"
100 ]
101 .iter()
102 .map(|s| s.as_bytes().as_bstr().to_owned())
103 .collect::<Vec<_>>()
104 )
105 }
106 }
107 }
108
109 mod ls_refs {
110 mod default_features {
111 use crate::fetch::blocking_io::tests::command::v2::capabilities;
112 use crate::fetch::{self, Command};
113
114 #[test]
115 fn default_as_there_are_no_features() {
116 assert_eq!(
117 Command::LsRefs.default_features(
118 git_transport::Protocol::V2,
119 &capabilities("something-else", "does not matter as there are none")
120 ),
121 &[fetch::agent()]
122 );
123 }
124 }
125
126 mod validate {
127 use bstr::ByteSlice;
128
129 use crate::fetch::blocking_io::tests::command::v2::capabilities;
130 use crate::fetch::Command;
131
132 #[test]
133 fn ref_prefixes_can_always_be_used() {
134 Command::LsRefs.validate_argument_prefixes_or_panic(
135 git_transport::Protocol::V2,
136 &capabilities("something else", "do-not-matter"),
137 &[b"ref-prefix hello/".as_bstr().into()],
138 &[],
139 );
140 }
141
142 #[test]
143 #[should_panic]
144 fn unknown_argument() {
145 Command::LsRefs.validate_argument_prefixes_or_panic(
146 git_transport::Protocol::V2,
147 &capabilities("other", "do-not-matter"),
148 &[b"definitely-nothing-we-know".as_bstr().into()],
149 &[],
150 );
151 }
152
153 #[test]
154 #[should_panic]
155 fn unknown_feature() {
156 Command::LsRefs.validate_argument_prefixes_or_panic(
157 git_transport::Protocol::V2,
158 &capabilities("other", "do-not-matter"),
159 &[],
160 &[("some-feature-that-does-not-exist", None)],
161 );
162 }
163 }
164 }
165}
git-protocol/src/fetch/blocking_io/tests/mod.rs+3−0
@@ -0,0 +1,3 @@
1mod arguments;
2mod command;
3mod refs;
git-protocol/src/fetch/blocking_io/tests/refs.rs+108−0
@@ -0,0 +1,108 @@
1use std::io;
2
3use git_transport::client;
4
5use crate::fetch::{blocking_io::refs::InternalRef, refs, Ref};
6
7fn oid(hex_sha: &str) -> git_hash::ObjectId {
8 git_hash::ObjectId::from_hex(hex_sha.as_bytes()).expect("valid input")
9}
10
11#[test]
12fn extract_references_from_v2_refs() {
13 let input: &mut dyn io::BufRead = &mut "808e50d724f604f69ab93c6da2919c014667bedb HEAD symref-target:refs/heads/main
14808e50d724f604f69ab93c6da2919c014667bedb refs/heads/main
157fe1b98b39423b71e14217aa299a03b7c937d656 refs/tags/foo peeled:808e50d724f604f69ab93c6da2919c014667bedb
167fe1b98b39423b71e14217aa299a03b7c937d6ff refs/tags/blaz
17"
18 .as_bytes();
19 let mut out = Vec::new();
20 refs::from_v2_refs(&mut out, input).expect("no failure on valid input");
21
22 assert_eq!(
23 out,
24 vec![
25 Ref::Symbolic {
26 path: "HEAD".into(),
27 target: "refs/heads/main".into(),
28 object: oid("808e50d724f604f69ab93c6da2919c014667bedb")
29 },
30 Ref::Direct {
31 path: "refs/heads/main".into(),
32 object: oid("808e50d724f604f69ab93c6da2919c014667bedb")
33 },
34 Ref::Peeled {
35 path: "refs/tags/foo".into(),
36 tag: oid("7fe1b98b39423b71e14217aa299a03b7c937d656"),
37 object: oid("808e50d724f604f69ab93c6da2919c014667bedb")
38 },
39 Ref::Direct {
40 path: "refs/tags/blaz".into(),
41 object: oid("7fe1b98b39423b71e14217aa299a03b7c937d6ff")
42 },
43 ]
44 )
45}
46
47#[test]
48fn extract_references_from_v1_refs() {
49 let input: &mut dyn io::BufRead = &mut "73a6868963993a3328e7d8fe94e5a6ac5078a944 HEAD
5073a6868963993a3328e7d8fe94e5a6ac5078a944 refs/heads/main
518e472f9ccc7d745927426cbb2d9d077de545aa4e refs/pull/13/head
52dce0ea858eef7ff61ad345cc5cdac62203fb3c10 refs/tags/git-commitgraph-v0.0.0
5321c9b7500cb144b3169a6537961ec2b9e865be81 refs/tags/git-commitgraph-v0.0.0^{}"
54 .as_bytes();
55 let mut out = vec![InternalRef::SymbolicForLookup {
56 path: "HEAD".into(),
57 target: "refs/heads/main".into(),
58 }];
59 refs::from_v1_refs_received_as_part_of_handshake(&mut out, input).expect("no failure from valid input");
60 assert_eq!(
61 out,
62 vec![
63 InternalRef::Symbolic {
64 path: "HEAD".into(),
65 target: "refs/heads/main".into(),
66 object: oid("73a6868963993a3328e7d8fe94e5a6ac5078a944")
67 },
68 InternalRef::Direct {
69 path: "refs/heads/main".into(),
70 object: oid("73a6868963993a3328e7d8fe94e5a6ac5078a944")
71 },
72 InternalRef::Direct {
73 path: "refs/pull/13/head".into(),
74 object: oid("8e472f9ccc7d745927426cbb2d9d077de545aa4e")
75 },
76 InternalRef::Peeled {
77 path: "refs/tags/git-commitgraph-v0.0.0".into(),
78 tag: oid("dce0ea858eef7ff61ad345cc5cdac62203fb3c10"),
79 object: oid("21c9b7500cb144b3169a6537961ec2b9e865be81")
80 }
81 ]
82 )
83}
84
85#[test]
86fn extract_symbolic_references_from_capabilities() -> Result<(), client::Error> {
87 let caps = client::Capabilities::from_bytes(
88 b"\0unrelated symref=HEAD:refs/heads/main symref=ANOTHER:refs/heads/foo agent=git/2.28.0",
89 )?
90 .0;
91 let mut out = Vec::new();
92 refs::from_capabilities(&mut out, caps.iter()).expect("a working example");
93
94 assert_eq!(
95 out,
96 vec![
97 InternalRef::SymbolicForLookup {
98 path: "HEAD".into(),
99 target: "refs/heads/main".into()
100 },
101 InternalRef::SymbolicForLookup {
102 path: "ANOTHER".into(),
103 target: "refs/heads/foo".into()
104 }
105 ]
106 );
107 Ok(())
108}