1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.internal.storage.file;
45
46 import static org.eclipse.jgit.internal.storage.pack.PackWriter.NONE;
47 import static org.eclipse.jgit.lib.Constants.INFO_ALTERNATES;
48 import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
49 import static org.junit.Assert.assertEquals;
50 import static org.junit.Assert.assertFalse;
51 import static org.junit.Assert.assertNotNull;
52 import static org.junit.Assert.assertTrue;
53 import static org.junit.Assert.fail;
54
55 import java.io.ByteArrayInputStream;
56 import java.io.ByteArrayOutputStream;
57 import java.io.File;
58 import java.io.FileOutputStream;
59 import java.io.IOException;
60 import java.text.ParseException;
61 import java.util.ArrayList;
62 import java.util.Arrays;
63 import java.util.Collections;
64 import java.util.HashSet;
65 import java.util.List;
66 import java.util.Set;
67
68 import org.eclipse.jgit.errors.MissingObjectException;
69 import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry;
70 import org.eclipse.jgit.internal.storage.pack.PackWriter;
71 import org.eclipse.jgit.junit.JGitTestUtil;
72 import org.eclipse.jgit.junit.TestRepository;
73 import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
74 import org.eclipse.jgit.lib.NullProgressMonitor;
75 import org.eclipse.jgit.lib.ObjectId;
76 import org.eclipse.jgit.lib.ObjectIdSet;
77 import org.eclipse.jgit.lib.ObjectInserter;
78 import org.eclipse.jgit.lib.Repository;
79 import org.eclipse.jgit.lib.Sets;
80 import org.eclipse.jgit.revwalk.DepthWalk;
81 import org.eclipse.jgit.revwalk.ObjectWalk;
82 import org.eclipse.jgit.revwalk.RevBlob;
83 import org.eclipse.jgit.revwalk.RevCommit;
84 import org.eclipse.jgit.revwalk.RevObject;
85 import org.eclipse.jgit.revwalk.RevWalk;
86 import org.eclipse.jgit.storage.pack.PackConfig;
87 import org.eclipse.jgit.storage.pack.PackStatistics;
88 import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
89 import org.eclipse.jgit.transport.PackParser;
90 import org.junit.After;
91 import org.junit.Before;
92 import org.junit.Test;
93
94 public class PackWriterTest extends SampleDataRepositoryTestCase {
95
96 private static final List<RevObject> EMPTY_LIST_REVS = Collections
97 .<RevObject> emptyList();
98
99 private static final Set<ObjectIdSet> EMPTY_ID_SET = Collections
100 .<ObjectIdSet> emptySet();
101
102 private PackConfig config;
103
104 private PackWriter writer;
105
106 private ByteArrayOutputStream os;
107
108 private PackFile pack;
109
110 private ObjectInserter inserter;
111
112 private FileRepository dst;
113
114 private RevBlob contentA;
115
116 private RevBlob contentB;
117
118 private RevBlob contentC;
119
120 private RevBlob contentD;
121
122 private RevBlob contentE;
123
124 private RevCommit c1;
125
126 private RevCommit c2;
127
128 private RevCommit c3;
129
130 private RevCommit c4;
131
132 private RevCommit c5;
133
134 @Override
135 @Before
136 public void setUp() throws Exception {
137 super.setUp();
138 os = new ByteArrayOutputStream();
139 config = new PackConfig(db);
140
141 dst = createBareRepository();
142 File alt = new File(dst.getObjectDatabase().getDirectory(), INFO_ALTERNATES);
143 alt.getParentFile().mkdirs();
144 write(alt, db.getObjectDatabase().getDirectory().getAbsolutePath() + "\n");
145 }
146
147 @Override
148 @After
149 public void tearDown() throws Exception {
150 if (writer != null) {
151 writer.close();
152 writer = null;
153 }
154 if (inserter != null) {
155 inserter.close();
156 inserter = null;
157 }
158 super.tearDown();
159 }
160
161
162
163
164
165
166 @Test
167 public void testContructor() throws IOException {
168 writer = new PackWriter(config, db.newObjectReader());
169 assertFalse(writer.isDeltaBaseAsOffset());
170 assertTrue(config.isReuseDeltas());
171 assertTrue(config.isReuseObjects());
172 assertEquals(0, writer.getObjectCount());
173 }
174
175
176
177
178 @Test
179 public void testModifySettings() {
180 config.setReuseDeltas(false);
181 config.setReuseObjects(false);
182 config.setDeltaBaseAsOffset(false);
183 assertFalse(config.isReuseDeltas());
184 assertFalse(config.isReuseObjects());
185 assertFalse(config.isDeltaBaseAsOffset());
186
187 writer = new PackWriter(config, db.newObjectReader());
188 writer.setDeltaBaseAsOffset(true);
189 assertTrue(writer.isDeltaBaseAsOffset());
190 assertFalse(config.isDeltaBaseAsOffset());
191 }
192
193
194
195
196
197
198
199 @Test
200 public void testWriteEmptyPack1() throws IOException {
201 createVerifyOpenPack(NONE, NONE, false, false);
202
203 assertEquals(0, writer.getObjectCount());
204 assertEquals(0, pack.getObjectCount());
205 assertEquals("da39a3ee5e6b4b0d3255bfef95601890afd80709", writer
206 .computeName().name());
207 }
208
209
210
211
212
213
214
215 @Test
216 public void testWriteEmptyPack2() throws IOException {
217 createVerifyOpenPack(EMPTY_LIST_REVS);
218
219 assertEquals(0, writer.getObjectCount());
220 assertEquals(0, pack.getObjectCount());
221 }
222
223
224
225
226
227
228
229 @Test
230 public void testNotIgnoreNonExistingObjects() throws IOException {
231 final ObjectId nonExisting = ObjectId
232 .fromString("0000000000000000000000000000000000000001");
233 try {
234 createVerifyOpenPack(NONE, haves(nonExisting), false, false);
235 fail("Should have thrown MissingObjectException");
236 } catch (MissingObjectException x) {
237
238 }
239 }
240
241
242
243
244
245
246 @Test
247 public void testIgnoreNonExistingObjects() throws IOException {
248 final ObjectId nonExisting = ObjectId
249 .fromString("0000000000000000000000000000000000000001");
250 createVerifyOpenPack(NONE, haves(nonExisting), false, true);
251
252 }
253
254
255
256
257
258
259
260
261
262 @Test
263 public void testIgnoreNonExistingObjectsWithBitmaps() throws IOException,
264 ParseException {
265 final ObjectId nonExisting = ObjectId
266 .fromString("0000000000000000000000000000000000000001");
267 new GC(db).gc();
268 createVerifyOpenPack(NONE, haves(nonExisting), false, true, true);
269
270 }
271
272
273
274
275
276
277
278 @Test
279 public void testWritePack1() throws IOException {
280 config.setReuseDeltas(false);
281 writeVerifyPack1();
282 }
283
284
285
286
287
288
289
290 @Test
291 public void testWritePack1NoObjectReuse() throws IOException {
292 config.setReuseDeltas(false);
293 config.setReuseObjects(false);
294 writeVerifyPack1();
295 }
296
297
298
299
300
301
302
303 @Test
304 public void testWritePack2() throws IOException {
305 writeVerifyPack2(false);
306 }
307
308
309
310
311
312
313
314 @Test
315 public void testWritePack2DeltasReuseRefs() throws IOException {
316 writeVerifyPack2(true);
317 }
318
319
320
321
322
323
324
325 @Test
326 public void testWritePack2DeltasReuseOffsets() throws IOException {
327 config.setDeltaBaseAsOffset(true);
328 writeVerifyPack2(true);
329 }
330
331
332
333
334
335
336
337
338 @Test
339 public void testWritePack2DeltasCRC32Copy() throws IOException {
340 final File packDir = db.getObjectDatabase().getPackDirectory();
341 final File crc32Pack = new File(packDir,
342 "pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.pack");
343 final File crc32Idx = new File(packDir,
344 "pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idx");
345 copyFile(JGitTestUtil.getTestResourceFile(
346 "pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idxV2"),
347 crc32Idx);
348 db.openPack(crc32Pack);
349
350 writeVerifyPack2(true);
351 }
352
353
354
355
356
357
358
359
360
361 @Test
362 public void testWritePack3() throws MissingObjectException, IOException {
363 config.setReuseDeltas(false);
364 final ObjectId forcedOrder[] = new ObjectId[] {
365 ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
366 ObjectId.fromString("c59759f143fb1fe21c197981df75a7ee00290799"),
367 ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035"),
368 ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327"),
369 ObjectId.fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3") ,
370 ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259") };
371 try (RevWalk parser = new RevWalk(db)) {
372 final RevObject forcedOrderRevs[] = new RevObject[forcedOrder.length];
373 for (int i = 0; i < forcedOrder.length; i++)
374 forcedOrderRevs[i] = parser.parseAny(forcedOrder[i]);
375
376 createVerifyOpenPack(Arrays.asList(forcedOrderRevs));
377 }
378
379 assertEquals(forcedOrder.length, writer.getObjectCount());
380 verifyObjectsOrder(forcedOrder);
381 assertEquals("ed3f96b8327c7c66b0f8f70056129f0769323d86", writer
382 .computeName().name());
383 }
384
385
386
387
388
389
390
391
392 @Test
393 public void testWritePack4() throws IOException {
394 writeVerifyPack4(false);
395 }
396
397
398
399
400
401
402
403 @Test
404 public void testWritePack4ThinPack() throws IOException {
405 writeVerifyPack4(true);
406 }
407
408
409
410
411
412
413
414
415 @Test
416 public void testWritePack2SizeDeltasVsNoDeltas() throws Exception {
417 config.setReuseDeltas(false);
418 config.setDeltaCompress(false);
419 testWritePack2();
420 final long sizePack2NoDeltas = os.size();
421 tearDown();
422 setUp();
423 testWritePack2DeltasReuseRefs();
424 final long sizePack2DeltasRefs = os.size();
425
426 assertTrue(sizePack2NoDeltas > sizePack2DeltasRefs);
427 }
428
429
430
431
432
433
434
435
436
437 @Test
438 public void testWritePack2SizeOffsetsVsRefs() throws Exception {
439 testWritePack2DeltasReuseRefs();
440 final long sizePack2DeltasRefs = os.size();
441 tearDown();
442 setUp();
443 testWritePack2DeltasReuseOffsets();
444 final long sizePack2DeltasOffsets = os.size();
445
446 assertTrue(sizePack2DeltasRefs > sizePack2DeltasOffsets);
447 }
448
449
450
451
452
453
454
455
456 @Test
457 public void testWritePack4SizeThinVsNoThin() throws Exception {
458 testWritePack4();
459 final long sizePack4 = os.size();
460 tearDown();
461 setUp();
462 testWritePack4ThinPack();
463 final long sizePack4Thin = os.size();
464
465 assertTrue(sizePack4 > sizePack4Thin);
466 }
467
468 @Test
469 public void testDeltaStatistics() throws Exception {
470 config.setDeltaCompress(true);
471
472 FileRepository repo = createBareRepository();
473 ArrayList<RevObject> blobs = new ArrayList<>();
474 try (TestRepository<FileRepository> testRepo = new TestRepository<>(
475 repo)) {
476 blobs.add(testRepo.blob(genDeltableData(1000)));
477 blobs.add(testRepo.blob(genDeltableData(1005)));
478 try (PackWriter pw = new PackWriter(repo)) {
479 NullProgressMonitor m = NullProgressMonitor.INSTANCE;
480 pw.preparePack(blobs.iterator());
481 pw.writePack(m, m, os);
482 PackStatistics stats = pw.getStatistics();
483 assertEquals(1, stats.getTotalDeltas());
484 assertTrue("Delta bytes not set.",
485 stats.byObjectType(OBJ_BLOB).getDeltaBytes() > 0);
486 }
487 }
488 }
489
490
491 private String genDeltableData(int length) {
492 assertTrue("Generated data must have a length > 0", length > 0);
493 char[] data = {'a', 'b', 'c', '\n'};
494 StringBuilder builder = new StringBuilder(length);
495 for (int i = 0; i < length; i++) {
496 builder.append(data[i % 4]);
497 }
498 return builder.toString();
499 }
500
501
502 @Test
503 public void testWriteIndex() throws Exception {
504 config.setIndexVersion(2);
505 writeVerifyPack4(false);
506
507 File packFile = pack.getPackFile();
508 String name = packFile.getName();
509 String base = name.substring(0, name.lastIndexOf('.'));
510 File indexFile = new File(packFile.getParentFile(), base + ".idx");
511
512
513 final PackIndex idx1 = PackIndex.open(indexFile);
514 assertTrue(idx1 instanceof PackIndexV2);
515 assertEquals(0x4743F1E4L, idx1.findCRC32(ObjectId
516 .fromString("82c6b885ff600be425b4ea96dee75dca255b69e7")));
517
518
519 final File idx2File = new File(indexFile.getAbsolutePath() + ".2");
520 try (FileOutputStream is = new FileOutputStream(idx2File)) {
521 writer.writeIndex(is);
522 }
523 final PackIndex idx2 = PackIndex.open(idx2File);
524 assertTrue(idx2 instanceof PackIndexV2);
525 assertEquals(idx1.getObjectCount(), idx2.getObjectCount());
526 assertEquals(idx1.getOffset64Count(), idx2.getOffset64Count());
527
528 for (int i = 0; i < idx1.getObjectCount(); i++) {
529 final ObjectId id = idx1.getObjectId(i);
530 assertEquals(id, idx2.getObjectId(i));
531 assertEquals(idx1.findOffset(id), idx2.findOffset(id));
532 assertEquals(idx1.findCRC32(id), idx2.findCRC32(id));
533 }
534 }
535
536 @Test
537 public void testExclude() throws Exception {
538
539 FileRepository repo = createBareRepository();
540
541 try (TestRepository<FileRepository> testRepo = new TestRepository<>(
542 repo)) {
543 BranchBuilder bb = testRepo.branch("refs/heads/master");
544 contentA = testRepo.blob("A");
545 c1 = bb.commit().add("f", contentA).create();
546 testRepo.getRevWalk().parseHeaders(c1);
547 PackIndex pf1 = writePack(repo, wants(c1), EMPTY_ID_SET);
548 assertContent(pf1, Arrays.asList(c1.getId(), c1.getTree().getId(),
549 contentA.getId()));
550 contentB = testRepo.blob("B");
551 c2 = bb.commit().add("f", contentB).create();
552 testRepo.getRevWalk().parseHeaders(c2);
553 PackIndex pf2 = writePack(repo, wants(c2),
554 Sets.of((ObjectIdSet) pf1));
555 assertContent(pf2, Arrays.asList(c2.getId(), c2.getTree().getId(),
556 contentB.getId()));
557 }
558 }
559
560 private static void assertContent(PackIndex pi, List<ObjectId> expected) {
561 assertEquals("Pack index has wrong size.", expected.size(),
562 pi.getObjectCount());
563 for (int i = 0; i < pi.getObjectCount(); i++)
564 assertTrue(
565 "Pack index didn't contain the expected id "
566 + pi.getObjectId(i),
567 expected.contains(pi.getObjectId(i)));
568 }
569
570 @Test
571 public void testShallowIsMinimalDepth1() throws Exception {
572 try (FileRepository repo = setupRepoForShallowFetch()) {
573 PackIndex idx = writeShallowPack(repo, 1, wants(c2), NONE, NONE);
574 assertContent(idx, Arrays.asList(c2.getId(), c2.getTree().getId(),
575 contentA.getId(), contentB.getId()));
576
577
578 idx = writeShallowPack(repo, 1, wants(c5), haves(c2), shallows(c2));
579 assertContent(idx, Arrays.asList(c5.getId(), c5.getTree().getId(),
580 contentC.getId(), contentD.getId(), contentE.getId()));
581 }
582 }
583
584 @Test
585 public void testShallowIsMinimalDepth2() throws Exception {
586 try (FileRepository repo = setupRepoForShallowFetch()) {
587 PackIndex idx = writeShallowPack(repo, 2, wants(c2), NONE, NONE);
588 assertContent(idx,
589 Arrays.asList(c1.getId(), c2.getId(), c1.getTree().getId(),
590 c2.getTree().getId(), contentA.getId(),
591 contentB.getId()));
592
593
594 idx = writeShallowPack(repo, 2, wants(c5), haves(c1, c2),
595 shallows(c1));
596 assertContent(idx,
597 Arrays.asList(c4.getId(), c5.getId(), c4.getTree().getId(),
598 c5.getTree().getId(), contentC.getId(),
599 contentD.getId(), contentE.getId()));
600 }
601 }
602
603 @Test
604 public void testShallowFetchShallowParentDepth1() throws Exception {
605 try (FileRepository repo = setupRepoForShallowFetch()) {
606 PackIndex idx = writeShallowPack(repo, 1, wants(c5), NONE, NONE);
607 assertContent(idx, Arrays.asList(c5.getId(), c5.getTree().getId(),
608 contentA.getId(), contentB.getId(), contentC.getId(),
609 contentD.getId(), contentE.getId()));
610
611 idx = writeShallowPack(repo, 1, wants(c4), haves(c5), shallows(c5));
612 assertContent(idx, Arrays.asList(c4.getId(), c4.getTree().getId()));
613 }
614 }
615
616 @Test
617 public void testShallowFetchShallowParentDepth2() throws Exception {
618 try (FileRepository repo = setupRepoForShallowFetch()) {
619 PackIndex idx = writeShallowPack(repo, 2, wants(c5), NONE, NONE);
620 assertContent(idx,
621 Arrays.asList(c4.getId(), c5.getId(), c4.getTree().getId(),
622 c5.getTree().getId(), contentA.getId(),
623 contentB.getId(), contentC.getId(),
624 contentD.getId(), contentE.getId()));
625
626 idx = writeShallowPack(repo, 2, wants(c3), haves(c4, c5),
627 shallows(c4));
628 assertContent(idx, Arrays.asList(c2.getId(), c3.getId(),
629 c2.getTree().getId(), c3.getTree().getId()));
630 }
631 }
632
633 @Test
634 public void testShallowFetchShallowAncestorDepth1() throws Exception {
635 try (FileRepository repo = setupRepoForShallowFetch()) {
636 PackIndex idx = writeShallowPack(repo, 1, wants(c5), NONE, NONE);
637 assertContent(idx, Arrays.asList(c5.getId(), c5.getTree().getId(),
638 contentA.getId(), contentB.getId(), contentC.getId(),
639 contentD.getId(), contentE.getId()));
640
641 idx = writeShallowPack(repo, 1, wants(c3), haves(c5), shallows(c5));
642 assertContent(idx, Arrays.asList(c3.getId(), c3.getTree().getId()));
643 }
644 }
645
646 @Test
647 public void testShallowFetchShallowAncestorDepth2() throws Exception {
648 try (FileRepository repo = setupRepoForShallowFetch()) {
649 PackIndex idx = writeShallowPack(repo, 2, wants(c5), NONE, NONE);
650 assertContent(idx,
651 Arrays.asList(c4.getId(), c5.getId(), c4.getTree().getId(),
652 c5.getTree().getId(), contentA.getId(),
653 contentB.getId(), contentC.getId(),
654 contentD.getId(), contentE.getId()));
655
656 idx = writeShallowPack(repo, 2, wants(c2), haves(c4, c5),
657 shallows(c4));
658 assertContent(idx, Arrays.asList(c1.getId(), c2.getId(),
659 c1.getTree().getId(), c2.getTree().getId()));
660 }
661 }
662
663 private FileRepository setupRepoForShallowFetch() throws Exception {
664 FileRepository repo = createBareRepository();
665
666
667 repo.incrementOpen();
668 try (TestRepository<Repository> r = new TestRepository<>(repo)) {
669 BranchBuilder bb = r.branch("refs/heads/master");
670 contentA = r.blob("A");
671 contentB = r.blob("B");
672 contentC = r.blob("C");
673 contentD = r.blob("D");
674 contentE = r.blob("E");
675 c1 = bb.commit().add("a", contentA).create();
676 c2 = bb.commit().add("b", contentB).create();
677 c3 = bb.commit().add("c", contentC).create();
678 c4 = bb.commit().add("d", contentD).create();
679 c5 = bb.commit().add("e", contentE).create();
680 r.getRevWalk().parseHeaders(c5);
681 return repo;
682 }
683 }
684
685 private static PackIndex writePack(FileRepository repo,
686 Set<? extends ObjectId> want, Set<ObjectIdSet> excludeObjects)
687 throws IOException {
688 try (RevWalk walk = new RevWalk(repo)) {
689 return writePack(repo, walk, 0, want, NONE, excludeObjects);
690 }
691 }
692
693 private static PackIndex writeShallowPack(FileRepository repo, int depth,
694 Set<? extends ObjectId> want, Set<? extends ObjectId> have,
695 Set<? extends ObjectId> shallow) throws IOException {
696
697
698 try (DepthWalk.RevWalk walk = new DepthWalk.RevWalk(repo, depth - 1)) {
699 walk.assumeShallow(shallow);
700 return writePack(repo, walk, depth, want, have, EMPTY_ID_SET);
701 }
702 }
703
704 private static PackIndex writePack(FileRepository repo, RevWalk walk,
705 int depth, Set<? extends ObjectId> want,
706 Set<? extends ObjectId> have, Set<ObjectIdSet> excludeObjects)
707 throws IOException {
708 try (PackWriter pw = new PackWriter(repo)) {
709 pw.setDeltaBaseAsOffset(true);
710 pw.setReuseDeltaCommits(false);
711 for (ObjectIdSet idx : excludeObjects) {
712 pw.excludeObjects(idx);
713 }
714 if (depth > 0) {
715 pw.setShallowPack(depth, null);
716 }
717
718 ObjectWalk ow = walk.toObjectWalkWithSameObjects();
719
720 pw.preparePack(NullProgressMonitor.INSTANCE, ow, want, have, NONE);
721 String id = pw.computeName().getName();
722 File packdir = repo.getObjectDatabase().getPackDirectory();
723 File packFile = new File(packdir, "pack-" + id + ".pack");
724 try (FileOutputStream packOS = new FileOutputStream(packFile)) {
725 pw.writePack(NullProgressMonitor.INSTANCE,
726 NullProgressMonitor.INSTANCE, packOS);
727 }
728 File idxFile = new File(packdir, "pack-" + id + ".idx");
729 try (FileOutputStream idxOS = new FileOutputStream(idxFile)) {
730 pw.writeIndex(idxOS);
731 }
732 return PackIndex.open(idxFile);
733 }
734 }
735
736
737
738
739 private void writeVerifyPack1() throws IOException {
740 final HashSet<ObjectId> interestings = new HashSet<>();
741 interestings.add(ObjectId
742 .fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"));
743 createVerifyOpenPack(interestings, NONE, false, false);
744
745 final ObjectId expectedOrder[] = new ObjectId[] {
746 ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
747 ObjectId.fromString("c59759f143fb1fe21c197981df75a7ee00290799"),
748 ObjectId.fromString("540a36d136cf413e4b064c2b0e0a4db60f77feab"),
749 ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035"),
750 ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327"),
751 ObjectId.fromString("4b825dc642cb6eb9a060e54bf8d69288fbee4904"),
752 ObjectId.fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3"),
753 ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259") };
754
755 assertEquals(expectedOrder.length, writer.getObjectCount());
756 verifyObjectsOrder(expectedOrder);
757 assertEquals("34be9032ac282b11fa9babdc2b2a93ca996c9c2f", writer
758 .computeName().name());
759 }
760
761 private void writeVerifyPack2(boolean deltaReuse) throws IOException {
762 config.setReuseDeltas(deltaReuse);
763 final HashSet<ObjectId> interestings = new HashSet<>();
764 interestings.add(ObjectId
765 .fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"));
766 final HashSet<ObjectId> uninterestings = new HashSet<>();
767 uninterestings.add(ObjectId
768 .fromString("540a36d136cf413e4b064c2b0e0a4db60f77feab"));
769 createVerifyOpenPack(interestings, uninterestings, false, false);
770
771 final ObjectId expectedOrder[] = new ObjectId[] {
772 ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
773 ObjectId.fromString("c59759f143fb1fe21c197981df75a7ee00290799"),
774 ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035"),
775 ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327"),
776 ObjectId.fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3") ,
777 ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259") };
778 if (!config.isReuseDeltas() && !config.isDeltaCompress()) {
779
780 swap(expectedOrder, 4, 5);
781 }
782 assertEquals(expectedOrder.length, writer.getObjectCount());
783 verifyObjectsOrder(expectedOrder);
784 assertEquals("ed3f96b8327c7c66b0f8f70056129f0769323d86", writer
785 .computeName().name());
786 }
787
788 private static void swap(ObjectId[] arr, int a, int b) {
789 ObjectId tmp = arr[a];
790 arr[a] = arr[b];
791 arr[b] = tmp;
792 }
793
794 private void writeVerifyPack4(final boolean thin) throws IOException {
795 final HashSet<ObjectId> interestings = new HashSet<>();
796 interestings.add(ObjectId
797 .fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"));
798 final HashSet<ObjectId> uninterestings = new HashSet<>();
799 uninterestings.add(ObjectId
800 .fromString("c59759f143fb1fe21c197981df75a7ee00290799"));
801 createVerifyOpenPack(interestings, uninterestings, thin, false);
802
803 final ObjectId writtenObjects[] = new ObjectId[] {
804 ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
805 ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035"),
806 ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259") };
807 assertEquals(writtenObjects.length, writer.getObjectCount());
808 ObjectId expectedObjects[];
809 if (thin) {
810 expectedObjects = new ObjectId[4];
811 System.arraycopy(writtenObjects, 0, expectedObjects, 0,
812 writtenObjects.length);
813 expectedObjects[3] = ObjectId
814 .fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3");
815
816 } else {
817 expectedObjects = writtenObjects;
818 }
819 verifyObjectsOrder(expectedObjects);
820 assertEquals("cded4b74176b4456afa456768b2b5aafb41c44fc", writer
821 .computeName().name());
822 }
823
824 private void createVerifyOpenPack(final Set<ObjectId> interestings,
825 final Set<ObjectId> uninterestings, final boolean thin,
826 final boolean ignoreMissingUninteresting)
827 throws MissingObjectException, IOException {
828 createVerifyOpenPack(interestings, uninterestings, thin,
829 ignoreMissingUninteresting, false);
830 }
831
832 private void createVerifyOpenPack(final Set<ObjectId> interestings,
833 final Set<ObjectId> uninterestings, final boolean thin,
834 final boolean ignoreMissingUninteresting, boolean useBitmaps)
835 throws MissingObjectException, IOException {
836 NullProgressMonitor m = NullProgressMonitor.INSTANCE;
837 writer = new PackWriter(config, db.newObjectReader());
838 writer.setUseBitmaps(useBitmaps);
839 writer.setThin(thin);
840 writer.setIgnoreMissingUninteresting(ignoreMissingUninteresting);
841 writer.preparePack(m, interestings, uninterestings);
842 writer.writePack(m, m, os);
843 writer.close();
844 verifyOpenPack(thin);
845 }
846
847 private void createVerifyOpenPack(List<RevObject> objectSource)
848 throws MissingObjectException, IOException {
849 NullProgressMonitor m = NullProgressMonitor.INSTANCE;
850 writer = new PackWriter(config, db.newObjectReader());
851 writer.preparePack(objectSource.iterator());
852 assertEquals(objectSource.size(), writer.getObjectCount());
853 writer.writePack(m, m, os);
854 writer.close();
855 verifyOpenPack(false);
856 }
857
858 private void verifyOpenPack(boolean thin) throws IOException {
859 final byte[] packData = os.toByteArray();
860
861 if (thin) {
862 PackParser p = index(packData);
863 try {
864 p.parse(NullProgressMonitor.INSTANCE);
865 fail("indexer should grumble about missing object");
866 } catch (IOException x) {
867
868 }
869 }
870
871 ObjectDirectoryPackParser p = (ObjectDirectoryPackParser) index(packData);
872 p.setKeepEmpty(true);
873 p.setAllowThin(thin);
874 p.setIndexVersion(2);
875 p.parse(NullProgressMonitor.INSTANCE);
876 pack = p.getPackFile();
877 assertNotNull("have PackFile after parsing", pack);
878 }
879
880 private PackParser index(byte[] packData) throws IOException {
881 if (inserter == null)
882 inserter = dst.newObjectInserter();
883 return inserter.newPackParser(new ByteArrayInputStream(packData));
884 }
885
886 private void verifyObjectsOrder(ObjectId objectsOrder[]) {
887 final List<PackIndex.MutableEntry> entries = new ArrayList<>();
888
889 for (MutableEntry me : pack) {
890 entries.add(me.cloneEntry());
891 }
892 Collections.sort(entries, (MutableEntry o1, MutableEntry o2) -> Long
893 .signum(o1.getOffset() - o2.getOffset()));
894
895 int i = 0;
896 for (MutableEntry me : entries) {
897 assertEquals(objectsOrder[i++].toObjectId(), me.toObjectId());
898 }
899 }
900
901 private static Set<ObjectId> haves(ObjectId... objects) {
902 return Sets.of(objects);
903 }
904
905 private static Set<ObjectId> wants(ObjectId... objects) {
906 return Sets.of(objects);
907 }
908
909 private static Set<ObjectId> shallows(ObjectId... objects) {
910 return Sets.of(objects);
911 }
912 }