1 package org.eclipse.jgit.transport;
2
3 import static org.hamcrest.Matchers.containsString;
4 import static org.hamcrest.Matchers.hasItems;
5 import static org.hamcrest.Matchers.is;
6 import static org.hamcrest.Matchers.notNullValue;
7 import static org.junit.Assert.assertEquals;
8 import static org.junit.Assert.assertFalse;
9 import static org.junit.Assert.assertNotNull;
10 import static org.junit.Assert.assertThat;
11 import static org.junit.Assert.assertTrue;
12 import static org.junit.Assert.fail;
13
14 import java.io.ByteArrayInputStream;
15 import java.io.ByteArrayOutputStream;
16 import java.io.IOException;
17 import java.io.StringWriter;
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24
25 import org.eclipse.jgit.dircache.DirCache;
26 import org.eclipse.jgit.dircache.DirCacheBuilder;
27 import org.eclipse.jgit.dircache.DirCacheEntry;
28 import org.eclipse.jgit.errors.PackProtocolException;
29 import org.eclipse.jgit.errors.TransportException;
30 import org.eclipse.jgit.internal.storage.dfs.DfsGarbageCollector;
31 import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
32 import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
33 import org.eclipse.jgit.junit.TestRepository;
34 import org.eclipse.jgit.lib.NullProgressMonitor;
35 import org.eclipse.jgit.lib.ObjectId;
36 import org.eclipse.jgit.lib.ObjectInserter;
37 import org.eclipse.jgit.lib.PersonIdent;
38 import org.eclipse.jgit.lib.ProgressMonitor;
39 import org.eclipse.jgit.lib.Ref;
40 import org.eclipse.jgit.lib.Repository;
41 import org.eclipse.jgit.lib.Sets;
42 import org.eclipse.jgit.lib.TextProgressMonitor;
43 import org.eclipse.jgit.revwalk.RevBlob;
44 import org.eclipse.jgit.revwalk.RevCommit;
45 import org.eclipse.jgit.revwalk.RevTag;
46 import org.eclipse.jgit.revwalk.RevTree;
47 import org.eclipse.jgit.storage.pack.PackStatistics;
48 import org.eclipse.jgit.transport.UploadPack.RequestPolicy;
49 import org.eclipse.jgit.util.io.NullOutputStream;
50 import org.hamcrest.Matchers;
51 import org.junit.After;
52 import org.junit.Before;
53 import org.junit.Rule;
54 import org.junit.Test;
55 import org.junit.rules.ExpectedException;
56
57
58
59
60 public class UploadPackTest {
61 @Rule
62 public ExpectedException thrown = ExpectedException.none();
63
64 private URIish uri;
65
66 private TestProtocol<Object> testProtocol;
67
68 private Object ctx = new Object();
69
70 private InMemoryRepository server;
71
72 private InMemoryRepository client;
73
74 private TestRepository<InMemoryRepository> remote;
75
76 private PackStatistics stats;
77
78 @Before
79 public void setUp() throws Exception {
80 server = newRepo("server");
81 client = newRepo("client");
82
83 remote = new TestRepository<>(server);
84 }
85
86 @After
87 public void tearDown() {
88 Transport.unregister(testProtocol);
89 }
90
91 private static InMemoryRepository newRepo(String name) {
92 return new InMemoryRepository(new DfsRepositoryDescription(name));
93 }
94
95 private void generateBitmaps(InMemoryRepository repo) throws Exception {
96 new DfsGarbageCollector(repo).pack(null);
97 repo.scanForRepoChanges();
98 }
99
100 private static TestProtocol<Object> generateReachableCommitUploadPackProtocol() {
101 return new TestProtocol<>((Object req, Repository db) -> {
102 UploadPack up = new UploadPack(db);
103 up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT);
104 return up;
105 }, null);
106 }
107
108 @Test
109 public void testFetchParentOfShallowCommit() throws Exception {
110 RevCommit commit0 = remote.commit().message("0").create();
111 RevCommit commit1 = remote.commit().message("1").parent(commit0).create();
112 RevCommit tip = remote.commit().message("2").parent(commit1).create();
113 remote.update("master", tip);
114
115 testProtocol = new TestProtocol<>((Object req, Repository db) -> {
116 UploadPack up = new UploadPack(db);
117 up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT);
118
119 up.getRevWalk()
120 .assumeShallow(Collections.singleton(commit1.getId()));
121 return up;
122 }, null);
123 uri = testProtocol.register(ctx, server);
124
125 assertFalse(client.getObjectDatabase().has(commit0.toObjectId()));
126
127
128 try (Transport tn = testProtocol.open(uri, client, "server")) {
129 tn.fetch(NullProgressMonitor.INSTANCE,
130 Collections.singletonList(new RefSpec(commit0.name())));
131 assertTrue(client.getObjectDatabase().has(commit0.toObjectId()));
132 }
133 }
134
135 @Test
136 public void testFetchUnreachableBlobWithBitmap() throws Exception {
137 RevBlob blob = remote.blob("foo");
138 remote.commit(remote.tree(remote.file("foo", blob)));
139 generateBitmaps(server);
140
141 testProtocol = generateReachableCommitUploadPackProtocol();
142 uri = testProtocol.register(ctx, server);
143
144 assertFalse(client.getObjectDatabase().has(blob.toObjectId()));
145
146 try (Transport tn = testProtocol.open(uri, client, "server")) {
147 thrown.expect(TransportException.class);
148 thrown.expectMessage(Matchers.containsString(
149 "want " + blob.name() + " not valid"));
150 tn.fetch(NullProgressMonitor.INSTANCE,
151 Collections.singletonList(new RefSpec(blob.name())));
152 }
153 }
154
155 @Test
156 public void testFetchReachableBlobWithBitmap() throws Exception {
157 RevBlob blob = remote.blob("foo");
158 RevCommit commit = remote.commit(remote.tree(remote.file("foo", blob)));
159 remote.update("master", commit);
160 generateBitmaps(server);
161
162 testProtocol = generateReachableCommitUploadPackProtocol();
163 uri = testProtocol.register(ctx, server);
164
165 assertFalse(client.getObjectDatabase().has(blob.toObjectId()));
166
167 try (Transport tn = testProtocol.open(uri, client, "server")) {
168 tn.fetch(NullProgressMonitor.INSTANCE,
169 Collections.singletonList(new RefSpec(blob.name())));
170 assertTrue(client.getObjectDatabase().has(blob.toObjectId()));
171 }
172 }
173
174 @Test
175 public void testFetchReachableBlobWithoutBitmap() throws Exception {
176 RevBlob blob = remote.blob("foo");
177 RevCommit commit = remote.commit(remote.tree(remote.file("foo", blob)));
178 remote.update("master", commit);
179
180 testProtocol = generateReachableCommitUploadPackProtocol();
181 uri = testProtocol.register(ctx, server);
182
183 assertFalse(client.getObjectDatabase().has(blob.toObjectId()));
184
185 try (Transport tn = testProtocol.open(uri, client, "server")) {
186 thrown.expect(TransportException.class);
187 thrown.expectMessage(Matchers.containsString(
188 "want " + blob.name() + " not valid"));
189 tn.fetch(NullProgressMonitor.INSTANCE,
190 Collections.singletonList(new RefSpec(blob.name())));
191 }
192 }
193
194 @Test
195 public void testFetchWithBlobNoneFilter() throws Exception {
196 InMemoryRepository server2 = newRepo("server2");
197 try (TestRepository<InMemoryRepository> remote2 = new TestRepository<>(
198 server2)) {
199 RevBlob blob1 = remote2.blob("foobar");
200 RevBlob blob2 = remote2.blob("fooba");
201 RevTree tree = remote2.tree(remote2.file("1", blob1),
202 remote2.file("2", blob2));
203 RevCommit commit = remote2.commit(tree);
204 remote2.update("master", commit);
205
206 server2.getConfig().setBoolean("uploadpack", null, "allowfilter",
207 true);
208
209 testProtocol = new TestProtocol<>((Object req, Repository db) -> {
210 UploadPack up = new UploadPack(db);
211 return up;
212 }, null);
213 uri = testProtocol.register(ctx, server2);
214
215 try (Transport tn = testProtocol.open(uri, client, "server2")) {
216 tn.setFilterSpec(FilterSpec.withBlobLimit(0));
217 tn.fetch(NullProgressMonitor.INSTANCE,
218 Collections.singletonList(new RefSpec(commit.name())));
219 assertTrue(client.getObjectDatabase().has(tree.toObjectId()));
220 assertFalse(client.getObjectDatabase().has(blob1.toObjectId()));
221 assertFalse(client.getObjectDatabase().has(blob2.toObjectId()));
222 }
223 }
224 }
225
226 @Test
227 public void testFetchExplicitBlobWithFilter() throws Exception {
228 InMemoryRepository server2 = newRepo("server2");
229 try (TestRepository<InMemoryRepository> remote2 = new TestRepository<>(
230 server2)) {
231 RevBlob blob1 = remote2.blob("foobar");
232 RevBlob blob2 = remote2.blob("fooba");
233 RevTree tree = remote2.tree(remote2.file("1", blob1),
234 remote2.file("2", blob2));
235 RevCommit commit = remote2.commit(tree);
236 remote2.update("master", commit);
237 remote2.update("a_blob", blob1);
238
239 server2.getConfig().setBoolean("uploadpack", null, "allowfilter",
240 true);
241
242 testProtocol = new TestProtocol<>((Object req, Repository db) -> {
243 UploadPack up = new UploadPack(db);
244 return up;
245 }, null);
246 uri = testProtocol.register(ctx, server2);
247
248 try (Transport tn = testProtocol.open(uri, client, "server2")) {
249 tn.setFilterSpec(FilterSpec.withBlobLimit(0));
250 tn.fetch(NullProgressMonitor.INSTANCE, Arrays.asList(
251 new RefSpec(commit.name()), new RefSpec(blob1.name())));
252 assertTrue(client.getObjectDatabase().has(tree.toObjectId()));
253 assertTrue(client.getObjectDatabase().has(blob1.toObjectId()));
254 assertFalse(client.getObjectDatabase().has(blob2.toObjectId()));
255 }
256 }
257 }
258
259 @Test
260 public void testFetchWithBlobLimitFilter() throws Exception {
261 InMemoryRepository server2 = newRepo("server2");
262 try (TestRepository<InMemoryRepository> remote2 = new TestRepository<>(
263 server2)) {
264 RevBlob longBlob = remote2.blob("foobar");
265 RevBlob shortBlob = remote2.blob("fooba");
266 RevTree tree = remote2.tree(remote2.file("1", longBlob),
267 remote2.file("2", shortBlob));
268 RevCommit commit = remote2.commit(tree);
269 remote2.update("master", commit);
270
271 server2.getConfig().setBoolean("uploadpack", null, "allowfilter",
272 true);
273
274 testProtocol = new TestProtocol<>((Object req, Repository db) -> {
275 UploadPack up = new UploadPack(db);
276 return up;
277 }, null);
278 uri = testProtocol.register(ctx, server2);
279
280 try (Transport tn = testProtocol.open(uri, client, "server2")) {
281 tn.setFilterSpec(FilterSpec.withBlobLimit(5));
282 tn.fetch(NullProgressMonitor.INSTANCE,
283 Collections.singletonList(new RefSpec(commit.name())));
284 assertFalse(
285 client.getObjectDatabase().has(longBlob.toObjectId()));
286 assertTrue(
287 client.getObjectDatabase().has(shortBlob.toObjectId()));
288 }
289 }
290 }
291
292 @Test
293 public void testFetchExplicitBlobWithFilterAndBitmaps() throws Exception {
294 InMemoryRepository server2 = newRepo("server2");
295 try (TestRepository<InMemoryRepository> remote2 = new TestRepository<>(
296 server2)) {
297 RevBlob blob1 = remote2.blob("foobar");
298 RevBlob blob2 = remote2.blob("fooba");
299 RevTree tree = remote2.tree(remote2.file("1", blob1),
300 remote2.file("2", blob2));
301 RevCommit commit = remote2.commit(tree);
302 remote2.update("master", commit);
303 remote2.update("a_blob", blob1);
304
305 server2.getConfig().setBoolean("uploadpack", null, "allowfilter",
306 true);
307
308
309 new DfsGarbageCollector(server2).pack(null);
310 server2.scanForRepoChanges();
311
312 testProtocol = new TestProtocol<>((Object req, Repository db) -> {
313 UploadPack up = new UploadPack(db);
314 return up;
315 }, null);
316 uri = testProtocol.register(ctx, server2);
317
318 try (Transport tn = testProtocol.open(uri, client, "server2")) {
319 tn.setFilterSpec(FilterSpec.withBlobLimit(0));
320 tn.fetch(NullProgressMonitor.INSTANCE, Arrays.asList(
321 new RefSpec(commit.name()), new RefSpec(blob1.name())));
322 assertTrue(client.getObjectDatabase().has(blob1.toObjectId()));
323 assertFalse(client.getObjectDatabase().has(blob2.toObjectId()));
324 }
325 }
326 }
327
328 @Test
329 public void testFetchWithBlobLimitFilterAndBitmaps() throws Exception {
330 InMemoryRepository server2 = newRepo("server2");
331 try (TestRepository<InMemoryRepository> remote2 = new TestRepository<>(
332 server2)) {
333 RevBlob longBlob = remote2.blob("foobar");
334 RevBlob shortBlob = remote2.blob("fooba");
335 RevTree tree = remote2.tree(remote2.file("1", longBlob),
336 remote2.file("2", shortBlob));
337 RevCommit commit = remote2.commit(tree);
338 remote2.update("master", commit);
339
340 server2.getConfig().setBoolean("uploadpack", null, "allowfilter",
341 true);
342
343
344 new DfsGarbageCollector(server2).pack(null);
345 server2.scanForRepoChanges();
346
347 testProtocol = new TestProtocol<>((Object req, Repository db) -> {
348 UploadPack up = new UploadPack(db);
349 return up;
350 }, null);
351 uri = testProtocol.register(ctx, server2);
352
353 try (Transport tn = testProtocol.open(uri, client, "server2")) {
354 tn.setFilterSpec(FilterSpec.withBlobLimit(5));
355 tn.fetch(NullProgressMonitor.INSTANCE,
356 Collections.singletonList(new RefSpec(commit.name())));
357 assertFalse(
358 client.getObjectDatabase().has(longBlob.toObjectId()));
359 assertTrue(
360 client.getObjectDatabase().has(shortBlob.toObjectId()));
361 }
362 }
363 }
364
365 @Test
366 public void testFetchWithNonSupportingServer() throws Exception {
367 InMemoryRepository server2 = newRepo("server2");
368 try (TestRepository<InMemoryRepository> remote2 = new TestRepository<>(
369 server2)) {
370 RevBlob blob = remote2.blob("foo");
371 RevTree tree = remote2.tree(remote2.file("1", blob));
372 RevCommit commit = remote2.commit(tree);
373 remote2.update("master", commit);
374
375 server2.getConfig().setBoolean("uploadpack", null, "allowfilter",
376 false);
377
378 testProtocol = new TestProtocol<>((Object req, Repository db) -> {
379 UploadPack up = new UploadPack(db);
380 return up;
381 }, null);
382 uri = testProtocol.register(ctx, server2);
383
384 try (Transport tn = testProtocol.open(uri, client, "server2")) {
385 tn.setFilterSpec(FilterSpec.withBlobLimit(0));
386
387 thrown.expect(TransportException.class);
388 thrown.expectMessage(
389 "filter requires server to advertise that capability");
390
391 tn.fetch(NullProgressMonitor.INSTANCE,
392 Collections.singletonList(new RefSpec(commit.name())));
393 }
394 }
395 }
396
397
398
399
400
401 private ByteArrayInputStream uploadPackV2Setup(RequestPolicy requestPolicy,
402 RefFilter refFilter, ProtocolV2Hook hook, String... inputLines)
403 throws Exception {
404
405 ByteArrayInputStream send = linesAsInputStream(inputLines);
406
407 server.getConfig().setString("protocol", null, "version", "2");
408 UploadPack up = new UploadPack(server);
409 if (requestPolicy != null)
410 up.setRequestPolicy(requestPolicy);
411 if (refFilter != null)
412 up.setRefFilter(refFilter);
413 up.setExtraParameters(Sets.of("version=2"));
414 if (hook != null) {
415 up.setProtocolV2Hook(hook);
416 }
417
418 ByteArrayOutputStream recv = new ByteArrayOutputStream();
419 up.upload(send, recv, null);
420 stats = up.getStatistics();
421
422 return new ByteArrayInputStream(recv.toByteArray());
423 }
424
425 private static ByteArrayInputStream linesAsInputStream(String... inputLines)
426 throws IOException {
427 try (ByteArrayOutputStream send = new ByteArrayOutputStream()) {
428 PacketLineOut pckOut = new PacketLineOut(send);
429 for (String line : inputLines) {
430 if (PacketLineIn.isEnd(line)) {
431 pckOut.end();
432 } else if (PacketLineIn.isDelimiter(line)) {
433 pckOut.writeDelim();
434 } else {
435 pckOut.writeString(line);
436 }
437 }
438 return new ByteArrayInputStream(send.toByteArray());
439 }
440 }
441
442
443
444
445
446
447 private ByteArrayInputStream uploadPackV2(RequestPolicy requestPolicy,
448 RefFilter refFilter, ProtocolV2Hook hook, String... inputLines)
449 throws Exception {
450 ByteArrayInputStream recvStream =
451 uploadPackV2Setup(requestPolicy, refFilter, hook, inputLines);
452 PacketLineIn pckIn = new PacketLineIn(recvStream);
453
454
455 while (!PacketLineIn.isEnd(pckIn.readString())) {
456
457 }
458 return recvStream;
459 }
460
461 private ByteArrayInputStream uploadPackV2(String... inputLines) throws Exception {
462 return uploadPackV2(null, null, null, inputLines);
463 }
464
465 private static class TestV2Hook implements ProtocolV2Hook {
466 private CapabilitiesV2Request capabilitiesRequest;
467
468 private LsRefsV2Request lsRefsRequest;
469
470 private FetchV2Request fetchRequest;
471
472 @Override
473 public void onCapabilities(CapabilitiesV2Request req) {
474 capabilitiesRequest = req;
475 }
476
477 @Override
478 public void onLsRefs(LsRefsV2Request req) {
479 lsRefsRequest = req;
480 }
481
482 @Override
483 public void onFetch(FetchV2Request req) {
484 fetchRequest = req;
485 }
486 }
487
488 @Test
489 public void testV2Capabilities() throws Exception {
490 TestV2Hook hook = new TestV2Hook();
491 ByteArrayInputStream recvStream =
492 uploadPackV2Setup(null, null, hook, PacketLineIn.end());
493 PacketLineIn pckIn = new PacketLineIn(recvStream);
494 assertThat(hook.capabilitiesRequest, notNullValue());
495 assertThat(pckIn.readString(), is("version 2"));
496 assertThat(
497 Arrays.asList(pckIn.readString(), pckIn.readString(),
498 pckIn.readString()),
499
500
501
502
503
504
505 hasItems("ls-refs", "fetch=shallow", "server-option"));
506 assertTrue(PacketLineIn.isEnd(pckIn.readString()));
507 }
508
509 @Test
510 public void testV2CapabilitiesAllowFilter() throws Exception {
511 server.getConfig().setBoolean("uploadpack", null, "allowfilter", true);
512 ByteArrayInputStream recvStream =
513 uploadPackV2Setup(null, null, null, PacketLineIn.end());
514 PacketLineIn pckIn = new PacketLineIn(recvStream);
515
516 assertThat(pckIn.readString(), is("version 2"));
517 assertThat(
518 Arrays.asList(pckIn.readString(), pckIn.readString(),
519 pckIn.readString()),
520
521
522 hasItems("ls-refs", "fetch=filter shallow", "server-option"));
523 assertTrue(PacketLineIn.isEnd(pckIn.readString()));
524 }
525
526 @Test
527 public void testV2CapabilitiesRefInWant() throws Exception {
528 server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true);
529 ByteArrayInputStream recvStream =
530 uploadPackV2Setup(null, null, null, PacketLineIn.end());
531 PacketLineIn pckIn = new PacketLineIn(recvStream);
532
533 assertThat(pckIn.readString(), is("version 2"));
534 assertThat(
535 Arrays.asList(pckIn.readString(), pckIn.readString(),
536 pckIn.readString()),
537
538
539 hasItems("ls-refs", "fetch=ref-in-want shallow",
540 "server-option"));
541 assertTrue(PacketLineIn.isEnd(pckIn.readString()));
542 }
543
544 @Test
545 public void testV2CapabilitiesRefInWantNotAdvertisedIfUnallowed() throws Exception {
546 server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", false);
547 ByteArrayInputStream recvStream =
548 uploadPackV2Setup(null, null, null, PacketLineIn.end());
549 PacketLineIn pckIn = new PacketLineIn(recvStream);
550
551 assertThat(pckIn.readString(), is("version 2"));
552 assertThat(
553 Arrays.asList(pckIn.readString(), pckIn.readString(),
554 pckIn.readString()),
555 hasItems("ls-refs", "fetch=shallow", "server-option"));
556 assertTrue(PacketLineIn.isEnd(pckIn.readString()));
557 }
558
559 @Test
560 public void testV2CapabilitiesRefInWantNotAdvertisedIfAdvertisingForbidden() throws Exception {
561 server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true);
562 server.getConfig().setBoolean("uploadpack", null, "advertiserefinwant", false);
563 ByteArrayInputStream recvStream =
564 uploadPackV2Setup(null, null, null, PacketLineIn.end());
565 PacketLineIn pckIn = new PacketLineIn(recvStream);
566
567 assertThat(pckIn.readString(), is("version 2"));
568 assertThat(
569 Arrays.asList(pckIn.readString(), pckIn.readString(),
570 pckIn.readString()),
571 hasItems("ls-refs", "fetch=shallow", "server-option"));
572 assertTrue(PacketLineIn.isEnd(pckIn.readString()));
573 }
574
575 @Test
576 public void testV2EmptyRequest() throws Exception {
577 ByteArrayInputStream recvStream = uploadPackV2(PacketLineIn.end());
578
579
580 assertEquals(0, recvStream.available());
581 }
582
583 @Test
584 public void testV2LsRefs() throws Exception {
585 RevCommit tip = remote.commit().message("message").create();
586 remote.update("master", tip);
587 server.updateRef("HEAD").link("refs/heads/master");
588 RevTag tag = remote.tag("tag", tip);
589 remote.update("refs/tags/tag", tag);
590
591 TestV2Hook hook = new TestV2Hook();
592 ByteArrayInputStream recvStream = uploadPackV2(null, null, hook,
593 "command=ls-refs\n", PacketLineIn.end());
594 PacketLineIn pckIn = new PacketLineIn(recvStream);
595
596 assertThat(hook.lsRefsRequest, notNullValue());
597 assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD"));
598 assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
599 assertThat(pckIn.readString(), is(tag.toObjectId().getName() + " refs/tags/tag"));
600 assertTrue(PacketLineIn.isEnd(pckIn.readString()));
601 }
602
603 @Test
604 public void testV2LsRefsSymrefs() throws Exception {
605 RevCommit tip = remote.commit().message("message").create();
606 remote.update("master", tip);
607 server.updateRef("HEAD").link("refs/heads/master");
608 RevTag tag = remote.tag("tag", tip);
609 remote.update("refs/tags/tag", tag);
610
611 ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n",
612 PacketLineIn.delimiter(), "symrefs", PacketLineIn.end());
613 PacketLineIn pckIn = new PacketLineIn(recvStream);
614
615 assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD symref-target:refs/heads/master"));
616 assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
617 assertThat(pckIn.readString(), is(tag.toObjectId().getName() + " refs/tags/tag"));
618 assertTrue(PacketLineIn.isEnd(pckIn.readString()));
619 }
620
621 @Test
622 public void testV2LsRefsPeel() throws Exception {
623 RevCommit tip = remote.commit().message("message").create();
624 remote.update("master", tip);
625 server.updateRef("HEAD").link("refs/heads/master");
626 RevTag tag = remote.tag("tag", tip);
627 remote.update("refs/tags/tag", tag);
628
629 ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n",
630 PacketLineIn.delimiter(), "peel", PacketLineIn.end());
631 PacketLineIn pckIn = new PacketLineIn(recvStream);
632
633 assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD"));
634 assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
635 assertThat(
636 pckIn.readString(),
637 is(tag.toObjectId().getName() + " refs/tags/tag peeled:"
638 + tip.toObjectId().getName()));
639 assertTrue(PacketLineIn.isEnd(pckIn.readString()));
640 }
641
642 @Test
643 public void testV2LsRefsMultipleCommands() throws Exception {
644 RevCommit tip = remote.commit().message("message").create();
645 remote.update("master", tip);
646 server.updateRef("HEAD").link("refs/heads/master");
647 RevTag tag = remote.tag("tag", tip);
648 remote.update("refs/tags/tag", tag);
649
650 ByteArrayInputStream recvStream = uploadPackV2(
651 "command=ls-refs\n", PacketLineIn.delimiter(), "symrefs",
652 "peel", PacketLineIn.end(), "command=ls-refs\n",
653 PacketLineIn.delimiter(), PacketLineIn.end());
654 PacketLineIn pckIn = new PacketLineIn(recvStream);
655
656 assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD symref-target:refs/heads/master"));
657 assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
658 assertThat(
659 pckIn.readString(),
660 is(tag.toObjectId().getName() + " refs/tags/tag peeled:"
661 + tip.toObjectId().getName()));
662 assertTrue(PacketLineIn.isEnd(pckIn.readString()));
663 assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD"));
664 assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
665 assertThat(pckIn.readString(), is(tag.toObjectId().getName() + " refs/tags/tag"));
666 assertTrue(PacketLineIn.isEnd(pckIn.readString()));
667 }
668
669 @Test
670 public void testV2LsRefsRefPrefix() throws Exception {
671 RevCommit tip = remote.commit().message("message").create();
672 remote.update("master", tip);
673 remote.update("other", tip);
674 remote.update("yetAnother", tip);
675
676 ByteArrayInputStream recvStream = uploadPackV2(
677 "command=ls-refs\n",
678 PacketLineIn.delimiter(),
679 "ref-prefix refs/heads/maste",
680 "ref-prefix refs/heads/other",
681 PacketLineIn.end());
682 PacketLineIn pckIn = new PacketLineIn(recvStream);
683
684 assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
685 assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/other"));
686 assertTrue(PacketLineIn.isEnd(pckIn.readString()));
687 }
688
689 @Test
690 public void testV2LsRefsRefPrefixNoSlash() throws Exception {
691 RevCommit tip = remote.commit().message("message").create();
692 remote.update("master", tip);
693 remote.update("other", tip);
694
695 ByteArrayInputStream recvStream = uploadPackV2(
696 "command=ls-refs\n",
697 PacketLineIn.delimiter(),
698 "ref-prefix refs/heads/maste",
699 "ref-prefix r",
700 PacketLineIn.end());
701 PacketLineIn pckIn = new PacketLineIn(recvStream);
702
703 assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
704 assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/other"));
705 assertTrue(PacketLineIn.isEnd(pckIn.readString()));
706 }
707
708 @Test
709 public void testV2LsRefsUnrecognizedArgument() throws Exception {
710 thrown.expect(PackProtocolException.class);
711 thrown.expectMessage("unexpected invalid-argument");
712 uploadPackV2(
713 "command=ls-refs\n",
714 PacketLineIn.delimiter(),
715 "invalid-argument\n",
716 PacketLineIn.end());
717 }
718
719 @Test
720 public void testV2LsRefsServerOptions() throws Exception {
721 String[] lines = { "command=ls-refs\n",
722 "server-option=one\n", "server-option=two\n",
723 PacketLineIn.delimiter(),
724 PacketLineIn.end() };
725
726 TestV2Hook testHook = new TestV2Hook();
727 uploadPackV2Setup(null, null, testHook, lines);
728
729 LsRefsV2Request req = testHook.lsRefsRequest;
730 assertEquals(2, req.getServerOptions().size());
731 assertThat(req.getServerOptions(), hasItems("one", "two"));
732 }
733
734
735
736
737
738 private ReceivedPackStatistics parsePack(ByteArrayInputStream recvStream) throws Exception {
739 return parsePack(recvStream, NullProgressMonitor.INSTANCE);
740 }
741
742 private ReceivedPackStatistics parsePack(ByteArrayInputStream recvStream, ProgressMonitor pm)
743 throws Exception {
744 SideBandInputStream sb = new SideBandInputStream(
745 recvStream, pm,
746 new StringWriter(), NullOutputStream.INSTANCE);
747 PackParser pp = client.newObjectInserter().newPackParser(sb);
748 pp.parse(NullProgressMonitor.INSTANCE);
749
750
751 assertEquals(-1, recvStream.read());
752
753 return pp.getReceivedPackStatistics();
754 }
755
756 @Test
757 public void testV2FetchRequestPolicyAdvertised() throws Exception {
758 RevCommit advertized = remote.commit().message("x").create();
759 RevCommit unadvertized = remote.commit().message("y").create();
760 remote.update("branch1", advertized);
761
762
763 uploadPackV2(
764 RequestPolicy.ADVERTISED,
765 null,
766 null,
767 "command=fetch\n",
768 PacketLineIn.delimiter(),
769 "want " + advertized.name() + "\n",
770 PacketLineIn.end());
771
772
773 thrown.expect(TransportException.class);
774 thrown.expectMessage(Matchers.containsString(
775 "want " + unadvertized.name() + " not valid"));
776 uploadPackV2(
777 RequestPolicy.ADVERTISED,
778 null,
779 null,
780 "command=fetch\n",
781 PacketLineIn.delimiter(),
782 "want " + unadvertized.name() + "\n",
783 PacketLineIn.end());
784 }
785
786 @Test
787 public void testV2FetchRequestPolicyReachableCommit() throws Exception {
788 RevCommit reachable = remote.commit().message("x").create();
789 RevCommit advertized = remote.commit().message("x").parent(reachable).create();
790 RevCommit unreachable = remote.commit().message("y").create();
791 remote.update("branch1", advertized);
792
793
794 uploadPackV2(
795 RequestPolicy.REACHABLE_COMMIT,
796 null,
797 null,
798 "command=fetch\n",
799 PacketLineIn.delimiter(),
800 "want " + reachable.name() + "\n",
801 PacketLineIn.end());
802
803
804 thrown.expect(TransportException.class);
805 thrown.expectMessage(Matchers.containsString(
806 "want " + unreachable.name() + " not valid"));
807 uploadPackV2(
808 RequestPolicy.REACHABLE_COMMIT,
809 null,
810 null,
811 "command=fetch\n",
812 PacketLineIn.delimiter(),
813 "want " + unreachable.name() + "\n",
814 PacketLineIn.end());
815 }
816
817 @Test
818 public void testV2FetchRequestPolicyTip() throws Exception {
819 RevCommit parentOfTip = remote.commit().message("x").create();
820 RevCommit tip = remote.commit().message("y").parent(parentOfTip).create();
821 remote.update("secret", tip);
822
823
824 uploadPackV2(
825 RequestPolicy.TIP,
826 new RejectAllRefFilter(),
827 null,
828 "command=fetch\n",
829 PacketLineIn.delimiter(),
830 "want " + tip.name() + "\n",
831 PacketLineIn.end());
832
833
834 thrown.expect(TransportException.class);
835 thrown.expectMessage(Matchers.containsString(
836 "want " + parentOfTip.name() + " not valid"));
837 uploadPackV2(
838 RequestPolicy.TIP,
839 new RejectAllRefFilter(),
840 null,
841 "command=fetch\n",
842 PacketLineIn.delimiter(),
843 "want " + parentOfTip.name() + "\n",
844 PacketLineIn.end());
845 }
846
847 @Test
848 public void testV2FetchRequestPolicyReachableCommitTip() throws Exception {
849 RevCommit parentOfTip = remote.commit().message("x").create();
850 RevCommit tip = remote.commit().message("y").parent(parentOfTip).create();
851 RevCommit unreachable = remote.commit().message("y").create();
852 remote.update("secret", tip);
853
854
855 uploadPackV2(
856 RequestPolicy.REACHABLE_COMMIT_TIP,
857 new RejectAllRefFilter(),
858 null,
859 "command=fetch\n",
860 PacketLineIn.delimiter(),
861 "want " + parentOfTip.name() + "\n",
862 PacketLineIn.end());
863
864
865 thrown.expect(TransportException.class);
866 thrown.expectMessage(Matchers.containsString(
867 "want " + unreachable.name() + " not valid"));
868 uploadPackV2(
869 RequestPolicy.REACHABLE_COMMIT_TIP,
870 new RejectAllRefFilter(),
871 null,
872 "command=fetch\n",
873 PacketLineIn.delimiter(),
874 "want " + unreachable.name() + "\n",
875 PacketLineIn.end());
876 }
877
878 @Test
879 public void testV2FetchRequestPolicyAny() throws Exception {
880 RevCommit unreachable = remote.commit().message("y").create();
881
882
883 uploadPackV2(
884 RequestPolicy.ANY,
885 null,
886 null,
887 "command=fetch\n",
888 PacketLineIn.delimiter(),
889 "want " + unreachable.name() + "\n",
890 PacketLineIn.end());
891 }
892
893 @Test
894 public void testV2FetchServerDoesNotStopNegotiation() throws Exception {
895 RevCommit fooParent = remote.commit().message("x").create();
896 RevCommit fooChild = remote.commit().message("x").parent(fooParent).create();
897 RevCommit barParent = remote.commit().message("y").create();
898 RevCommit barChild = remote.commit().message("y").parent(barParent).create();
899 remote.update("branch1", fooChild);
900 remote.update("branch2", barChild);
901
902 ByteArrayInputStream recvStream = uploadPackV2(
903 "command=fetch\n",
904 PacketLineIn.delimiter(),
905 "want " + fooChild.toObjectId().getName() + "\n",
906 "want " + barChild.toObjectId().getName() + "\n",
907 "have " + fooParent.toObjectId().getName() + "\n",
908 PacketLineIn.end());
909 PacketLineIn pckIn = new PacketLineIn(recvStream);
910
911 assertThat(pckIn.readString(), is("acknowledgments"));
912 assertThat(pckIn.readString(), is("ACK " + fooParent.toObjectId().getName()));
913 assertTrue(PacketLineIn.isEnd(pckIn.readString()));
914 }
915
916 @Test
917 public void testV2FetchServerStopsNegotiation() throws Exception {
918 RevCommit fooParent = remote.commit().message("x").create();
919 RevCommit fooChild = remote.commit().message("x").parent(fooParent).create();
920 RevCommit barParent = remote.commit().message("y").create();
921 RevCommit barChild = remote.commit().message("y").parent(barParent).create();
922 remote.update("branch1", fooChild);
923 remote.update("branch2", barChild);
924
925 ByteArrayInputStream recvStream = uploadPackV2(
926 "command=fetch\n",
927 PacketLineIn.delimiter(),
928 "want " + fooChild.toObjectId().getName() + "\n",
929 "want " + barChild.toObjectId().getName() + "\n",
930 "have " + fooParent.toObjectId().getName() + "\n",
931 "have " + barParent.toObjectId().getName() + "\n",
932 PacketLineIn.end());
933 PacketLineIn pckIn = new PacketLineIn(recvStream);
934
935 assertThat(pckIn.readString(), is("acknowledgments"));
936 assertThat(
937 Arrays.asList(pckIn.readString(), pckIn.readString()),
938 hasItems(
939 "ACK " + fooParent.toObjectId().getName(),
940 "ACK " + barParent.toObjectId().getName()));
941 assertThat(pckIn.readString(), is("ready"));
942 assertTrue(PacketLineIn.isDelimiter(pckIn.readString()));
943 assertThat(pckIn.readString(), is("packfile"));
944 parsePack(recvStream);
945 assertFalse(client.getObjectDatabase().has(fooParent.toObjectId()));
946 assertTrue(client.getObjectDatabase().has(fooChild.toObjectId()));
947 assertFalse(client.getObjectDatabase().has(barParent.toObjectId()));
948 assertTrue(client.getObjectDatabase().has(barChild.toObjectId()));
949 }
950
951 @Test
952 public void testV2FetchClientStopsNegotiation() throws Exception {
953 RevCommit fooParent = remote.commit().message("x").create();
954 RevCommit fooChild = remote.commit().message("x").parent(fooParent).create();
955 RevCommit barParent = remote.commit().message("y").create();
956 RevCommit barChild = remote.commit().message("y").parent(barParent).create();
957 remote.update("branch1", fooChild);
958 remote.update("branch2", barChild);
959
960 ByteArrayInputStream recvStream = uploadPackV2(
961 "command=fetch\n",
962 PacketLineIn.delimiter(),
963 "want " + fooChild.toObjectId().getName() + "\n",
964 "want " + barChild.toObjectId().getName() + "\n",
965 "have " + fooParent.toObjectId().getName() + "\n",
966 "done\n",
967 PacketLineIn.end());
968 PacketLineIn pckIn = new PacketLineIn(recvStream);
969
970 assertThat(pckIn.readString(), is("packfile"));
971 parsePack(recvStream);
972 assertFalse(client.getObjectDatabase().has(fooParent.toObjectId()));
973 assertTrue(client.getObjectDatabase().has(fooChild.toObjectId()));
974 assertTrue(client.getObjectDatabase().has(barParent.toObjectId()));
975 assertTrue(client.getObjectDatabase().has(barChild.toObjectId()));
976 }
977
978 @Test
979 public void testV2FetchThinPack() throws Exception {
980 String commonInBlob = "abcdefghijklmnopqrstuvwxyz";
981
982 RevBlob parentBlob = remote.blob(commonInBlob + "a");
983 RevCommit parent = remote.commit(remote.tree(remote.file("foo", parentBlob)));
984 RevBlob childBlob = remote.blob(commonInBlob + "b");
985 RevCommit child = remote.commit(remote.tree(remote.file("foo", childBlob)), parent);
986 remote.update("branch1", child);
987
988
989 ByteArrayInputStream recvStream = uploadPackV2(
990 "command=fetch\n",
991 PacketLineIn.delimiter(),
992 "want " + child.toObjectId().getName() + "\n",
993 "have " + parent.toObjectId().getName() + "\n",
994 "thin-pack\n",
995 "done\n",
996 PacketLineIn.end());
997 PacketLineIn pckIn = new PacketLineIn(recvStream);
998
999 assertThat(pckIn.readString(), is("packfile"));
1000
1001
1002
1003 thrown.expect(IOException.class);
1004 thrown.expectMessage("pack has unresolved deltas");
1005 parsePack(recvStream);
1006 }
1007
1008 @Test
1009 public void testV2FetchNoProgress() throws Exception {
1010 RevCommit commit = remote.commit().message("x").create();
1011 remote.update("branch1", commit);
1012
1013
1014 StringWriter sw = new StringWriter();
1015 ByteArrayInputStream recvStream = uploadPackV2(
1016 "command=fetch\n",
1017 PacketLineIn.delimiter(),
1018 "want " + commit.toObjectId().getName() + "\n",
1019 "done\n",
1020 PacketLineIn.end());
1021 PacketLineIn pckIn = new PacketLineIn(recvStream);
1022 assertThat(pckIn.readString(), is("packfile"));
1023 parsePack(recvStream, new TextProgressMonitor(sw));
1024 assertFalse(sw.toString().isEmpty());
1025
1026
1027 sw = new StringWriter();
1028 recvStream = uploadPackV2(
1029 "command=fetch\n",
1030 PacketLineIn.delimiter(),
1031 "want " + commit.toObjectId().getName() + "\n",
1032 "no-progress\n",
1033 "done\n",
1034 PacketLineIn.end());
1035 pckIn = new PacketLineIn(recvStream);
1036 assertThat(pckIn.readString(), is("packfile"));
1037 parsePack(recvStream, new TextProgressMonitor(sw));
1038 assertTrue(sw.toString().isEmpty());
1039 }
1040
1041 @Test
1042 public void testV2FetchIncludeTag() throws Exception {
1043 RevCommit commit = remote.commit().message("x").create();
1044 RevTag tag = remote.tag("tag", commit);
1045 remote.update("branch1", commit);
1046 remote.update("refs/tags/tag", tag);
1047
1048
1049 ByteArrayInputStream recvStream = uploadPackV2(
1050 "command=fetch\n",
1051 PacketLineIn.delimiter(),
1052 "want " + commit.toObjectId().getName() + "\n",
1053 "done\n",
1054 PacketLineIn.end());
1055 PacketLineIn pckIn = new PacketLineIn(recvStream);
1056 assertThat(pckIn.readString(), is("packfile"));
1057 parsePack(recvStream);
1058 assertFalse(client.getObjectDatabase().has(tag.toObjectId()));
1059
1060
1061 recvStream = uploadPackV2(
1062 "command=fetch\n",
1063 PacketLineIn.delimiter(),
1064 "want " + commit.toObjectId().getName() + "\n",
1065 "include-tag\n",
1066 "done\n",
1067 PacketLineIn.end());
1068 pckIn = new PacketLineIn(recvStream);
1069 assertThat(pckIn.readString(), is("packfile"));
1070 parsePack(recvStream);
1071 assertTrue(client.getObjectDatabase().has(tag.toObjectId()));
1072 }
1073
1074 @Test
1075 public void testV2FetchOfsDelta() throws Exception {
1076 String commonInBlob = "abcdefghijklmnopqrstuvwxyz";
1077
1078 RevBlob parentBlob = remote.blob(commonInBlob + "a");
1079 RevCommit parent = remote.commit(remote.tree(remote.file("foo", parentBlob)));
1080 RevBlob childBlob = remote.blob(commonInBlob + "b");
1081 RevCommit child = remote.commit(remote.tree(remote.file("foo", childBlob)), parent);
1082 remote.update("branch1", child);
1083
1084
1085 ByteArrayInputStream recvStream = uploadPackV2(
1086 "command=fetch\n",
1087 PacketLineIn.delimiter(),
1088 "want " + child.toObjectId().getName() + "\n",
1089 "done\n",
1090 PacketLineIn.end());
1091 PacketLineIn pckIn = new PacketLineIn(recvStream);
1092 assertThat(pckIn.readString(), is("packfile"));
1093 ReceivedPackStatistics receivedStats = parsePack(recvStream);
1094 assertTrue(receivedStats.getNumOfsDelta() == 0);
1095
1096
1097 recvStream = uploadPackV2(
1098 "command=fetch\n",
1099 PacketLineIn.delimiter(),
1100 "want " + child.toObjectId().getName() + "\n",
1101 "ofs-delta\n",
1102 "done\n",
1103 PacketLineIn.end());
1104 pckIn = new PacketLineIn(recvStream);
1105 assertThat(pckIn.readString(), is("packfile"));
1106 receivedStats = parsePack(recvStream);
1107 assertTrue(receivedStats.getNumOfsDelta() != 0);
1108 }
1109
1110 @Test
1111 public void testV2FetchShallow() throws Exception {
1112 RevCommit commonParent = remote.commit().message("parent").create();
1113 RevCommit fooChild = remote.commit().message("x").parent(commonParent).create();
1114 RevCommit barChild = remote.commit().message("y").parent(commonParent).create();
1115 remote.update("branch1", barChild);
1116
1117
1118
1119 ByteArrayInputStream recvStream = uploadPackV2(
1120 "command=fetch\n",
1121 PacketLineIn.delimiter(),
1122 "want " + barChild.toObjectId().getName() + "\n",
1123 "have " + fooChild.toObjectId().getName() + "\n",
1124 "done\n",
1125 PacketLineIn.end());
1126 PacketLineIn pckIn = new PacketLineIn(recvStream);
1127 assertThat(pckIn.readString(), is("packfile"));
1128 parsePack(recvStream);
1129 assertTrue(client.getObjectDatabase().has(barChild.toObjectId()));
1130 assertFalse(client.getObjectDatabase().has(commonParent.toObjectId()));
1131
1132
1133
1134 recvStream = uploadPackV2(
1135 "command=fetch\n",
1136 PacketLineIn.delimiter(),
1137 "want " + barChild.toObjectId().getName() + "\n",
1138 "have " + fooChild.toObjectId().getName() + "\n",
1139 "shallow " + fooChild.toObjectId().getName() + "\n",
1140 "done\n",
1141 PacketLineIn.end());
1142 pckIn = new PacketLineIn(recvStream);
1143 assertThat(pckIn.readString(), is("packfile"));
1144 parsePack(recvStream);
1145 assertTrue(client.getObjectDatabase().has(commonParent.toObjectId()));
1146 }
1147
1148 @Test
1149 public void testV2FetchDeepenAndDone() throws Exception {
1150 RevCommit parent = remote.commit().message("parent").create();
1151 RevCommit child = remote.commit().message("x").parent(parent).create();
1152 remote.update("branch1", child);
1153
1154
1155 ByteArrayInputStream recvStream = uploadPackV2(
1156 "command=fetch\n",
1157 PacketLineIn.delimiter(),
1158 "want " + child.toObjectId().getName() + "\n",
1159 "deepen 1\n",
1160 "done\n",
1161 PacketLineIn.end());
1162 PacketLineIn pckIn = new PacketLineIn(recvStream);
1163 assertThat(pckIn.readString(), is("shallow-info"));
1164 assertThat(pckIn.readString(), is("shallow " + child.toObjectId().getName()));
1165 assertTrue(PacketLineIn.isDelimiter(pckIn.readString()));
1166 assertThat(pckIn.readString(), is("packfile"));
1167 parsePack(recvStream);
1168 assertTrue(client.getObjectDatabase().has(child.toObjectId()));
1169 assertFalse(client.getObjectDatabase().has(parent.toObjectId()));
1170
1171
1172 recvStream = uploadPackV2(
1173 "command=fetch\n",
1174 PacketLineIn.delimiter(),
1175 "want " + child.toObjectId().getName() + "\n",
1176 "done\n",
1177 PacketLineIn.end());
1178 pckIn = new PacketLineIn(recvStream);
1179 assertThat(pckIn.readString(), is("packfile"));
1180 parsePack(recvStream);
1181 assertTrue(client.getObjectDatabase().has(parent.toObjectId()));
1182 }
1183
1184 @Test
1185 public void testV2FetchDeepenWithoutDone() throws Exception {
1186 RevCommit parent = remote.commit().message("parent").create();
1187 RevCommit child = remote.commit().message("x").parent(parent).create();
1188 remote.update("branch1", child);
1189
1190 ByteArrayInputStream recvStream = uploadPackV2(
1191 "command=fetch\n",
1192 PacketLineIn.delimiter(),
1193 "want " + child.toObjectId().getName() + "\n",
1194 "deepen 1\n",
1195 PacketLineIn.end());
1196 PacketLineIn pckIn = new PacketLineIn(recvStream);
1197
1198
1199
1200
1201 assertThat(pckIn.readString(), is("acknowledgments"));
1202 assertThat(pckIn.readString(), is("NAK"));
1203 assertTrue(PacketLineIn.isEnd(pckIn.readString()));
1204 }
1205
1206 @Test
1207 public void testV2FetchShallowSince() throws Exception {
1208 PersonIdent person = new PersonIdent(remote.getRepository());
1209
1210 RevCommit beyondBoundary = remote.commit()
1211 .committer(new PersonIdent(person, 1510000000, 0)).create();
1212 RevCommit boundary = remote.commit().parent(beyondBoundary)
1213 .committer(new PersonIdent(person, 1520000000, 0)).create();
1214 RevCommit tooOld = remote.commit()
1215 .committer(new PersonIdent(person, 1500000000, 0)).create();
1216 RevCommit merge = remote.commit().parent(boundary).parent(tooOld)
1217 .committer(new PersonIdent(person, 1530000000, 0)).create();
1218
1219 remote.update("branch1", merge);
1220
1221
1222 ByteArrayInputStream recvStream = uploadPackV2(
1223 "command=fetch\n",
1224 PacketLineIn.delimiter(),
1225 "shallow " + boundary.toObjectId().getName() + "\n",
1226 "deepen-since 1510000\n",
1227 "want " + merge.toObjectId().getName() + "\n",
1228 "have " + boundary.toObjectId().getName() + "\n",
1229 "done\n",
1230 PacketLineIn.end());
1231 PacketLineIn pckIn = new PacketLineIn(recvStream);
1232 assertThat(pckIn.readString(), is("shallow-info"));
1233
1234
1235
1236 assertThat(pckIn.readString(), is("shallow " + merge.toObjectId().getName()));
1237
1238
1239
1240 assertThat(pckIn.readString(), is("unshallow " + boundary.toObjectId().getName()));
1241
1242 assertTrue(PacketLineIn.isDelimiter(pckIn.readString()));
1243 assertThat(pckIn.readString(), is("packfile"));
1244 parsePack(recvStream);
1245
1246
1247
1248 assertFalse(client.getObjectDatabase().has(tooOld.toObjectId()));
1249
1250
1251
1252 assertFalse(client.getObjectDatabase().has(boundary.toObjectId()));
1253
1254
1255 assertTrue(client.getObjectDatabase().has(beyondBoundary.toObjectId()));
1256 assertTrue(client.getObjectDatabase().has(merge.toObjectId()));
1257 }
1258
1259 @Test
1260 public void testV2FetchShallowSince_excludedParentWithMultipleChildren() throws Exception {
1261 PersonIdent person = new PersonIdent(remote.getRepository());
1262
1263 RevCommit base = remote.commit()
1264 .committer(new PersonIdent(person, 1500000000, 0)).create();
1265 RevCommit child1 = remote.commit().parent(base)
1266 .committer(new PersonIdent(person, 1510000000, 0)).create();
1267 RevCommit child2 = remote.commit().parent(base)
1268 .committer(new PersonIdent(person, 1520000000, 0)).create();
1269
1270 remote.update("branch1", child1);
1271 remote.update("branch2", child2);
1272
1273 ByteArrayInputStream recvStream = uploadPackV2(
1274 "command=fetch\n",
1275 PacketLineIn.delimiter(),
1276 "deepen-since 1510000\n",
1277 "want " + child1.toObjectId().getName() + "\n",
1278 "want " + child2.toObjectId().getName() + "\n",
1279 "done\n",
1280 PacketLineIn.end());
1281 PacketLineIn pckIn = new PacketLineIn(recvStream);
1282 assertThat(pckIn.readString(), is("shallow-info"));
1283
1284
1285 assertThat(
1286 Arrays.asList(pckIn.readString(), pckIn.readString()),
1287 hasItems(
1288 "shallow " + child1.toObjectId().getName(),
1289 "shallow " + child2.toObjectId().getName()));
1290
1291 assertTrue(PacketLineIn.isDelimiter(pckIn.readString()));
1292 assertThat(pckIn.readString(), is("packfile"));
1293 parsePack(recvStream);
1294
1295
1296 assertFalse(client.getObjectDatabase().has(base.toObjectId()));
1297 assertTrue(client.getObjectDatabase().has(child1.toObjectId()));
1298 assertTrue(client.getObjectDatabase().has(child2.toObjectId()));
1299 }
1300
1301 @Test
1302 public void testV2FetchShallowSince_noCommitsSelected() throws Exception {
1303 PersonIdent person = new PersonIdent(remote.getRepository());
1304
1305 RevCommit tooOld = remote.commit()
1306 .committer(new PersonIdent(person, 1500000000, 0)).create();
1307
1308 remote.update("branch1", tooOld);
1309
1310 thrown.expect(PackProtocolException.class);
1311 thrown.expectMessage("No commits selected for shallow request");
1312 uploadPackV2(
1313 "command=fetch\n",
1314 PacketLineIn.delimiter(),
1315 "deepen-since 1510000\n",
1316 "want " + tooOld.toObjectId().getName() + "\n",
1317 "done\n",
1318 PacketLineIn.end());
1319 }
1320
1321 @Test
1322 public void testV2FetchDeepenNot() throws Exception {
1323 RevCommit one = remote.commit().message("one").create();
1324 RevCommit two = remote.commit().message("two").parent(one).create();
1325 RevCommit three = remote.commit().message("three").parent(two).create();
1326 RevCommit side = remote.commit().message("side").parent(one).create();
1327 RevCommit merge = remote.commit().message("merge")
1328 .parent(three).parent(side).create();
1329
1330 remote.update("branch1", merge);
1331 remote.update("side", side);
1332
1333
1334
1335 ByteArrayInputStream recvStream = uploadPackV2(
1336 "command=fetch\n",
1337 PacketLineIn.delimiter(),
1338 "shallow " + three.toObjectId().getName() + "\n",
1339 "deepen-not side\n",
1340 "want " + merge.toObjectId().getName() + "\n",
1341 "have " + three.toObjectId().getName() + "\n",
1342 "done\n",
1343 PacketLineIn.end());
1344 PacketLineIn pckIn = new PacketLineIn(recvStream);
1345 assertThat(pckIn.readString(), is("shallow-info"));
1346
1347
1348
1349 assertThat(
1350 Arrays.asList(pckIn.readString(), pckIn.readString()),
1351 hasItems(
1352 "shallow " + merge.toObjectId().getName(),
1353 "shallow " + two.toObjectId().getName()));
1354
1355
1356 assertThat(pckIn.readString(), is("unshallow " + three.toObjectId().getName()));
1357
1358 assertTrue(PacketLineIn.isDelimiter(pckIn.readString()));
1359 assertThat(pckIn.readString(), is("packfile"));
1360 parsePack(recvStream);
1361
1362
1363
1364 assertFalse(client.getObjectDatabase().has(side.toObjectId()));
1365 assertFalse(client.getObjectDatabase().has(one.toObjectId()));
1366
1367
1368
1369 assertFalse(client.getObjectDatabase().has(three.toObjectId()));
1370
1371
1372 assertTrue(client.getObjectDatabase().has(merge.toObjectId()));
1373 assertTrue(client.getObjectDatabase().has(two.toObjectId()));
1374 }
1375
1376 @Test
1377 public void testV2FetchDeepenNot_excludeDescendantOfWant() throws Exception {
1378 RevCommit one = remote.commit().message("one").create();
1379 RevCommit two = remote.commit().message("two").parent(one).create();
1380 RevCommit three = remote.commit().message("three").parent(two).create();
1381 RevCommit four = remote.commit().message("four").parent(three).create();
1382
1383 remote.update("two", two);
1384 remote.update("four", four);
1385
1386 thrown.expect(PackProtocolException.class);
1387 thrown.expectMessage("No commits selected for shallow request");
1388 uploadPackV2(
1389 "command=fetch\n",
1390 PacketLineIn.delimiter(),
1391 "deepen-not four\n",
1392 "want " + two.toObjectId().getName() + "\n",
1393 "done\n",
1394 PacketLineIn.end());
1395 }
1396
1397 @Test
1398 public void testV2FetchDeepenNot_supportAnnotatedTags() throws Exception {
1399 RevCommit one = remote.commit().message("one").create();
1400 RevCommit two = remote.commit().message("two").parent(one).create();
1401 RevCommit three = remote.commit().message("three").parent(two).create();
1402 RevCommit four = remote.commit().message("four").parent(three).create();
1403 RevTag twoTag = remote.tag("twotag", two);
1404
1405 remote.update("refs/tags/twotag", twoTag);
1406 remote.update("four", four);
1407
1408 ByteArrayInputStream recvStream = uploadPackV2(
1409 "command=fetch\n",
1410 PacketLineIn.delimiter(),
1411 "deepen-not twotag\n",
1412 "want " + four.toObjectId().getName() + "\n",
1413 "done\n",
1414 PacketLineIn.end());
1415 PacketLineIn pckIn = new PacketLineIn(recvStream);
1416 assertThat(pckIn.readString(), is("shallow-info"));
1417 assertThat(pckIn.readString(), is("shallow " + three.toObjectId().getName()));
1418 assertTrue(PacketLineIn.isDelimiter(pckIn.readString()));
1419 assertThat(pckIn.readString(), is("packfile"));
1420 parsePack(recvStream);
1421 assertFalse(client.getObjectDatabase().has(one.toObjectId()));
1422 assertFalse(client.getObjectDatabase().has(two.toObjectId()));
1423 assertTrue(client.getObjectDatabase().has(three.toObjectId()));
1424 assertTrue(client.getObjectDatabase().has(four.toObjectId()));
1425 }
1426
1427 @Test
1428 public void testV2FetchDeepenNot_excludedParentWithMultipleChildren() throws Exception {
1429 PersonIdent person = new PersonIdent(remote.getRepository());
1430
1431 RevCommit base = remote.commit()
1432 .committer(new PersonIdent(person, 1500000000, 0)).create();
1433 RevCommit child1 = remote.commit().parent(base)
1434 .committer(new PersonIdent(person, 1510000000, 0)).create();
1435 RevCommit child2 = remote.commit().parent(base)
1436 .committer(new PersonIdent(person, 1520000000, 0)).create();
1437
1438 remote.update("base", base);
1439 remote.update("branch1", child1);
1440 remote.update("branch2", child2);
1441
1442 ByteArrayInputStream recvStream = uploadPackV2(
1443 "command=fetch\n",
1444 PacketLineIn.delimiter(),
1445 "deepen-not base\n",
1446 "want " + child1.toObjectId().getName() + "\n",
1447 "want " + child2.toObjectId().getName() + "\n",
1448 "done\n",
1449 PacketLineIn.end());
1450 PacketLineIn pckIn = new PacketLineIn(recvStream);
1451 assertThat(pckIn.readString(), is("shallow-info"));
1452
1453
1454 assertThat(
1455 Arrays.asList(pckIn.readString(), pckIn.readString()),
1456 hasItems(
1457 "shallow " + child1.toObjectId().getName(),
1458 "shallow " + child2.toObjectId().getName()));
1459
1460 assertTrue(PacketLineIn.isDelimiter(pckIn.readString()));
1461 assertThat(pckIn.readString(), is("packfile"));
1462 parsePack(recvStream);
1463
1464
1465 assertFalse(client.getObjectDatabase().has(base.toObjectId()));
1466 assertTrue(client.getObjectDatabase().has(child1.toObjectId()));
1467 assertTrue(client.getObjectDatabase().has(child2.toObjectId()));
1468 }
1469
1470 @Test
1471 public void testV2FetchUnrecognizedArgument() throws Exception {
1472 thrown.expect(PackProtocolException.class);
1473 thrown.expectMessage("unexpected invalid-argument");
1474 uploadPackV2(
1475 "command=fetch\n",
1476 PacketLineIn.delimiter(),
1477 "invalid-argument\n",
1478 PacketLineIn.end());
1479 }
1480
1481 @Test
1482 public void testV2FetchServerOptions() throws Exception {
1483 String[] lines = { "command=fetch\n", "server-option=one\n",
1484 "server-option=two\n", PacketLineIn.delimiter(),
1485 PacketLineIn.end() };
1486
1487 TestV2Hook testHook = new TestV2Hook();
1488 uploadPackV2Setup(null, null, testHook, lines);
1489
1490 FetchV2Request req = testHook.fetchRequest;
1491 assertNotNull(req);
1492 assertEquals(2, req.getServerOptions().size());
1493 assertThat(req.getServerOptions(), hasItems("one", "two"));
1494 }
1495
1496 @Test
1497 public void testV2FetchFilter() throws Exception {
1498 RevBlob big = remote.blob("foobar");
1499 RevBlob small = remote.blob("fooba");
1500 RevTree tree = remote.tree(remote.file("1", big),
1501 remote.file("2", small));
1502 RevCommit commit = remote.commit(tree);
1503 remote.update("master", commit);
1504
1505 server.getConfig().setBoolean("uploadpack", null, "allowfilter", true);
1506
1507 ByteArrayInputStream recvStream = uploadPackV2(
1508 "command=fetch\n",
1509 PacketLineIn.delimiter(),
1510 "want " + commit.toObjectId().getName() + "\n",
1511 "filter blob:limit=5\n",
1512 "done\n",
1513 PacketLineIn.end());
1514 PacketLineIn pckIn = new PacketLineIn(recvStream);
1515 assertThat(pckIn.readString(), is("packfile"));
1516 parsePack(recvStream);
1517
1518 assertFalse(client.getObjectDatabase().has(big.toObjectId()));
1519 assertTrue(client.getObjectDatabase().has(small.toObjectId()));
1520 }
1521
1522 abstract class TreeBuilder {
1523 abstract void addElements(DirCacheBuilder dcBuilder) throws Exception;
1524
1525 RevTree build() throws Exception {
1526 DirCache dc = DirCache.newInCore();
1527 DirCacheBuilder dcBuilder = dc.builder();
1528 addElements(dcBuilder);
1529 dcBuilder.finish();
1530 ObjectId id;
1531 try (ObjectInserter ins =
1532 remote.getRepository().newObjectInserter()) {
1533 id = dc.writeTree(ins);
1534 ins.flush();
1535 }
1536 return remote.getRevWalk().parseTree(id);
1537 }
1538 }
1539
1540 class DeepTreePreparator {
1541 RevBlob blobLowDepth = remote.blob("lo");
1542 RevBlob blobHighDepth = remote.blob("hi");
1543
1544 RevTree subtree = remote.tree(remote.file("1", blobHighDepth));
1545 RevTree rootTree = (new TreeBuilder() {
1546 @Override
1547 void addElements(DirCacheBuilder dcBuilder) throws Exception {
1548 dcBuilder.add(remote.file("1", blobLowDepth));
1549 dcBuilder.addTree(new byte[] {'2'}, DirCacheEntry.STAGE_0,
1550 remote.getRevWalk().getObjectReader(), subtree);
1551 }
1552 }).build();
1553 RevCommit commit = remote.commit(rootTree);
1554
1555 DeepTreePreparator() throws Exception {}
1556 }
1557
1558 private void uploadV2WithTreeDepthFilter(
1559 long depth, ObjectId... wants) throws Exception {
1560 server.getConfig().setBoolean("uploadpack", null, "allowfilter", true);
1561
1562 List<String> input = new ArrayList<>();
1563 input.add("command=fetch\n");
1564 input.add(PacketLineIn.delimiter());
1565 for (ObjectId want : wants) {
1566 input.add("want " + want.getName() + "\n");
1567 }
1568 input.add("filter tree:" + depth + "\n");
1569 input.add("done\n");
1570 input.add(PacketLineIn.end());
1571 ByteArrayInputStream recvStream =
1572 uploadPackV2(RequestPolicy.ANY, null,
1573 null, input.toArray(new String[0]));
1574 PacketLineIn pckIn = new PacketLineIn(recvStream);
1575 assertThat(pckIn.readString(), is("packfile"));
1576 parsePack(recvStream);
1577 }
1578
1579 @Test
1580 public void testV2FetchFilterTreeDepth0() throws Exception {
1581 DeepTreePreparator preparator = new DeepTreePreparator();
1582 remote.update("master", preparator.commit);
1583
1584 uploadV2WithTreeDepthFilter(0, preparator.commit.toObjectId());
1585
1586 assertFalse(client.getObjectDatabase()
1587 .has(preparator.rootTree.toObjectId()));
1588 assertFalse(client.getObjectDatabase()
1589 .has(preparator.subtree.toObjectId()));
1590 assertFalse(client.getObjectDatabase()
1591 .has(preparator.blobLowDepth.toObjectId()));
1592 assertFalse(client.getObjectDatabase()
1593 .has(preparator.blobHighDepth.toObjectId()));
1594 assertEquals(1, stats.getTreesTraversed());
1595 }
1596
1597 @Test
1598 public void testV2FetchFilterTreeDepth1_serverHasBitmap() throws Exception {
1599 DeepTreePreparator preparator = new DeepTreePreparator();
1600 remote.update("master", preparator.commit);
1601
1602
1603
1604 generateBitmaps(server);
1605
1606 uploadV2WithTreeDepthFilter(1, preparator.commit.toObjectId());
1607
1608 assertTrue(client.getObjectDatabase()
1609 .has(preparator.rootTree.toObjectId()));
1610 assertFalse(client.getObjectDatabase()
1611 .has(preparator.subtree.toObjectId()));
1612 assertFalse(client.getObjectDatabase()
1613 .has(preparator.blobLowDepth.toObjectId()));
1614 assertFalse(client.getObjectDatabase()
1615 .has(preparator.blobHighDepth.toObjectId()));
1616 assertEquals(1, stats.getTreesTraversed());
1617 }
1618
1619 @Test
1620 public void testV2FetchFilterTreeDepth2() throws Exception {
1621 DeepTreePreparator preparator = new DeepTreePreparator();
1622 remote.update("master", preparator.commit);
1623
1624 uploadV2WithTreeDepthFilter(2, preparator.commit.toObjectId());
1625
1626 assertTrue(client.getObjectDatabase()
1627 .has(preparator.rootTree.toObjectId()));
1628 assertTrue(client.getObjectDatabase()
1629 .has(preparator.subtree.toObjectId()));
1630 assertTrue(client.getObjectDatabase()
1631 .has(preparator.blobLowDepth.toObjectId()));
1632 assertFalse(client.getObjectDatabase()
1633 .has(preparator.blobHighDepth.toObjectId()));
1634 assertEquals(2, stats.getTreesTraversed());
1635 }
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645 class RepeatedSubtreePreparator {
1646 RevBlob foo = remote.blob("foo");
1647 RevTree subtree3 = remote.tree(remote.file("foo", foo));
1648 RevTree subtree2 = (new TreeBuilder() {
1649 @Override
1650 void addElements(DirCacheBuilder dcBuilder) throws Exception {
1651 dcBuilder.addTree(new byte[] {'b'}, DirCacheEntry.STAGE_0,
1652 remote.getRevWalk().getObjectReader(), subtree3);
1653 }
1654 }).build();
1655 RevTree subtree1 = (new TreeBuilder() {
1656 @Override
1657 void addElements(DirCacheBuilder dcBuilder) throws Exception {
1658 dcBuilder.addTree(new byte[] {'x'}, DirCacheEntry.STAGE_0,
1659 remote.getRevWalk().getObjectReader(), subtree2);
1660 }
1661 }).build();
1662 RevTree rootTree = (new TreeBuilder() {
1663 @Override
1664 void addElements(DirCacheBuilder dcBuilder) throws Exception {
1665 dcBuilder.addTree(new byte[] {'a'}, DirCacheEntry.STAGE_0,
1666 remote.getRevWalk().getObjectReader(), subtree1);
1667 dcBuilder.addTree(new byte[] {'x'}, DirCacheEntry.STAGE_0,
1668 remote.getRevWalk().getObjectReader(), subtree2);
1669 }
1670 }).build();
1671 RevCommit commit = remote.commit(rootTree);
1672
1673 RepeatedSubtreePreparator() throws Exception {}
1674 }
1675
1676 @Test
1677 public void testV2FetchFilterTreeDepth_iterateOverTreeAtTwoLevels()
1678 throws Exception {
1679
1680
1681
1682 RepeatedSubtreePreparator preparator = new RepeatedSubtreePreparator();
1683 remote.update("master", preparator.commit);
1684
1685 uploadV2WithTreeDepthFilter(4, preparator.commit.toObjectId());
1686
1687 assertTrue(client.getObjectDatabase()
1688 .has(preparator.foo.toObjectId()));
1689 }
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707 class RepeatedSubtreeAtSameLevelPreparator {
1708 RevBlob foo = remote.blob("foo");
1709
1710
1711 RevTree subtree1 = remote.tree(remote.file("foo", foo));
1712
1713
1714 RevTree subtree2 = (new TreeBuilder() {
1715 @Override
1716 void addElements(DirCacheBuilder dcBuilder) throws Exception {
1717 dcBuilder.addTree(new byte[] {'b'}, DirCacheEntry.STAGE_0,
1718 remote.getRevWalk().getObjectReader(), subtree1);
1719 }
1720 }).build();
1721
1722
1723 RevTree subtree3 = (new TreeBuilder() {
1724 @Override
1725 void addElements(DirCacheBuilder dcBuilder) throws Exception {
1726 dcBuilder.addTree(new byte[] {'x'}, DirCacheEntry.STAGE_0,
1727 remote.getRevWalk().getObjectReader(), subtree2);
1728 }
1729 }).build();
1730
1731 RevBlob baz = remote.blob("baz");
1732
1733
1734 RevTree subtree4 = remote.tree(remote.file("baz", baz));
1735
1736
1737 RevTree subtree5 = (new TreeBuilder() {
1738 @Override
1739 void addElements(DirCacheBuilder dcBuilder) throws Exception {
1740 dcBuilder.addTree(new byte[] {'c'}, DirCacheEntry.STAGE_0,
1741 remote.getRevWalk().getObjectReader(), subtree4);
1742 }
1743 }).build();
1744
1745
1746 RevTree subtree6 = (new TreeBuilder() {
1747 @Override
1748 void addElements(DirCacheBuilder dcBuilder) throws Exception {
1749 dcBuilder.addTree(new byte[] {'u'}, DirCacheEntry.STAGE_0,
1750 remote.getRevWalk().getObjectReader(), subtree5);
1751 }
1752 }).build();
1753
1754
1755 RevTree subtree7 = (new TreeBuilder() {
1756 @Override
1757 void addElements(DirCacheBuilder dcBuilder) throws Exception {
1758 dcBuilder.addTree(new byte[] {'v'}, DirCacheEntry.STAGE_0,
1759 remote.getRevWalk().getObjectReader(), subtree5);
1760 }
1761 }).build();
1762
1763 RevTree rootTree = (new TreeBuilder() {
1764 @Override
1765 void addElements(DirCacheBuilder dcBuilder) throws Exception {
1766 dcBuilder.addTree(new byte[] {'a'}, DirCacheEntry.STAGE_0,
1767 remote.getRevWalk().getObjectReader(), subtree3);
1768 dcBuilder.addTree(new byte[] {'b'}, DirCacheEntry.STAGE_0,
1769 remote.getRevWalk().getObjectReader(), subtree6);
1770 dcBuilder.addTree(new byte[] {'y'}, DirCacheEntry.STAGE_0,
1771 remote.getRevWalk().getObjectReader(), subtree3);
1772 dcBuilder.addTree(new byte[] {'z'}, DirCacheEntry.STAGE_0,
1773 remote.getRevWalk().getObjectReader(), subtree7);
1774 }
1775 }).build();
1776 RevCommit commit = remote.commit(rootTree);
1777
1778 RepeatedSubtreeAtSameLevelPreparator() throws Exception {}
1779 }
1780
1781 @Test
1782 public void testV2FetchFilterTreeDepth_repeatTreeAtSameLevelIncludeFile()
1783 throws Exception {
1784 RepeatedSubtreeAtSameLevelPreparator preparator =
1785 new RepeatedSubtreeAtSameLevelPreparator();
1786 remote.update("master", preparator.commit);
1787
1788 uploadV2WithTreeDepthFilter(5, preparator.commit.toObjectId());
1789
1790 assertTrue(client.getObjectDatabase()
1791 .has(preparator.foo.toObjectId()));
1792 assertTrue(client.getObjectDatabase()
1793 .has(preparator.baz.toObjectId()));
1794 assertEquals(8, stats.getTreesTraversed());
1795 }
1796
1797 @Test
1798 public void testV2FetchFilterTreeDepth_repeatTreeAtSameLevelExcludeFile()
1799 throws Exception {
1800 RepeatedSubtreeAtSameLevelPreparator preparator =
1801 new RepeatedSubtreeAtSameLevelPreparator();
1802 remote.update("master", preparator.commit);
1803
1804 uploadV2WithTreeDepthFilter(4, preparator.commit.toObjectId());
1805
1806 assertFalse(client.getObjectDatabase()
1807 .has(preparator.foo.toObjectId()));
1808 assertFalse(client.getObjectDatabase()
1809 .has(preparator.baz.toObjectId()));
1810 assertEquals(8, stats.getTreesTraversed());
1811 }
1812
1813 @Test
1814 public void testWantFilteredObject() throws Exception {
1815 RepeatedSubtreePreparator preparator = new RepeatedSubtreePreparator();
1816 remote.update("master", preparator.commit);
1817
1818
1819
1820 uploadV2WithTreeDepthFilter(
1821 3,
1822 preparator.commit.toObjectId(),
1823 preparator.foo.toObjectId());
1824 assertTrue(client.getObjectDatabase()
1825 .has(preparator.foo.toObjectId()));
1826
1827 client = newRepo("client");
1828
1829
1830 uploadV2WithTreeDepthFilter(
1831 2,
1832 preparator.commit.toObjectId(),
1833 preparator.subtree3.toObjectId());
1834 assertTrue(client.getObjectDatabase()
1835 .has(preparator.foo.toObjectId()));
1836 assertTrue(client.getObjectDatabase()
1837 .has(preparator.subtree3.toObjectId()));
1838 }
1839
1840 @Test
1841 public void testV2FetchFilterWhenNotAllowed() throws Exception {
1842 RevCommit commit = remote.commit().message("0").create();
1843 remote.update("master", commit);
1844
1845 server.getConfig().setBoolean("uploadpack", null, "allowfilter", false);
1846
1847 thrown.expect(PackProtocolException.class);
1848 thrown.expectMessage("unexpected filter blob:limit=5");
1849 uploadPackV2(
1850 "command=fetch\n",
1851 PacketLineIn.delimiter(),
1852 "want " + commit.toObjectId().getName() + "\n",
1853 "filter blob:limit=5\n",
1854 "done\n",
1855 PacketLineIn.end());
1856 }
1857
1858 @Test
1859 public void testV2FetchWantRefIfNotAllowed() throws Exception {
1860 RevCommit one = remote.commit().message("1").create();
1861 remote.update("one", one);
1862
1863 try {
1864 uploadPackV2(
1865 "command=fetch\n",
1866 PacketLineIn.delimiter(),
1867 "want-ref refs/heads/one\n",
1868 "done\n",
1869 PacketLineIn.end());
1870 } catch (PackProtocolException e) {
1871 assertThat(
1872 e.getMessage(),
1873 containsString("unexpected want-ref refs/heads/one"));
1874 return;
1875 }
1876 fail("expected PackProtocolException");
1877 }
1878
1879 @Test
1880 public void testV2FetchWantRef() throws Exception {
1881 RevCommit one = remote.commit().message("1").create();
1882 RevCommit two = remote.commit().message("2").create();
1883 RevCommit three = remote.commit().message("3").create();
1884 remote.update("one", one);
1885 remote.update("two", two);
1886 remote.update("three", three);
1887
1888 server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true);
1889
1890 ByteArrayInputStream recvStream = uploadPackV2(
1891 "command=fetch\n",
1892 PacketLineIn.delimiter(),
1893 "want-ref refs/heads/one\n",
1894 "want-ref refs/heads/two\n",
1895 "done\n",
1896 PacketLineIn.end());
1897 PacketLineIn pckIn = new PacketLineIn(recvStream);
1898 assertThat(pckIn.readString(), is("wanted-refs"));
1899 assertThat(
1900 Arrays.asList(pckIn.readString(), pckIn.readString()),
1901 hasItems(
1902 one.toObjectId().getName() + " refs/heads/one",
1903 two.toObjectId().getName() + " refs/heads/two"));
1904 assertTrue(PacketLineIn.isDelimiter(pckIn.readString()));
1905 assertThat(pckIn.readString(), is("packfile"));
1906 parsePack(recvStream);
1907
1908 assertTrue(client.getObjectDatabase().has(one.toObjectId()));
1909 assertTrue(client.getObjectDatabase().has(two.toObjectId()));
1910 assertFalse(client.getObjectDatabase().has(three.toObjectId()));
1911 }
1912
1913 @Test
1914 public void testV2FetchBadWantRef() throws Exception {
1915 RevCommit one = remote.commit().message("1").create();
1916 remote.update("one", one);
1917
1918 server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true);
1919
1920 try {
1921 uploadPackV2(
1922 "command=fetch\n",
1923 PacketLineIn.delimiter(),
1924 "want-ref refs/heads/one\n",
1925 "want-ref refs/heads/nonExistentRef\n",
1926 "done\n",
1927 PacketLineIn.end());
1928 } catch (PackProtocolException e) {
1929 assertThat(
1930 e.getMessage(),
1931 containsString("Invalid ref name: refs/heads/nonExistentRef"));
1932 return;
1933 }
1934 fail("expected PackProtocolException");
1935 }
1936
1937 @Test
1938 public void testV2FetchMixedWantRef() throws Exception {
1939 RevCommit one = remote.commit().message("1").create();
1940 RevCommit two = remote.commit().message("2").create();
1941 RevCommit three = remote.commit().message("3").create();
1942 remote.update("one", one);
1943 remote.update("two", two);
1944 remote.update("three", three);
1945
1946 server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true);
1947
1948 ByteArrayInputStream recvStream = uploadPackV2(
1949 "command=fetch\n",
1950 PacketLineIn.delimiter(),
1951 "want-ref refs/heads/one\n",
1952 "want " + two.toObjectId().getName() + "\n",
1953 "done\n",
1954 PacketLineIn.end());
1955 PacketLineIn pckIn = new PacketLineIn(recvStream);
1956 assertThat(pckIn.readString(), is("wanted-refs"));
1957 assertThat(
1958 pckIn.readString(),
1959 is(one.toObjectId().getName() + " refs/heads/one"));
1960 assertTrue(PacketLineIn.isDelimiter(pckIn.readString()));
1961 assertThat(pckIn.readString(), is("packfile"));
1962 parsePack(recvStream);
1963
1964 assertTrue(client.getObjectDatabase().has(one.toObjectId()));
1965 assertTrue(client.getObjectDatabase().has(two.toObjectId()));
1966 assertFalse(client.getObjectDatabase().has(three.toObjectId()));
1967 }
1968
1969 @Test
1970 public void testV2FetchWantRefWeAlreadyHave() throws Exception {
1971 RevCommit one = remote.commit().message("1").create();
1972 remote.update("one", one);
1973
1974 server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true);
1975
1976 ByteArrayInputStream recvStream = uploadPackV2(
1977 "command=fetch\n",
1978 PacketLineIn.delimiter(),
1979 "want-ref refs/heads/one\n",
1980 "have " + one.toObjectId().getName(),
1981 "done\n",
1982 PacketLineIn.end());
1983 PacketLineIn pckIn = new PacketLineIn(recvStream);
1984
1985
1986
1987
1988 assertThat(pckIn.readString(), is("wanted-refs"));
1989 assertThat(
1990 pckIn.readString(),
1991 is(one.toObjectId().getName() + " refs/heads/one"));
1992 assertTrue(PacketLineIn.isDelimiter(pckIn.readString()));
1993
1994
1995 assertThat(pckIn.readString(), is("packfile"));
1996 parsePack(recvStream);
1997 assertFalse(client.getObjectDatabase().has(one.toObjectId()));
1998 }
1999
2000 @Test
2001 public void testV2FetchWantRefAndDeepen() throws Exception {
2002 RevCommit parent = remote.commit().message("parent").create();
2003 RevCommit child = remote.commit().message("x").parent(parent).create();
2004 remote.update("branch1", child);
2005
2006 server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true);
2007
2008 ByteArrayInputStream recvStream = uploadPackV2(
2009 "command=fetch\n",
2010 PacketLineIn.delimiter(),
2011 "want-ref refs/heads/branch1\n",
2012 "deepen 1\n",
2013 "done\n",
2014 PacketLineIn.end());
2015 PacketLineIn pckIn = new PacketLineIn(recvStream);
2016
2017
2018 assertThat(pckIn.readString(), is("shallow-info"));
2019 assertThat(pckIn.readString(), is("shallow " + child.toObjectId().getName()));
2020 assertTrue(PacketLineIn.isDelimiter(pckIn.readString()));
2021 assertThat(pckIn.readString(), is("wanted-refs"));
2022 assertThat(pckIn.readString(), is(child.toObjectId().getName() + " refs/heads/branch1"));
2023 assertTrue(PacketLineIn.isDelimiter(pckIn.readString()));
2024 assertThat(pckIn.readString(), is("packfile"));
2025 parsePack(recvStream);
2026 assertTrue(client.getObjectDatabase().has(child.toObjectId()));
2027 assertFalse(client.getObjectDatabase().has(parent.toObjectId()));
2028 }
2029
2030 @Test
2031 public void testV2FetchMissingShallow() throws Exception {
2032 RevCommit one = remote.commit().message("1").create();
2033 RevCommit two = remote.commit().message("2").parent(one).create();
2034 RevCommit three = remote.commit().message("3").parent(two).create();
2035 remote.update("three", three);
2036
2037 server.getConfig().setBoolean("uploadpack", null, "allowrefinwant",
2038 true);
2039
2040 ByteArrayInputStream recvStream = uploadPackV2("command=fetch\n",
2041 PacketLineIn.delimiter(),
2042 "want-ref refs/heads/three\n",
2043 "deepen 3",
2044 "shallow 0123012301230123012301230123012301230123",
2045 "shallow " + two.getName() + '\n',
2046 "done\n",
2047 PacketLineIn.end());
2048 PacketLineIn pckIn = new PacketLineIn(recvStream);
2049
2050 assertThat(pckIn.readString(), is("shallow-info"));
2051 assertThat(pckIn.readString(),
2052 is("shallow " + one.toObjectId().getName()));
2053 assertThat(pckIn.readString(),
2054 is("unshallow " + two.toObjectId().getName()));
2055 assertTrue(PacketLineIn.isDelimiter(pckIn.readString()));
2056 assertThat(pckIn.readString(), is("wanted-refs"));
2057 assertThat(pckIn.readString(),
2058 is(three.toObjectId().getName() + " refs/heads/three"));
2059 assertTrue(PacketLineIn.isDelimiter(pckIn.readString()));
2060 assertThat(pckIn.readString(), is("packfile"));
2061 parsePack(recvStream);
2062
2063 assertTrue(client.getObjectDatabase().has(one.toObjectId()));
2064 assertTrue(client.getObjectDatabase().has(two.toObjectId()));
2065 assertTrue(client.getObjectDatabase().has(three.toObjectId()));
2066 }
2067
2068 @Test
2069 public void testGetPeerAgentProtocolV0() throws Exception {
2070 RevCommit one = remote.commit().message("1").create();
2071 remote.update("one", one);
2072
2073 UploadPack up = new UploadPack(server);
2074 ByteArrayInputStream send = linesAsInputStream(
2075 "want " + one.getName() + " agent=JGit-test/1.2.3\n",
2076 PacketLineIn.end(),
2077 "have 11cedf1b796d44207da702f7d420684022fc0f09\n", "done\n");
2078
2079 ByteArrayOutputStream recv = new ByteArrayOutputStream();
2080 up.upload(send, recv, null);
2081
2082 assertEquals(up.getPeerUserAgent(), "JGit-test/1.2.3");
2083 }
2084
2085 @Test
2086 public void testGetPeerAgentProtocolV2() throws Exception {
2087 server.getConfig().setString("protocol", null, "version", "2");
2088
2089 RevCommit one = remote.commit().message("1").create();
2090 remote.update("one", one);
2091
2092 UploadPack up = new UploadPack(server);
2093 up.setExtraParameters(Sets.of("version=2"));
2094
2095 ByteArrayInputStream send = linesAsInputStream(
2096 "command=fetch\n", "agent=JGit-test/1.2.4\n",
2097 PacketLineIn.delimiter(), "want " + one.getName() + "\n",
2098 "have 11cedf1b796d44207da702f7d420684022fc0f09\n", "done\n",
2099 PacketLineIn.end());
2100
2101 ByteArrayOutputStream recv = new ByteArrayOutputStream();
2102 up.upload(send, recv, null);
2103
2104 assertEquals(up.getPeerUserAgent(), "JGit-test/1.2.4");
2105 }
2106
2107 private static class RejectAllRefFilter implements RefFilter {
2108 @Override
2109 public Map<String, Ref> filter(Map<String, Ref> refs) {
2110 return new HashMap<>();
2111 }
2112 }
2113 }