PackParserTest: Extract pack-writing helper code to its own class
PackParserTest has code to create a small pack in memory. We can use it to test also the DfsPackParser. Extract the helper functions to a new class (InMemoryPack). Change-Id: I6dea4d6ea2cac2da8201702df92fd09a687e90a6
This commit is contained in:
parent
cb99ff5bbb
commit
afb013b983
|
@ -29,6 +29,7 @@ HELPERS = glob(
|
|||
"transport/ObjectIdMatcher.java",
|
||||
"transport/RequestValidatorTestCase.java",
|
||||
"transport/SpiTransport.java",
|
||||
"transport/InMemoryPack.java",
|
||||
"treewalk/filter/AlwaysCloneTreeFilter.java",
|
||||
"test/resources/SampleDataRepositoryTestCase.java",
|
||||
"util/CPUTimeStopWatch.java",
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (C) 2023, Google LLC. and others
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
||||
* https://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
package org.eclipse.jgit.transport;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
import org.eclipse.jgit.lib.AnyObjectId;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.util.NB;
|
||||
import org.eclipse.jgit.util.TemporaryBuffer;
|
||||
import org.eclipse.jgit.util.TemporaryBuffer.Heap;
|
||||
|
||||
/**
|
||||
* Helper class to create packs for tests.
|
||||
*/
|
||||
public class InMemoryPack {
|
||||
|
||||
private final Heap tinyPack;
|
||||
|
||||
public InMemoryPack() {
|
||||
this(1024);
|
||||
}
|
||||
|
||||
public InMemoryPack(int size) {
|
||||
this.tinyPack = new TemporaryBuffer.Heap(size);
|
||||
}
|
||||
|
||||
public InMemoryPack header(int cnt)
|
||||
throws IOException {
|
||||
final byte[] hdr = new byte[8];
|
||||
NB.encodeInt32(hdr, 0, 2);
|
||||
NB.encodeInt32(hdr, 4, cnt);
|
||||
|
||||
tinyPack.write(Constants.PACK_SIGNATURE);
|
||||
tinyPack.write(hdr, 0, 8);
|
||||
return this;
|
||||
}
|
||||
|
||||
public InMemoryPack write(int i) throws IOException {
|
||||
tinyPack.write(i);
|
||||
return this;
|
||||
}
|
||||
|
||||
public InMemoryPack deflate(byte[] content)
|
||||
throws IOException {
|
||||
Deflater deflater = new Deflater();
|
||||
byte[] buf = new byte[128];
|
||||
deflater.setInput(content, 0, content.length);
|
||||
deflater.finish();
|
||||
do {
|
||||
final int n = deflater.deflate(buf, 0, buf.length);
|
||||
if (n > 0)
|
||||
tinyPack.write(buf, 0, n);
|
||||
} while (!deflater.finished());
|
||||
return this;
|
||||
}
|
||||
|
||||
public InMemoryPack copyRaw(AnyObjectId o) throws IOException {
|
||||
o.copyRawTo(tinyPack);
|
||||
return this;
|
||||
}
|
||||
|
||||
public InMemoryPack digest() throws IOException {
|
||||
MessageDigest md = Constants.newMessageDigest();
|
||||
md.update(tinyPack.toByteArray());
|
||||
tinyPack.write(md.digest());
|
||||
return this;
|
||||
}
|
||||
|
||||
public InputStream toInputStream() throws IOException {
|
||||
return new ByteArrayInputStream(tinyPack.toByteArray());
|
||||
}
|
||||
|
||||
public byte[] toByteArray() throws IOException {
|
||||
return tinyPack.toByteArray();
|
||||
}
|
||||
}
|
|
@ -22,12 +22,10 @@
|
|||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
import org.eclipse.jgit.errors.TooLargeObjectInPackException;
|
||||
import org.eclipse.jgit.internal.JGitText;
|
||||
|
@ -42,8 +40,6 @@
|
|||
import org.eclipse.jgit.lib.ObjectInserter;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.revwalk.RevBlob;
|
||||
import org.eclipse.jgit.util.NB;
|
||||
import org.eclipse.jgit.util.TemporaryBuffer;
|
||||
import org.eclipse.jgit.util.io.UnionInputStream;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
@ -193,17 +189,14 @@ public void testTinyThinPack() throws Exception {
|
|||
a = d.blob("a");
|
||||
}
|
||||
|
||||
TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
|
||||
|
||||
packHeader(pack, 1);
|
||||
|
||||
InMemoryPack pack = new InMemoryPack();
|
||||
pack.header(1);
|
||||
pack.write((Constants.OBJ_REF_DELTA) << 4 | 4);
|
||||
a.copyRawTo(pack);
|
||||
deflate(pack, new byte[] { 0x1, 0x1, 0x1, 'b' });
|
||||
pack.copyRaw(a);
|
||||
pack.deflate(new byte[] { 0x1, 0x1, 0x1, 'b' });
|
||||
pack.digest();
|
||||
|
||||
digest(pack);
|
||||
|
||||
PackParser p = index(new ByteArrayInputStream(pack.toByteArray()));
|
||||
PackParser p = index(pack.toInputStream());
|
||||
p.setAllowThin(true);
|
||||
p.parse(NullProgressMonitor.INSTANCE);
|
||||
}
|
||||
|
@ -216,14 +209,14 @@ public void testPackWithDuplicateBlob() throws Exception {
|
|||
assertTrue(db.getObjectDatabase().has(d.blob(data)));
|
||||
}
|
||||
|
||||
TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
|
||||
packHeader(pack, 1);
|
||||
InMemoryPack pack = new InMemoryPack();
|
||||
pack.header(1);
|
||||
pack.write((Constants.OBJ_BLOB) << 4 | 0x80 | 1);
|
||||
pack.write(1);
|
||||
deflate(pack, data);
|
||||
digest(pack);
|
||||
pack.deflate(data);
|
||||
pack.digest();
|
||||
|
||||
PackParser p = index(new ByteArrayInputStream(pack.toByteArray()));
|
||||
PackParser p = index(pack.toInputStream());
|
||||
p.setAllowThin(false);
|
||||
p.parse(NullProgressMonitor.INSTANCE);
|
||||
}
|
||||
|
@ -236,16 +229,16 @@ public void testParseOfsDeltaFullSize() throws Exception {
|
|||
assertTrue(db.getObjectDatabase().has(d.blob(data)));
|
||||
}
|
||||
|
||||
TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
|
||||
packHeader(pack, 2);
|
||||
InMemoryPack pack = new InMemoryPack();
|
||||
pack.header(2);
|
||||
pack.write((Constants.OBJ_BLOB) << 4 | 10); // offset 12
|
||||
deflate(pack, data);
|
||||
pack.deflate(data);
|
||||
pack.write((Constants.OBJ_OFS_DELTA) << 4 | 4); // offset 31
|
||||
pack.write(19);
|
||||
deflate(pack, new byte[] { 0xA, 0xB, 0x1, 'b' });
|
||||
digest(pack);
|
||||
pack.deflate(new byte[] { 0xA, 0xB, 0x1, 'b' });
|
||||
pack.digest();
|
||||
|
||||
PackParser p = index(new ByteArrayInputStream(pack.toByteArray()));
|
||||
PackParser p = index(pack.toInputStream());
|
||||
p.parse(NullProgressMonitor.INSTANCE);
|
||||
|
||||
List<PackedObjectInfo> sortedObjectList = p.getSortedObjectList(null);
|
||||
|
@ -275,15 +268,15 @@ public void testPackWithTrailingGarbage() throws Exception {
|
|||
a = d.blob("a");
|
||||
}
|
||||
|
||||
TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
|
||||
packHeader(pack, 1);
|
||||
InMemoryPack pack = new InMemoryPack();
|
||||
pack.header(1);
|
||||
pack.write((Constants.OBJ_REF_DELTA) << 4 | 4);
|
||||
a.copyRawTo(pack);
|
||||
deflate(pack, new byte[] { 0x1, 0x1, 0x1, 'b' });
|
||||
digest(pack);
|
||||
pack.copyRaw(a);
|
||||
pack.deflate(new byte[] { 0x1, 0x1, 0x1, 'b' });
|
||||
pack.digest();
|
||||
|
||||
PackParser p = index(new UnionInputStream(
|
||||
new ByteArrayInputStream(pack.toByteArray()),
|
||||
pack.toInputStream(),
|
||||
new ByteArrayInputStream(new byte[] { 0x7e })));
|
||||
p.setAllowThin(true);
|
||||
p.setCheckEofAfterPackFooter(true);
|
||||
|
@ -305,22 +298,21 @@ public void testMaxObjectSizeFullBlob() throws Exception {
|
|||
d.blob(data);
|
||||
}
|
||||
|
||||
TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
|
||||
|
||||
packHeader(pack, 1);
|
||||
InMemoryPack pack = new InMemoryPack();
|
||||
pack.header(1);
|
||||
pack.write((Constants.OBJ_BLOB) << 4 | 10);
|
||||
deflate(pack, data);
|
||||
digest(pack);
|
||||
pack.deflate(data);
|
||||
pack.digest();
|
||||
|
||||
PackParser p = index(new ByteArrayInputStream(pack.toByteArray()));
|
||||
PackParser p = index(pack.toInputStream());
|
||||
p.setMaxObjectSizeLimit(11);
|
||||
p.parse(NullProgressMonitor.INSTANCE);
|
||||
|
||||
p = index(new ByteArrayInputStream(pack.toByteArray()));
|
||||
p = index(pack.toInputStream());
|
||||
p.setMaxObjectSizeLimit(10);
|
||||
p.parse(NullProgressMonitor.INSTANCE);
|
||||
|
||||
p = index(new ByteArrayInputStream(pack.toByteArray()));
|
||||
p = index(pack.toInputStream());
|
||||
p.setMaxObjectSizeLimit(9);
|
||||
try {
|
||||
p.parse(NullProgressMonitor.INSTANCE);
|
||||
|
@ -339,21 +331,20 @@ public void testMaxObjectSizeDeltaBlock() throws Exception {
|
|||
a = d.blob("a");
|
||||
}
|
||||
|
||||
TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
|
||||
|
||||
packHeader(pack, 1);
|
||||
InMemoryPack pack = new InMemoryPack();
|
||||
pack.header(1);
|
||||
pack.write((Constants.OBJ_REF_DELTA) << 4 | 14);
|
||||
a.copyRawTo(pack);
|
||||
deflate(pack, new byte[] { 1, 11, 11, 'a', '0', '1', '2', '3', '4',
|
||||
pack.copyRaw(a);
|
||||
pack.deflate(new byte[] { 1, 11, 11, 'a', '0', '1', '2', '3', '4',
|
||||
'5', '6', '7', '8', '9' });
|
||||
digest(pack);
|
||||
pack.digest();
|
||||
|
||||
PackParser p = index(new ByteArrayInputStream(pack.toByteArray()));
|
||||
PackParser p = index(pack.toInputStream());
|
||||
p.setAllowThin(true);
|
||||
p.setMaxObjectSizeLimit(14);
|
||||
p.parse(NullProgressMonitor.INSTANCE);
|
||||
|
||||
p = index(new ByteArrayInputStream(pack.toByteArray()));
|
||||
p = index(pack.toInputStream());
|
||||
p.setAllowThin(true);
|
||||
p.setMaxObjectSizeLimit(13);
|
||||
try {
|
||||
|
@ -373,20 +364,19 @@ public void testMaxObjectSizeDeltaResultSize() throws Exception {
|
|||
a = d.blob("0123456789");
|
||||
}
|
||||
|
||||
TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
|
||||
|
||||
packHeader(pack, 1);
|
||||
InMemoryPack pack = new InMemoryPack();
|
||||
pack.header(1);
|
||||
pack.write((Constants.OBJ_REF_DELTA) << 4 | 4);
|
||||
a.copyRawTo(pack);
|
||||
deflate(pack, new byte[] { 10, 11, 1, 'a' });
|
||||
digest(pack);
|
||||
pack.copyRaw(a);
|
||||
pack.deflate(new byte[] { 10, 11, 1, 'a' });
|
||||
pack.digest();
|
||||
|
||||
PackParser p = index(new ByteArrayInputStream(pack.toByteArray()));
|
||||
PackParser p = index(pack.toInputStream());
|
||||
p.setAllowThin(true);
|
||||
p.setMaxObjectSizeLimit(11);
|
||||
p.parse(NullProgressMonitor.INSTANCE);
|
||||
|
||||
p = index(new ByteArrayInputStream(pack.toByteArray()));
|
||||
p = index(pack.toInputStream());
|
||||
p.setAllowThin(true);
|
||||
p.setMaxObjectSizeLimit(10);
|
||||
try {
|
||||
|
@ -406,12 +396,12 @@ public void testNonMarkingInputStream() throws Exception {
|
|||
a = d.blob("a");
|
||||
}
|
||||
|
||||
TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
|
||||
packHeader(pack, 1);
|
||||
InMemoryPack pack = new InMemoryPack();
|
||||
pack.header(1);
|
||||
pack.write((Constants.OBJ_REF_DELTA) << 4 | 4);
|
||||
a.copyRawTo(pack);
|
||||
deflate(pack, new byte[] { 0x1, 0x1, 0x1, 'b' });
|
||||
digest(pack);
|
||||
pack.copyRaw(a);
|
||||
pack.deflate(new byte[] { 0x1, 0x1, 0x1, 'b' });
|
||||
pack.digest();
|
||||
|
||||
InputStream in = new ByteArrayInputStream(pack.toByteArray()) {
|
||||
@Override
|
||||
|
@ -447,12 +437,12 @@ public void testDataAfterPackFooterSingleRead() throws Exception {
|
|||
a = d.blob("a");
|
||||
}
|
||||
|
||||
TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(32*1024);
|
||||
packHeader(pack, 1);
|
||||
InMemoryPack pack = new InMemoryPack();
|
||||
pack.header(1);
|
||||
pack.write((Constants.OBJ_REF_DELTA) << 4 | 4);
|
||||
a.copyRawTo(pack);
|
||||
deflate(pack, new byte[] { 0x1, 0x1, 0x1, 'b' });
|
||||
digest(pack);
|
||||
pack.copyRaw(a);
|
||||
pack.deflate(new byte[] { 0x1, 0x1, 0x1, 'b' });
|
||||
pack.digest();
|
||||
|
||||
byte packData[] = pack.toByteArray();
|
||||
byte streamData[] = new byte[packData.length + 1];
|
||||
|
@ -476,14 +466,14 @@ public void testDataAfterPackFooterSplitObjectRead() throws Exception {
|
|||
|
||||
// Build a pack ~17k
|
||||
int objects = 900;
|
||||
TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(32 * 1024);
|
||||
packHeader(pack, objects);
|
||||
InMemoryPack pack = new InMemoryPack(32 * 1024);
|
||||
pack.header(objects);
|
||||
|
||||
for (int i = 0; i < objects; i++) {
|
||||
pack.write((Constants.OBJ_BLOB) << 4 | 10);
|
||||
deflate(pack, data);
|
||||
pack.deflate(data);
|
||||
}
|
||||
digest(pack);
|
||||
pack.digest();
|
||||
|
||||
byte packData[] = pack.toByteArray();
|
||||
byte streamData[] = new byte[packData.length + 1];
|
||||
|
@ -510,8 +500,9 @@ public void testDataAfterPackFooterSplitHeaderRead() throws Exception {
|
|||
}
|
||||
|
||||
int objects = 248;
|
||||
TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(32 * 1024);
|
||||
packHeader(pack, objects + 1);
|
||||
InMemoryPack pack = new InMemoryPack(32 * 1024);
|
||||
pack.header(objects + 1);
|
||||
|
||||
int offset = 13;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < offset; i++)
|
||||
|
@ -529,16 +520,16 @@ public void testDataAfterPackFooterSplitHeaderRead() throws Exception {
|
|||
lenByte |= 1 << 7;
|
||||
pack.write(lenByte);
|
||||
}
|
||||
deflate(pack, Constants.encode(sb.toString()));
|
||||
pack.deflate(Constants.encode(sb.toString()));
|
||||
|
||||
for (int i = 0; i < objects; i++) {
|
||||
// The last pack header written falls across the 8192 byte boundary
|
||||
// between [8189:8210]
|
||||
pack.write((Constants.OBJ_REF_DELTA) << 4 | 4);
|
||||
b.copyRawTo(pack);
|
||||
deflate(pack, new byte[] { 0x1, 0x1, 0x1, 'b' });
|
||||
pack.copyRaw(b);
|
||||
pack.deflate(new byte[] { 0x1, 0x1, 0x1, 'b' });
|
||||
}
|
||||
digest(pack);
|
||||
pack.digest();
|
||||
|
||||
byte packData[] = pack.toByteArray();
|
||||
byte streamData[] = new byte[packData.length + 1];
|
||||
|
@ -555,36 +546,6 @@ public void testDataAfterPackFooterSplitHeaderRead() throws Exception {
|
|||
assertEquals(0x7e, in.read());
|
||||
}
|
||||
|
||||
private static void packHeader(TemporaryBuffer.Heap tinyPack, int cnt)
|
||||
throws IOException {
|
||||
final byte[] hdr = new byte[8];
|
||||
NB.encodeInt32(hdr, 0, 2);
|
||||
NB.encodeInt32(hdr, 4, cnt);
|
||||
|
||||
tinyPack.write(Constants.PACK_SIGNATURE);
|
||||
tinyPack.write(hdr, 0, 8);
|
||||
}
|
||||
|
||||
private static void deflate(TemporaryBuffer.Heap tinyPack,
|
||||
final byte[] content)
|
||||
throws IOException {
|
||||
final Deflater deflater = new Deflater();
|
||||
final byte[] buf = new byte[128];
|
||||
deflater.setInput(content, 0, content.length);
|
||||
deflater.finish();
|
||||
do {
|
||||
final int n = deflater.deflate(buf, 0, buf.length);
|
||||
if (n > 0)
|
||||
tinyPack.write(buf, 0, n);
|
||||
} while (!deflater.finished());
|
||||
}
|
||||
|
||||
private static void digest(TemporaryBuffer.Heap buf) throws IOException {
|
||||
MessageDigest md = Constants.newMessageDigest();
|
||||
md.update(buf.toByteArray());
|
||||
buf.write(md.digest());
|
||||
}
|
||||
|
||||
private ObjectInserter inserter;
|
||||
|
||||
@After
|
||||
|
|
Loading…
Reference in New Issue