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