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