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