You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PackWriterTest.java 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. /*
  2. * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
  3. * and other copyright owners as documented in the project's IP log.
  4. *
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Distribution License v1.0 which
  7. * accompanies this distribution, is reproduced below, and is
  8. * available at http://www.eclipse.org/org/documents/edl-v10.php
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or
  13. * without modification, are permitted provided that the following
  14. * conditions are met:
  15. *
  16. * - Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials provided
  22. * with the distribution.
  23. *
  24. * - Neither the name of the Eclipse Foundation, Inc. nor the
  25. * names of its contributors may be used to endorse or promote
  26. * products derived from this software without specific prior
  27. * written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. */
  43. package org.eclipse.jgit.storage.file;
  44. import static org.junit.Assert.assertEquals;
  45. import static org.junit.Assert.assertFalse;
  46. import static org.junit.Assert.assertNotNull;
  47. import static org.junit.Assert.assertTrue;
  48. import static org.junit.Assert.fail;
  49. import java.io.ByteArrayInputStream;
  50. import java.io.ByteArrayOutputStream;
  51. import java.io.File;
  52. import java.io.FileOutputStream;
  53. import java.io.IOException;
  54. import java.util.ArrayList;
  55. import java.util.Arrays;
  56. import java.util.Collections;
  57. import java.util.Comparator;
  58. import java.util.HashSet;
  59. import java.util.List;
  60. import java.util.Set;
  61. import org.eclipse.jgit.errors.MissingObjectException;
  62. import org.eclipse.jgit.junit.JGitTestUtil;
  63. import org.eclipse.jgit.junit.TestRepository;
  64. import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
  65. import org.eclipse.jgit.lib.NullProgressMonitor;
  66. import org.eclipse.jgit.lib.ObjectId;
  67. import org.eclipse.jgit.lib.ObjectInserter;
  68. import org.eclipse.jgit.lib.SampleDataRepositoryTestCase;
  69. import org.eclipse.jgit.revwalk.RevBlob;
  70. import org.eclipse.jgit.revwalk.RevCommit;
  71. import org.eclipse.jgit.revwalk.RevObject;
  72. import org.eclipse.jgit.revwalk.RevWalk;
  73. import org.eclipse.jgit.storage.file.PackIndex.MutableEntry;
  74. import org.eclipse.jgit.storage.pack.PackConfig;
  75. import org.eclipse.jgit.storage.pack.PackWriter;
  76. import org.eclipse.jgit.transport.PackParser;
  77. import org.junit.After;
  78. import org.junit.Before;
  79. import org.junit.Test;
  80. public class PackWriterTest extends SampleDataRepositoryTestCase {
  81. private static final Set<ObjectId> EMPTY_SET_OBJECT = Collections
  82. .<ObjectId> emptySet();
  83. private static final List<RevObject> EMPTY_LIST_REVS = Collections
  84. .<RevObject> emptyList();
  85. private PackConfig config;
  86. private PackWriter writer;
  87. private ByteArrayOutputStream os;
  88. private PackFile pack;
  89. private ObjectInserter inserter;
  90. private FileRepository dst;
  91. @Before
  92. public void setUp() throws Exception {
  93. super.setUp();
  94. os = new ByteArrayOutputStream();
  95. config = new PackConfig(db);
  96. dst = createBareRepository();
  97. File alt = new File(dst.getObjectDatabase().getDirectory(), "info/alternates");
  98. alt.getParentFile().mkdirs();
  99. write(alt, db.getObjectDatabase().getDirectory().getAbsolutePath() + "\n");
  100. }
  101. @After
  102. public void tearDown() throws Exception {
  103. if (writer != null) {
  104. writer.release();
  105. writer = null;
  106. }
  107. if (inserter != null) {
  108. inserter.release();
  109. inserter = null;
  110. }
  111. super.tearDown();
  112. }
  113. /**
  114. * Test constructor for exceptions, default settings, initialization.
  115. *
  116. * @throws IOException
  117. */
  118. @Test
  119. public void testContructor() throws IOException {
  120. writer = new PackWriter(config, db.newObjectReader());
  121. assertFalse(writer.isDeltaBaseAsOffset());
  122. assertTrue(config.isReuseDeltas());
  123. assertTrue(config.isReuseObjects());
  124. assertEquals(0, writer.getObjectCount());
  125. }
  126. /**
  127. * Change default settings and verify them.
  128. */
  129. @Test
  130. public void testModifySettings() {
  131. config.setReuseDeltas(false);
  132. config.setReuseObjects(false);
  133. config.setDeltaBaseAsOffset(false);
  134. assertFalse(config.isReuseDeltas());
  135. assertFalse(config.isReuseObjects());
  136. assertFalse(config.isDeltaBaseAsOffset());
  137. writer = new PackWriter(config, db.newObjectReader());
  138. writer.setDeltaBaseAsOffset(true);
  139. assertTrue(writer.isDeltaBaseAsOffset());
  140. assertFalse(config.isDeltaBaseAsOffset());
  141. }
  142. /**
  143. * Write empty pack by providing empty sets of interesting/uninteresting
  144. * objects and check for correct format.
  145. *
  146. * @throws IOException
  147. */
  148. @Test
  149. public void testWriteEmptyPack1() throws IOException {
  150. createVerifyOpenPack(EMPTY_SET_OBJECT, EMPTY_SET_OBJECT, false, false);
  151. assertEquals(0, writer.getObjectCount());
  152. assertEquals(0, pack.getObjectCount());
  153. assertEquals("da39a3ee5e6b4b0d3255bfef95601890afd80709", writer
  154. .computeName().name());
  155. }
  156. /**
  157. * Write empty pack by providing empty iterator of objects to write and
  158. * check for correct format.
  159. *
  160. * @throws IOException
  161. */
  162. @Test
  163. public void testWriteEmptyPack2() throws IOException {
  164. createVerifyOpenPack(EMPTY_LIST_REVS);
  165. assertEquals(0, writer.getObjectCount());
  166. assertEquals(0, pack.getObjectCount());
  167. }
  168. /**
  169. * Try to pass non-existing object as uninteresting, with non-ignoring
  170. * setting.
  171. *
  172. * @throws IOException
  173. */
  174. @Test
  175. public void testNotIgnoreNonExistingObjects() throws IOException {
  176. final ObjectId nonExisting = ObjectId
  177. .fromString("0000000000000000000000000000000000000001");
  178. try {
  179. createVerifyOpenPack(EMPTY_SET_OBJECT, Collections.singleton(
  180. nonExisting), false, false);
  181. fail("Should have thrown MissingObjectException");
  182. } catch (MissingObjectException x) {
  183. // expected
  184. }
  185. }
  186. /**
  187. * Try to pass non-existing object as uninteresting, with ignoring setting.
  188. *
  189. * @throws IOException
  190. */
  191. @Test
  192. public void testIgnoreNonExistingObjects() throws IOException {
  193. final ObjectId nonExisting = ObjectId
  194. .fromString("0000000000000000000000000000000000000001");
  195. createVerifyOpenPack(EMPTY_SET_OBJECT, Collections.singleton(
  196. nonExisting), false, true);
  197. // shouldn't throw anything
  198. }
  199. /**
  200. * Create pack basing on only interesting objects, then precisely verify
  201. * content. No delta reuse here.
  202. *
  203. * @throws IOException
  204. */
  205. @Test
  206. public void testWritePack1() throws IOException {
  207. config.setReuseDeltas(false);
  208. writeVerifyPack1();
  209. }
  210. /**
  211. * Test writing pack without object reuse. Pack content/preparation as in
  212. * {@link #testWritePack1()}.
  213. *
  214. * @throws IOException
  215. */
  216. @Test
  217. public void testWritePack1NoObjectReuse() throws IOException {
  218. config.setReuseDeltas(false);
  219. config.setReuseObjects(false);
  220. writeVerifyPack1();
  221. }
  222. /**
  223. * Create pack basing on both interesting and uninteresting objects, then
  224. * precisely verify content. No delta reuse here.
  225. *
  226. * @throws IOException
  227. */
  228. @Test
  229. public void testWritePack2() throws IOException {
  230. writeVerifyPack2(false);
  231. }
  232. /**
  233. * Test pack writing with deltas reuse, delta-base first rule. Pack
  234. * content/preparation as in {@link #testWritePack2()}.
  235. *
  236. * @throws IOException
  237. */
  238. @Test
  239. public void testWritePack2DeltasReuseRefs() throws IOException {
  240. writeVerifyPack2(true);
  241. }
  242. /**
  243. * Test pack writing with delta reuse. Delta bases referred as offsets. Pack
  244. * configuration as in {@link #testWritePack2DeltasReuseRefs()}.
  245. *
  246. * @throws IOException
  247. */
  248. @Test
  249. public void testWritePack2DeltasReuseOffsets() throws IOException {
  250. config.setDeltaBaseAsOffset(true);
  251. writeVerifyPack2(true);
  252. }
  253. /**
  254. * Test pack writing with delta reuse. Raw-data copy (reuse) is made on a
  255. * pack with CRC32 index. Pack configuration as in
  256. * {@link #testWritePack2DeltasReuseRefs()}.
  257. *
  258. * @throws IOException
  259. */
  260. @Test
  261. public void testWritePack2DeltasCRC32Copy() throws IOException {
  262. final File packDir = new File(db.getObjectDatabase().getDirectory(), "pack");
  263. final File crc32Pack = new File(packDir,
  264. "pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.pack");
  265. final File crc32Idx = new File(packDir,
  266. "pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idx");
  267. copyFile(JGitTestUtil.getTestResourceFile(
  268. "pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idxV2"),
  269. crc32Idx);
  270. db.openPack(crc32Pack, crc32Idx);
  271. writeVerifyPack2(true);
  272. }
  273. /**
  274. * Create pack basing on fixed objects list, then precisely verify content.
  275. * No delta reuse here.
  276. *
  277. * @throws IOException
  278. * @throws MissingObjectException
  279. *
  280. */
  281. @Test
  282. public void testWritePack3() throws MissingObjectException, IOException {
  283. config.setReuseDeltas(false);
  284. final ObjectId forcedOrder[] = new ObjectId[] {
  285. ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
  286. ObjectId.fromString("c59759f143fb1fe21c197981df75a7ee00290799"),
  287. ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035"),
  288. ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327"),
  289. ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259"),
  290. ObjectId.fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3") };
  291. final RevWalk parser = new RevWalk(db);
  292. final RevObject forcedOrderRevs[] = new RevObject[forcedOrder.length];
  293. for (int i = 0; i < forcedOrder.length; i++)
  294. forcedOrderRevs[i] = parser.parseAny(forcedOrder[i]);
  295. createVerifyOpenPack(Arrays.asList(forcedOrderRevs));
  296. assertEquals(forcedOrder.length, writer.getObjectCount());
  297. verifyObjectsOrder(forcedOrder);
  298. assertEquals("ed3f96b8327c7c66b0f8f70056129f0769323d86", writer
  299. .computeName().name());
  300. }
  301. /**
  302. * Another pack creation: basing on both interesting and uninteresting
  303. * objects. No delta reuse possible here, as this is a specific case when we
  304. * write only 1 commit, associated with 1 tree, 1 blob.
  305. *
  306. * @throws IOException
  307. */
  308. @Test
  309. public void testWritePack4() throws IOException {
  310. writeVerifyPack4(false);
  311. }
  312. /**
  313. * Test thin pack writing: 1 blob delta base is on objects edge. Pack
  314. * configuration as in {@link #testWritePack4()}.
  315. *
  316. * @throws IOException
  317. */
  318. @Test
  319. public void testWritePack4ThinPack() throws IOException {
  320. writeVerifyPack4(true);
  321. }
  322. /**
  323. * Compare sizes of packs created using {@link #testWritePack2()} and
  324. * {@link #testWritePack2DeltasReuseRefs()}. The pack using deltas should
  325. * be smaller.
  326. *
  327. * @throws Exception
  328. */
  329. @Test
  330. public void testWritePack2SizeDeltasVsNoDeltas() throws Exception {
  331. testWritePack2();
  332. final long sizePack2NoDeltas = os.size();
  333. tearDown();
  334. setUp();
  335. testWritePack2DeltasReuseRefs();
  336. final long sizePack2DeltasRefs = os.size();
  337. assertTrue(sizePack2NoDeltas > sizePack2DeltasRefs);
  338. }
  339. /**
  340. * Compare sizes of packs created using
  341. * {@link #testWritePack2DeltasReuseRefs()} and
  342. * {@link #testWritePack2DeltasReuseOffsets()}. The pack with delta bases
  343. * written as offsets should be smaller.
  344. *
  345. * @throws Exception
  346. */
  347. @Test
  348. public void testWritePack2SizeOffsetsVsRefs() throws Exception {
  349. testWritePack2DeltasReuseRefs();
  350. final long sizePack2DeltasRefs = os.size();
  351. tearDown();
  352. setUp();
  353. testWritePack2DeltasReuseOffsets();
  354. final long sizePack2DeltasOffsets = os.size();
  355. assertTrue(sizePack2DeltasRefs > sizePack2DeltasOffsets);
  356. }
  357. /**
  358. * Compare sizes of packs created using {@link #testWritePack4()} and
  359. * {@link #testWritePack4ThinPack()}. Obviously, the thin pack should be
  360. * smaller.
  361. *
  362. * @throws Exception
  363. */
  364. @Test
  365. public void testWritePack4SizeThinVsNoThin() throws Exception {
  366. testWritePack4();
  367. final long sizePack4 = os.size();
  368. tearDown();
  369. setUp();
  370. testWritePack4ThinPack();
  371. final long sizePack4Thin = os.size();
  372. assertTrue(sizePack4 > sizePack4Thin);
  373. }
  374. @Test
  375. public void testWriteIndex() throws Exception {
  376. config.setIndexVersion(2);
  377. writeVerifyPack4(false);
  378. File packFile = pack.getPackFile();
  379. String name = packFile.getName();
  380. String base = name.substring(0, name.lastIndexOf('.'));
  381. File indexFile = new File(packFile.getParentFile(), base + ".idx");
  382. // Validate that IndexPack came up with the right CRC32 value.
  383. final PackIndex idx1 = PackIndex.open(indexFile);
  384. assertTrue(idx1 instanceof PackIndexV2);
  385. assertEquals(0x4743F1E4L, idx1.findCRC32(ObjectId
  386. .fromString("82c6b885ff600be425b4ea96dee75dca255b69e7")));
  387. // Validate that an index written by PackWriter is the same.
  388. final File idx2File = new File(indexFile.getAbsolutePath() + ".2");
  389. final FileOutputStream is = new FileOutputStream(idx2File);
  390. try {
  391. writer.writeIndex(is);
  392. } finally {
  393. is.close();
  394. }
  395. final PackIndex idx2 = PackIndex.open(idx2File);
  396. assertTrue(idx2 instanceof PackIndexV2);
  397. assertEquals(idx1.getObjectCount(), idx2.getObjectCount());
  398. assertEquals(idx1.getOffset64Count(), idx2.getOffset64Count());
  399. for (int i = 0; i < idx1.getObjectCount(); i++) {
  400. final ObjectId id = idx1.getObjectId(i);
  401. assertEquals(id, idx2.getObjectId(i));
  402. assertEquals(idx1.findOffset(id), idx2.findOffset(id));
  403. assertEquals(idx1.findCRC32(id), idx2.findCRC32(id));
  404. }
  405. }
  406. @Test
  407. public void testExclude() throws Exception {
  408. FileRepository repo = createBareRepository();
  409. TestRepository<FileRepository> testRepo = new TestRepository<FileRepository>(
  410. repo);
  411. BranchBuilder bb = testRepo.branch("refs/heads/master");
  412. RevBlob contentA = testRepo.blob("A");
  413. RevCommit c1 = bb.commit().add("f", contentA).create();
  414. testRepo.getRevWalk().parseHeaders(c1);
  415. PackIndex pf1 = writePack(repo, Collections.singleton(c1),
  416. Collections.<PackIndex> emptySet());
  417. assertContent(
  418. pf1,
  419. Arrays.asList(c1.getId(), c1.getTree().getId(),
  420. contentA.getId()));
  421. RevBlob contentB = testRepo.blob("B");
  422. RevCommit c2 = bb.commit().add("f", contentB).create();
  423. testRepo.getRevWalk().parseHeaders(c2);
  424. PackIndex pf2 = writePack(repo, Collections.singleton(c2),
  425. Collections.singleton(pf1));
  426. assertContent(
  427. pf2,
  428. Arrays.asList(c2.getId(), c2.getTree().getId(),
  429. contentB.getId()));
  430. }
  431. private void assertContent(PackIndex pi, List<ObjectId> expected) {
  432. assertEquals("Pack index has wrong size.", expected.size(),
  433. pi.getObjectCount());
  434. for (int i = 0; i < pi.getObjectCount(); i++)
  435. assertTrue(
  436. "Pack index didn't contain the expected id "
  437. + pi.getObjectId(i),
  438. expected.contains(pi.getObjectId(i)));
  439. }
  440. private PackIndex writePack(FileRepository repo,
  441. Set<? extends ObjectId> want, Set<PackIndex> excludeObjects)
  442. throws IOException {
  443. PackWriter pw = new PackWriter(repo);
  444. pw.setDeltaBaseAsOffset(true);
  445. pw.setReuseDeltaCommits(false);
  446. for (PackIndex idx : excludeObjects)
  447. pw.excludeObjects(idx);
  448. pw.preparePack(NullProgressMonitor.INSTANCE, want,
  449. Collections.<ObjectId> emptySet());
  450. String id = pw.computeName().getName();
  451. File packdir = new File(repo.getObjectsDirectory(), "pack");
  452. File packFile = new File(packdir, "pack-" + id + ".pack");
  453. FileOutputStream packOS = new FileOutputStream(packFile);
  454. pw.writePack(NullProgressMonitor.INSTANCE,
  455. NullProgressMonitor.INSTANCE, packOS);
  456. packOS.close();
  457. File idxFile = new File(packdir, "pack-" + id + ".idx");
  458. FileOutputStream idxOS = new FileOutputStream(idxFile);
  459. pw.writeIndex(idxOS);
  460. idxOS.close();
  461. pw.release();
  462. return PackIndex.open(idxFile);
  463. }
  464. // TODO: testWritePackDeltasCycle()
  465. // TODO: testWritePackDeltasDepth()
  466. private void writeVerifyPack1() throws IOException {
  467. final HashSet<ObjectId> interestings = new HashSet<ObjectId>();
  468. interestings.add(ObjectId
  469. .fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"));
  470. createVerifyOpenPack(interestings, EMPTY_SET_OBJECT, false, false);
  471. final ObjectId expectedOrder[] = new ObjectId[] {
  472. ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
  473. ObjectId.fromString("c59759f143fb1fe21c197981df75a7ee00290799"),
  474. ObjectId.fromString("540a36d136cf413e4b064c2b0e0a4db60f77feab"),
  475. ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035"),
  476. ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327"),
  477. ObjectId.fromString("4b825dc642cb6eb9a060e54bf8d69288fbee4904"),
  478. ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259"),
  479. ObjectId.fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3") };
  480. assertEquals(expectedOrder.length, writer.getObjectCount());
  481. verifyObjectsOrder(expectedOrder);
  482. assertEquals("34be9032ac282b11fa9babdc2b2a93ca996c9c2f", writer
  483. .computeName().name());
  484. }
  485. private void writeVerifyPack2(boolean deltaReuse) throws IOException {
  486. config.setReuseDeltas(deltaReuse);
  487. final HashSet<ObjectId> interestings = new HashSet<ObjectId>();
  488. interestings.add(ObjectId
  489. .fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"));
  490. final HashSet<ObjectId> uninterestings = new HashSet<ObjectId>();
  491. uninterestings.add(ObjectId
  492. .fromString("540a36d136cf413e4b064c2b0e0a4db60f77feab"));
  493. createVerifyOpenPack(interestings, uninterestings, false, false);
  494. final ObjectId expectedOrder[] = new ObjectId[] {
  495. ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
  496. ObjectId.fromString("c59759f143fb1fe21c197981df75a7ee00290799"),
  497. ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035"),
  498. ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327"),
  499. ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259"),
  500. ObjectId.fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3") };
  501. if (deltaReuse) {
  502. // objects order influenced (swapped) by delta-base first rule
  503. ObjectId temp = expectedOrder[4];
  504. expectedOrder[4] = expectedOrder[5];
  505. expectedOrder[5] = temp;
  506. }
  507. assertEquals(expectedOrder.length, writer.getObjectCount());
  508. verifyObjectsOrder(expectedOrder);
  509. assertEquals("ed3f96b8327c7c66b0f8f70056129f0769323d86", writer
  510. .computeName().name());
  511. }
  512. private void writeVerifyPack4(final boolean thin) throws IOException {
  513. final HashSet<ObjectId> interestings = new HashSet<ObjectId>();
  514. interestings.add(ObjectId
  515. .fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"));
  516. final HashSet<ObjectId> uninterestings = new HashSet<ObjectId>();
  517. uninterestings.add(ObjectId
  518. .fromString("c59759f143fb1fe21c197981df75a7ee00290799"));
  519. createVerifyOpenPack(interestings, uninterestings, thin, false);
  520. final ObjectId writtenObjects[] = new ObjectId[] {
  521. ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
  522. ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035"),
  523. ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259") };
  524. assertEquals(writtenObjects.length, writer.getObjectCount());
  525. ObjectId expectedObjects[];
  526. if (thin) {
  527. expectedObjects = new ObjectId[4];
  528. System.arraycopy(writtenObjects, 0, expectedObjects, 0,
  529. writtenObjects.length);
  530. expectedObjects[3] = ObjectId
  531. .fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3");
  532. } else {
  533. expectedObjects = writtenObjects;
  534. }
  535. verifyObjectsOrder(expectedObjects);
  536. assertEquals("cded4b74176b4456afa456768b2b5aafb41c44fc", writer
  537. .computeName().name());
  538. }
  539. private void createVerifyOpenPack(final Set<ObjectId> interestings,
  540. final Set<ObjectId> uninterestings, final boolean thin,
  541. final boolean ignoreMissingUninteresting)
  542. throws MissingObjectException, IOException {
  543. NullProgressMonitor m = NullProgressMonitor.INSTANCE;
  544. writer = new PackWriter(config, db.newObjectReader());
  545. writer.setThin(thin);
  546. writer.setIgnoreMissingUninteresting(ignoreMissingUninteresting);
  547. writer.preparePack(m, interestings, uninterestings);
  548. writer.writePack(m, m, os);
  549. writer.release();
  550. verifyOpenPack(thin);
  551. }
  552. private void createVerifyOpenPack(final List<RevObject> objectSource)
  553. throws MissingObjectException, IOException {
  554. NullProgressMonitor m = NullProgressMonitor.INSTANCE;
  555. writer = new PackWriter(config, db.newObjectReader());
  556. writer.preparePack(objectSource.iterator());
  557. assertEquals(objectSource.size(), writer.getObjectCount());
  558. writer.writePack(m, m, os);
  559. writer.release();
  560. verifyOpenPack(false);
  561. }
  562. private void verifyOpenPack(final boolean thin) throws IOException {
  563. final byte[] packData = os.toByteArray();
  564. if (thin) {
  565. PackParser p = index(packData);
  566. try {
  567. p.parse(NullProgressMonitor.INSTANCE);
  568. fail("indexer should grumble about missing object");
  569. } catch (IOException x) {
  570. // expected
  571. }
  572. }
  573. ObjectDirectoryPackParser p = (ObjectDirectoryPackParser) index(packData);
  574. p.setKeepEmpty(true);
  575. p.setAllowThin(thin);
  576. p.setIndexVersion(2);
  577. p.parse(NullProgressMonitor.INSTANCE);
  578. pack = p.getPackFile();
  579. assertNotNull("have PackFile after parsing", pack);
  580. }
  581. private PackParser index(final byte[] packData) throws IOException {
  582. if (inserter == null)
  583. inserter = dst.newObjectInserter();
  584. return inserter.newPackParser(new ByteArrayInputStream(packData));
  585. }
  586. private void verifyObjectsOrder(final ObjectId objectsOrder[]) {
  587. final List<PackIndex.MutableEntry> entries = new ArrayList<PackIndex.MutableEntry>();
  588. for (MutableEntry me : pack) {
  589. entries.add(me.cloneEntry());
  590. }
  591. Collections.sort(entries, new Comparator<PackIndex.MutableEntry>() {
  592. public int compare(MutableEntry o1, MutableEntry o2) {
  593. return Long.signum(o1.getOffset() - o2.getOffset());
  594. }
  595. });
  596. int i = 0;
  597. for (MutableEntry me : entries) {
  598. assertEquals(objectsOrder[i++].toObjectId(), me.toObjectId());
  599. }
  600. }
  601. }