blob: bab4a36cc4bd5ce79ff266e29f49463745fa1c6e [file] [log] [blame]
/*
* Copyright (C) 2018, 2022 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 static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
import static org.eclipse.jgit.lib.Constants.OBJ_TAG;
import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
import static org.eclipse.jgit.transport.ObjectIdMatcher.hasOnlyObjectIds;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItems;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.eclipse.jgit.errors.PackProtocolException;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Before;
import org.junit.Test;
public class ProtocolV2ParserTest {
private TestRepository<InMemoryRepository> testRepo;
@Before
public void setUp() throws Exception {
testRepo = new TestRepository<>(newRepo("protocol-v2-parser-test"));
}
private static InMemoryRepository newRepo(String name) {
return new InMemoryRepository(new DfsRepositoryDescription(name));
}
private static class ConfigBuilder {
private boolean allowRefInWant;
private boolean allowFilter;
private ConfigBuilder() {
}
static ConfigBuilder start() {
return new ConfigBuilder();
}
static TransferConfig getDefault() {
return start().done();
}
ConfigBuilder allowRefInWant() {
allowRefInWant = true;
return this;
}
ConfigBuilder allowFilter() {
allowFilter = true;
return this;
}
TransferConfig done() {
Config rc = new Config();
rc.setBoolean("uploadpack", null, "allowrefinwant", allowRefInWant);
rc.setBoolean("uploadpack", null, "allowfilter", allowFilter);
return new TransferConfig(rc);
}
}
/*
* Convert the input lines to the PacketLine that the parser reads.
*/
private static PacketLineIn formatAsPacketLine(String... inputLines)
throws IOException {
ByteArrayOutputStream send = new ByteArrayOutputStream();
PacketLineOut pckOut = new PacketLineOut(send);
for (String line : inputLines) {
if (PacketLineIn.isEnd(line)) {
pckOut.end();
} else if (PacketLineIn.isDelimiter(line)) {
pckOut.writeDelim();
} else {
pckOut.writeString(line);
}
}
return new PacketLineIn(new ByteArrayInputStream(send.toByteArray()));
}
/*
* Successful fetch with the basic core commands of the protocol.
*/
@Test
public void testFetchBasicArguments()
throws PackProtocolException, IOException {
PacketLineIn pckIn = formatAsPacketLine(
PacketLineIn.delimiter(),
"thin-pack", "no-progress", "include-tag", "ofs-delta",
"want 4624442d68ee402a94364191085b77137618633e",
"want f900c8326a43303685c46b279b9f70411bff1a4b",
"have 554f6e41067b9e3e565b6988a8294fac1cb78f4b",
"have abc760ab9ad72f08209943251b36cb886a578f87", "done",
PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.getDefault());
FetchV2Request request = parser.parseFetchRequest(pckIn);
assertTrue(request.getClientCapabilities()
.contains(GitProtocolConstants.OPTION_THIN_PACK));
assertTrue(request.getClientCapabilities()
.contains(GitProtocolConstants.OPTION_NO_PROGRESS));
assertTrue(request.getClientCapabilities()
.contains(GitProtocolConstants.OPTION_INCLUDE_TAG));
assertTrue(request.getClientCapabilities()
.contains(GitProtocolConstants.CAPABILITY_OFS_DELTA));
assertThat(request.getWantIds(),
hasOnlyObjectIds("4624442d68ee402a94364191085b77137618633e",
"f900c8326a43303685c46b279b9f70411bff1a4b"));
assertThat(request.getPeerHas(),
hasOnlyObjectIds("554f6e41067b9e3e565b6988a8294fac1cb78f4b",
"abc760ab9ad72f08209943251b36cb886a578f87"));
assertTrue(request.getWantedRefs().isEmpty());
assertTrue(request.wasDoneReceived());
}
@Test
public void testFetchWithShallow_deepen() throws IOException {
PacketLineIn pckIn = formatAsPacketLine(
PacketLineIn.delimiter(),
"deepen 15",
"deepen-relative",
"shallow 28274d02c489f4c7e68153056e9061a46f62d7a0",
"shallow 145e683b229dcab9d0e2ccb01b386f9ecc17d29d",
PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.getDefault());
FetchV2Request request = parser.parseFetchRequest(pckIn);
assertThat(request.getClientShallowCommits(),
hasOnlyObjectIds("28274d02c489f4c7e68153056e9061a46f62d7a0",
"145e683b229dcab9d0e2ccb01b386f9ecc17d29d"));
assertTrue(request.getDeepenNots().isEmpty());
assertEquals(15, request.getDepth());
assertTrue(request.getClientCapabilities()
.contains(GitProtocolConstants.OPTION_DEEPEN_RELATIVE));
}
@Test
public void testFetchWithShallow_deepenNot() throws IOException {
PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(),
"shallow 28274d02c489f4c7e68153056e9061a46f62d7a0",
"shallow 145e683b229dcab9d0e2ccb01b386f9ecc17d29d",
"deepen-not a08595f76159b09d57553e37a5123f1091bb13e7",
PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.getDefault());
FetchV2Request request = parser.parseFetchRequest(pckIn);
assertThat(request.getClientShallowCommits(),
hasOnlyObjectIds("28274d02c489f4c7e68153056e9061a46f62d7a0",
"145e683b229dcab9d0e2ccb01b386f9ecc17d29d"));
assertThat(request.getDeepenNots(),
hasItems("a08595f76159b09d57553e37a5123f1091bb13e7"));
}
@Test
public void testFetchWithShallow_deepenSince() throws IOException {
PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(),
"shallow 28274d02c489f4c7e68153056e9061a46f62d7a0",
"shallow 145e683b229dcab9d0e2ccb01b386f9ecc17d29d",
"deepen-since 123123123",
PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.getDefault());
FetchV2Request request = parser.parseFetchRequest(pckIn);
assertThat(request.getClientShallowCommits(),
hasOnlyObjectIds("28274d02c489f4c7e68153056e9061a46f62d7a0",
"145e683b229dcab9d0e2ccb01b386f9ecc17d29d"));
assertEquals(123123123, request.getDeepenSince());
}
@Test
public void testFetchWithNoneFilter() throws IOException {
PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(),
"filter blob:none",
PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.start().allowFilter().done());
FetchV2Request request = parser.parseFetchRequest(pckIn);
assertFalse(request.getFilterSpec().allowsType(OBJ_BLOB));
assertTrue(request.getFilterSpec().allowsType(OBJ_TREE));
assertTrue(request.getFilterSpec().allowsType(OBJ_COMMIT));
assertTrue(request.getFilterSpec().allowsType(OBJ_TAG));
assertEquals(-1, request.getFilterSpec().getBlobLimit());
assertEquals(-1, request.getFilterSpec().getTreeDepthLimit());
}
@Test
public void testFetchWithBlobSizeFilter() throws IOException {
PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(),
"filter blob:limit=15",
PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.start().allowFilter().done());
FetchV2Request request = parser.parseFetchRequest(pckIn);
assertTrue(request.getFilterSpec().allowsType(OBJ_BLOB));
assertTrue(request.getFilterSpec().allowsType(OBJ_TREE));
assertTrue(request.getFilterSpec().allowsType(OBJ_COMMIT));
assertTrue(request.getFilterSpec().allowsType(OBJ_TAG));
assertEquals(15, request.getFilterSpec().getBlobLimit());
assertEquals(-1, request.getFilterSpec().getTreeDepthLimit());
}
@Test
public void testFetchWithTreeDepthFilter() throws IOException {
PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(),
"filter tree:3",
PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.start().allowFilter().done());
FetchV2Request request = parser.parseFetchRequest(pckIn);
assertTrue(request.getFilterSpec().allowsType(OBJ_BLOB));
assertTrue(request.getFilterSpec().allowsType(OBJ_TREE));
assertTrue(request.getFilterSpec().allowsType(OBJ_COMMIT));
assertTrue(request.getFilterSpec().allowsType(OBJ_TAG));
assertEquals(-1, request.getFilterSpec().getBlobLimit());
assertEquals(3, request.getFilterSpec().getTreeDepthLimit());
}
@Test
public void testFetchMustNotHaveMultipleFilters() throws IOException {
PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(),
"filter blob:none",
"filter blob:limit=12",
PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.start().allowFilter().done());
assertThrows(PackProtocolException.class,
() -> parser.parseFetchRequest(pckIn));
}
@Test
public void testFetchFilterWithoutAllowFilter() throws IOException {
PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(),
"filter blob:limit=12", PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.getDefault());
assertThrows(PackProtocolException.class,
() -> parser.parseFetchRequest(pckIn));
}
@Test
public void testFetchWithRefInWant() throws Exception {
RevCommit one = testRepo.commit().message("1").create();
RevCommit two = testRepo.commit().message("2").create();
testRepo.update("branchA", one);
testRepo.update("branchB", two);
PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(),
"want e4980cdc48cfa1301493ca94eb70523f6788b819",
"want-ref refs/heads/branchA",
PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.start().allowRefInWant().done());
FetchV2Request request = parser.parseFetchRequest(pckIn);
assertEquals(1, request.getWantedRefs().size());
assertThat(request.getWantedRefs(),
hasItems("refs/heads/branchA"));
assertEquals(1, request.getWantIds().size());
assertThat(request.getWantIds(), hasOnlyObjectIds(
"e4980cdc48cfa1301493ca94eb70523f6788b819"));
}
@Test
public void testFetchWithRefInWantUnknownRef() throws Exception {
PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(),
"want e4980cdc48cfa1301493ca94eb70523f6788b819",
"want-ref refs/heads/branchC",
PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.start().allowRefInWant().done());
RevCommit one = testRepo.commit().message("1").create();
RevCommit two = testRepo.commit().message("2").create();
testRepo.update("branchA", one);
testRepo.update("branchB", two);
FetchV2Request request = parser.parseFetchRequest(pckIn);
assertEquals(1, request.getWantedRefs().size());
assertThat(request.getWantedRefs(), hasItems("refs/heads/branchC"));
}
@Test
public void testLsRefsMinimalReq() throws IOException {
PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(),
PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.getDefault());
LsRefsV2Request req = parser.parseLsRefsRequest(pckIn);
assertFalse(req.getPeel());
assertFalse(req.getSymrefs());
assertEquals(0, req.getRefPrefixes().size());
}
@Test
public void testLsRefsSymrefs() throws IOException {
PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "symrefs",
PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.getDefault());
LsRefsV2Request req = parser.parseLsRefsRequest(pckIn);
assertFalse(req.getPeel());
assertTrue(req.getSymrefs());
assertEquals(0, req.getRefPrefixes().size());
}
@Test
public void testLsRefsPeel() throws IOException {
PacketLineIn pckIn = formatAsPacketLine(
PacketLineIn.delimiter(),
"peel",
PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.getDefault());
LsRefsV2Request req = parser.parseLsRefsRequest(pckIn);
assertTrue(req.getPeel());
assertFalse(req.getSymrefs());
assertEquals(0, req.getRefPrefixes().size());
}
@Test
public void testLsRefsRefPrefixes() throws IOException {
PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(),
"ref-prefix refs/for", "ref-prefix refs/heads",
PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.getDefault());
LsRefsV2Request req = parser.parseLsRefsRequest(pckIn);
assertFalse(req.getPeel());
assertFalse(req.getSymrefs());
assertEquals(2, req.getRefPrefixes().size());
assertThat(req.getRefPrefixes(), hasItems("refs/for", "refs/heads"));
}
@Test
public void testFetchWithSessionID() throws IOException {
PacketLineIn pckIn = formatAsPacketLine("session-id=the.client.sid",
PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.start().allowFilter().done());
FetchV2Request request = parser.parseFetchRequest(pckIn);
assertEquals("the.client.sid", request.getClientSID());
}
@Test
public void testLsRefsWithSessionID() throws IOException {
PacketLineIn pckIn = formatAsPacketLine("session-id=the.client.sid",
PacketLineIn.delimiter(), PacketLineIn.end());
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.getDefault());
LsRefsV2Request req = parser.parseLsRefsRequest(pckIn);
assertEquals("the.client.sid", req.getClientSID());
}
}