1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 package org.eclipse.jgit.transport;
44
45 import static org.hamcrest.Matchers.containsString;
46 import static org.hamcrest.Matchers.hasItems;
47 import static org.junit.Assert.assertEquals;
48 import static org.junit.Assert.assertThat;
49 import static org.junit.Assert.assertTrue;
50
51 import java.io.ByteArrayInputStream;
52 import java.io.ByteArrayOutputStream;
53 import java.io.IOException;
54 import java.util.Collection;
55 import java.util.List;
56 import java.util.stream.Collectors;
57
58 import org.eclipse.jgit.errors.PackProtocolException;
59 import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
60 import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
61 import org.eclipse.jgit.junit.TestRepository;
62 import org.eclipse.jgit.lib.Config;
63 import org.eclipse.jgit.lib.ObjectId;
64 import org.eclipse.jgit.revwalk.RevCommit;
65 import org.junit.Before;
66 import org.junit.Rule;
67 import org.junit.Test;
68 import org.junit.rules.ExpectedException;
69
70 public class ProtocolV2ParserTest {
71
72 @Rule
73 public ExpectedException thrown = ExpectedException.none();
74
75 private TestRepository<InMemoryRepository> testRepo;
76
77 @Before
78 public void setUp() throws Exception {
79 testRepo = new TestRepository<>(newRepo("protocol-v2-parser-test"));
80 }
81
82 private static InMemoryRepository newRepo(String name) {
83 return new InMemoryRepository(new DfsRepositoryDescription(name));
84 }
85
86 private static class ConfigBuilder {
87
88 private boolean allowRefInWant;
89
90 private boolean allowFilter;
91
92 private ConfigBuilder() {
93 }
94
95 static ConfigBuilder start() {
96 return new ConfigBuilder();
97 }
98
99 static TransferConfig getDefault() {
100 return start().done();
101 }
102
103 ConfigBuilder allowRefInWant() {
104 allowRefInWant = true;
105 return this;
106 }
107
108 ConfigBuilder allowFilter() {
109 allowFilter = true;
110 return this;
111 }
112
113 TransferConfig done() {
114 Config rc = new Config();
115 rc.setBoolean("uploadpack", null, "allowrefinwant", allowRefInWant);
116 rc.setBoolean("uploadpack", null, "allowfilter", allowFilter);
117 return new TransferConfig(rc);
118 }
119 }
120
121
122
123
124 private static PacketLineIn formatAsPacketLine(String... inputLines)
125 throws IOException {
126 ByteArrayOutputStream send = new ByteArrayOutputStream();
127 PacketLineOut pckOut = new PacketLineOut(send);
128 for (String line : inputLines) {
129 if (line == PacketLineIn.END) {
130 pckOut.end();
131 } else if (line == PacketLineIn.DELIM) {
132 pckOut.writeDelim();
133 } else {
134 pckOut.writeString(line);
135 }
136 }
137
138 return new PacketLineIn(new ByteArrayInputStream(send.toByteArray()));
139 }
140
141 private static List<String> objIdsAsStrings(Collection<ObjectId> objIds) {
142
143
144 return objIds.stream().map(ObjectId::name).collect(Collectors.toList());
145 }
146
147
148
149
150 @Test
151 public void testFetchBasicArguments()
152 throws PackProtocolException, IOException {
153 PacketLineIn pckIn = formatAsPacketLine(
154 PacketLineIn.DELIM,
155 "thin-pack", "no-progress", "include-tag", "ofs-delta",
156 "want 4624442d68ee402a94364191085b77137618633e",
157 "want f900c8326a43303685c46b279b9f70411bff1a4b",
158 "have 554f6e41067b9e3e565b6988a8294fac1cb78f4b",
159 "have abc760ab9ad72f08209943251b36cb886a578f87", "done",
160 PacketLineIn.END);
161 ProtocolV2Parser parser = new ProtocolV2Parser(
162 ConfigBuilder.getDefault());
163 FetchV2Request request = parser.parseFetchRequest(pckIn,
164 testRepo.getRepository().getRefDatabase());
165 assertTrue(request.getOptions()
166 .contains(GitProtocolConstants.OPTION_THIN_PACK));
167 assertTrue(request.getOptions()
168 .contains(GitProtocolConstants.OPTION_NO_PROGRESS));
169 assertTrue(request.getOptions()
170 .contains(GitProtocolConstants.OPTION_INCLUDE_TAG));
171 assertTrue(request.getOptions()
172 .contains(GitProtocolConstants.CAPABILITY_OFS_DELTA));
173 assertThat(objIdsAsStrings(request.getWantsIds()),
174 hasItems("4624442d68ee402a94364191085b77137618633e",
175 "f900c8326a43303685c46b279b9f70411bff1a4b"));
176 assertThat(objIdsAsStrings(request.getPeerHas()),
177 hasItems("554f6e41067b9e3e565b6988a8294fac1cb78f4b",
178 "abc760ab9ad72f08209943251b36cb886a578f87"));
179 assertTrue(request.getWantedRefs().isEmpty());
180 assertTrue(request.wasDoneReceived());
181 }
182
183 @Test
184 public void testFetchWithShallow_deepen() throws IOException {
185 PacketLineIn pckIn = formatAsPacketLine(
186 PacketLineIn.DELIM,
187 "deepen 15",
188 "deepen-relative",
189 "shallow 28274d02c489f4c7e68153056e9061a46f62d7a0",
190 "shallow 145e683b229dcab9d0e2ccb01b386f9ecc17d29d",
191 PacketLineIn.END);
192 ProtocolV2Parser parser = new ProtocolV2Parser(
193 ConfigBuilder.getDefault());
194 FetchV2Request request = parser.parseFetchRequest(pckIn,
195 testRepo.getRepository().getRefDatabase());
196 assertThat(objIdsAsStrings(request.getClientShallowCommits()),
197 hasItems("28274d02c489f4c7e68153056e9061a46f62d7a0",
198 "145e683b229dcab9d0e2ccb01b386f9ecc17d29d"));
199 assertTrue(request.getDeepenNotRefs().isEmpty());
200 assertEquals(15, request.getDepth());
201 assertTrue(request.getOptions()
202 .contains(GitProtocolConstants.OPTION_DEEPEN_RELATIVE));
203 }
204
205 @Test
206 public void testFetchWithShallow_deepenNot() throws IOException {
207 PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM,
208 "shallow 28274d02c489f4c7e68153056e9061a46f62d7a0",
209 "shallow 145e683b229dcab9d0e2ccb01b386f9ecc17d29d",
210 "deepen-not a08595f76159b09d57553e37a5123f1091bb13e7",
211 PacketLineIn.END);
212 ProtocolV2Parser parser = new ProtocolV2Parser(
213 ConfigBuilder.getDefault());
214 FetchV2Request request = parser.parseFetchRequest(pckIn,
215 testRepo.getRepository().getRefDatabase());
216 assertThat(objIdsAsStrings(request.getClientShallowCommits()),
217 hasItems("28274d02c489f4c7e68153056e9061a46f62d7a0",
218 "145e683b229dcab9d0e2ccb01b386f9ecc17d29d"));
219 assertThat(request.getDeepenNotRefs(),
220 hasItems("a08595f76159b09d57553e37a5123f1091bb13e7"));
221 }
222
223 @Test
224 public void testFetchWithShallow_deepenSince() throws IOException {
225 PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM,
226 "shallow 28274d02c489f4c7e68153056e9061a46f62d7a0",
227 "shallow 145e683b229dcab9d0e2ccb01b386f9ecc17d29d",
228 "deepen-since 123123123",
229 PacketLineIn.END);
230 ProtocolV2Parser parser = new ProtocolV2Parser(
231 ConfigBuilder.getDefault());
232 FetchV2Request request = parser.parseFetchRequest(pckIn,
233 testRepo.getRepository().getRefDatabase());
234 assertThat(objIdsAsStrings(request.getClientShallowCommits()),
235 hasItems("28274d02c489f4c7e68153056e9061a46f62d7a0",
236 "145e683b229dcab9d0e2ccb01b386f9ecc17d29d"));
237 assertEquals(123123123, request.getDeepenSince());
238 }
239
240 @Test
241 public void testFetchWithNoneFilter() throws IOException {
242 PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM,
243 "filter blob:none",
244 PacketLineIn.END);
245 ProtocolV2Parser parser = new ProtocolV2Parser(
246 ConfigBuilder.start().allowFilter().done());
247 FetchV2Request request = parser.parseFetchRequest(pckIn,
248 testRepo.getRepository().getRefDatabase());
249 assertEquals(0, request.getFilterBlobLimit());
250 }
251
252 @Test
253 public void testFetchWithBlobSizeFilter() throws IOException {
254 PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM,
255 "filter blob:limit=15",
256 PacketLineIn.END);
257 ProtocolV2Parser parser = new ProtocolV2Parser(
258 ConfigBuilder.start().allowFilter().done());
259 FetchV2Request request = parser.parseFetchRequest(pckIn,
260 testRepo.getRepository().getRefDatabase());
261 assertEquals(15, request.getFilterBlobLimit());
262 }
263
264 @Test
265 public void testFetchMustNotHaveMultipleFilters() throws IOException {
266 thrown.expect(PackProtocolException.class);
267 PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM,
268 "filter blob:none",
269 "filter blob:limit=12",
270 PacketLineIn.END);
271 ProtocolV2Parser parser = new ProtocolV2Parser(
272 ConfigBuilder.start().allowFilter().done());
273 FetchV2Request request = parser.parseFetchRequest(pckIn,
274 testRepo.getRepository().getRefDatabase());
275 assertEquals(0, request.getFilterBlobLimit());
276 }
277
278 @Test
279 public void testFetchFilterWithoutAllowFilter() throws IOException {
280 thrown.expect(PackProtocolException.class);
281 PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM,
282 "filter blob:limit=12", PacketLineIn.END);
283 ProtocolV2Parser parser = new ProtocolV2Parser(
284 ConfigBuilder.getDefault());
285 parser.parseFetchRequest(pckIn,
286 testRepo.getRepository().getRefDatabase());
287 }
288
289 @Test
290 public void testFetchWithRefInWant() throws Exception {
291 RevCommit one = testRepo.commit().message("1").create();
292 RevCommit two = testRepo.commit().message("2").create();
293 testRepo.update("branchA", one);
294 testRepo.update("branchB", two);
295
296 PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM,
297 "want e4980cdc48cfa1301493ca94eb70523f6788b819",
298 "want-ref refs/heads/branchA",
299 PacketLineIn.END);
300 ProtocolV2Parser parser = new ProtocolV2Parser(
301 ConfigBuilder.start().allowRefInWant().done());
302
303
304 FetchV2Request request = parser.parseFetchRequest(pckIn,
305 testRepo.getRepository().getRefDatabase());
306 assertEquals(1, request.getWantedRefs().size());
307 assertThat(request.getWantedRefs().keySet(),
308 hasItems("refs/heads/branchA"));
309 assertEquals(2, request.getWantsIds().size());
310 assertThat(objIdsAsStrings(request.getWantsIds()),
311 hasItems("e4980cdc48cfa1301493ca94eb70523f6788b819",
312 one.getName()));
313 }
314
315 @Test
316 public void testFetchWithRefInWantUnknownRef() throws Exception {
317 thrown.expect(PackProtocolException.class);
318 thrown.expectMessage(containsString("refs/heads/branchC"));
319
320 PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM,
321 "want e4980cdc48cfa1301493ca94eb70523f6788b819",
322 "want-ref refs/heads/branchC",
323 PacketLineIn.END);
324 ProtocolV2Parser parser = new ProtocolV2Parser(
325 ConfigBuilder.start().allowRefInWant().done());
326
327 RevCommit one = testRepo.commit().message("1").create();
328 RevCommit two = testRepo.commit().message("2").create();
329 testRepo.update("branchA", one);
330 testRepo.update("branchB", two);
331
332 parser.parseFetchRequest(pckIn,
333 testRepo.getRepository().getRefDatabase());
334 }
335
336 }