aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.test/tst
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit.test/tst')
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java10
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java36
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/SecurityManagerTest.java206
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AlternatesTest.java3
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java3
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java16
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java123
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java23
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RebaseTodoFileTest.java4
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java428
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java5
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PostUploadHookChainTest.java99
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PreUploadHookChainTest.java118
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2HookChainTest.java111
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java684
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FS_POSIXTest.java14
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitDateFormatterTest.java12
17 files changed, 1639 insertions, 256 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java
index 1dd329a9e7..714a54c90c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java
@@ -111,6 +111,16 @@ public class ApplyCommandTest extends RepositoryTestCase {
}
@Test
+ public void testAddA3() throws Exception {
+ ApplyResult result = init("A3", false, true);
+ assertEquals(1, result.getUpdatedFiles().size());
+ assertEquals(new File(db.getWorkTree(), "A3"),
+ result.getUpdatedFiles().get(0));
+ checkFile(new File(db.getWorkTree(), "A3"),
+ b.getString(0, b.size(), false));
+ }
+
+ @Test
public void testAddA1Sub() throws Exception {
ApplyResult result = init("A1_sub", false, false);
assertEquals(1, result.getUpdatedFiles().size());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
index dd7230bdbf..563b32dab8 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
@@ -194,6 +194,42 @@ public class ResetCommandTest extends RepositoryTestCase {
}
@Test
+ public void testHardResetWithConflicts_CreateFolder_UnstagedChanges() throws Exception {
+ setupRepository();
+
+ writeTrashFile("dir-or-file/c.txt", "content");
+ git.add().addFilepattern("dir-or-file/c.txt").call();
+ git.commit().setMessage("adding dir-or-file/c.txt").call();
+
+ FileUtils.delete(new File(db.getWorkTree(), "dir-or-file"), FileUtils.RECURSIVE);
+ writeTrashFile("dir-or-file", "content");
+
+ // bug 479266: cannot create folder "dir-or-file"
+ git.reset().setMode(ResetType.HARD).setRef(Constants.HEAD).call();
+ assertTrue(new File(db.getWorkTree(), "dir-or-file/c.txt").exists());
+ }
+
+ @Test
+ public void testHardResetWithConflicts_DeleteFolder_UnstagedChanges() throws Exception {
+ setupRepository();
+ ObjectId prevHead = db.resolve(Constants.HEAD);
+
+ writeTrashFile("dir-or-file/c.txt", "content");
+ git.add().addFilepattern("dir-or-file/c.txt").call();
+ git.commit().setMessage("adding dir-or-file/c.txt").call();
+
+ writeTrashFile("dir-or-file-2/d.txt", "content");
+ git.add().addFilepattern("dir-or-file-2/d.txt").call();
+ FileUtils.delete(new File(db.getWorkTree(), "dir-or-file-2"), FileUtils.RECURSIVE);
+ writeTrashFile("dir-or-file-2", "content");
+
+ // bug 479266: cannot delete folder "dir-or-file"
+ git.reset().setMode(ResetType.HARD).setRef(prevHead.getName()).call();
+ assertFalse(new File(db.getWorkTree(), "dir-or-file").exists());
+ assertFalse(new File(db.getWorkTree(), "dir-or-file-2").exists());
+ }
+
+ @Test
public void testResetToNonexistingHEAD() throws JGitInternalException,
AmbiguousObjectException, IOException, GitAPIException {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/SecurityManagerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/SecurityManagerTest.java
new file mode 100644
index 0000000000..62d3530338
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/SecurityManagerTest.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2019 Nail Samatov <sanail@yandex.ru>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FilePermission;
+import java.io.IOException;
+import java.lang.reflect.ReflectPermission;
+import java.nio.file.Files;
+import java.security.Permission;
+import java.security.SecurityPermission;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.PropertyPermission;
+import java.util.logging.LoggingPermission;
+
+import javax.security.auth.AuthPermission;
+
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.junit.JGitTestUtil;
+import org.eclipse.jgit.junit.MockSystemReader;
+import org.eclipse.jgit.junit.SeparateClassloaderTestRunner;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.util.FileUtils;
+import org.eclipse.jgit.util.SystemReader;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * <p>
+ * Tests if jgit works if SecurityManager is enabled.
+ * </p>
+ *
+ * <p>
+ * Note: JGit's classes shouldn't be used before SecurityManager is configured.
+ * If you use some JGit's class before SecurityManager is replaced then part of
+ * the code can be invoked outside of our custom SecurityManager and this test
+ * becomes useless.
+ * </p>
+ *
+ * <p>
+ * For example the class {@link org.eclipse.jgit.util.FS} is used widely in jgit
+ * sources. It contains DETECTED static field. At the first usage of the class
+ * FS the field DETECTED is initialized and during initialization many system
+ * operations that SecurityManager can forbid are invoked.
+ * </p>
+ *
+ * <p>
+ * For this reason this test doesn't extend LocalDiskRepositoryTestCase (it uses
+ * JGit's classes in setUp() method) and other JGit's utility classes. It's done
+ * to affect SecurityManager as less as possible.
+ * </p>
+ *
+ * <p>
+ * We use SeparateClassloaderTestRunner to isolate FS.DETECTED field
+ * initialization between different tests run.
+ * </p>
+ */
+@RunWith(SeparateClassloaderTestRunner.class)
+public class SecurityManagerTest {
+ private File root;
+
+ private SecurityManager originalSecurityManager;
+
+ private List<Permission> permissions = new ArrayList<>();
+
+ @Before
+ public void setUp() throws Exception {
+ // Create working directory
+ SystemReader.setInstance(new MockSystemReader());
+ root = Files.createTempDirectory("jgit-security").toFile();
+
+ // Add system permissions
+ permissions.add(new RuntimePermission("*"));
+ permissions.add(new SecurityPermission("*"));
+ permissions.add(new AuthPermission("*"));
+ permissions.add(new ReflectPermission("*"));
+ permissions.add(new PropertyPermission("*", "read,write"));
+ permissions.add(new LoggingPermission("control", null));
+
+ permissions.add(new FilePermission(
+ System.getProperty("java.home") + "/-", "read"));
+
+ String tempDir = System.getProperty("java.io.tmpdir");
+ permissions.add(new FilePermission(tempDir, "read,write,delete"));
+ permissions
+ .add(new FilePermission(tempDir + "/-", "read,write,delete"));
+
+ // Add permissions to dependent jar files.
+ String classPath = System.getProperty("java.class.path");
+ if (classPath != null) {
+ for (String path : classPath.split(File.pathSeparator)) {
+ permissions.add(new FilePermission(path, "read"));
+ }
+ }
+ // Add permissions to jgit class files.
+ String jgitSourcesRoot = new File(System.getProperty("user.dir"))
+ .getParent();
+ permissions.add(new FilePermission(jgitSourcesRoot + "/-", "read"));
+
+ // Add permissions to working dir for jgit. Our git repositories will be
+ // initialized and cloned here.
+ permissions.add(new FilePermission(root.getPath() + "/-",
+ "read,write,delete,execute"));
+
+ // Replace Security Manager
+ originalSecurityManager = System.getSecurityManager();
+ System.setSecurityManager(new SecurityManager() {
+
+ @Override
+ public void checkPermission(Permission requested) {
+ for (Permission permission : permissions) {
+ if (permission.implies(requested)) {
+ return;
+ }
+ }
+
+ super.checkPermission(requested);
+ }
+ });
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ System.setSecurityManager(originalSecurityManager);
+
+ // Note: don't use this method before security manager is replaced in
+ // setUp() method. The method uses FS.DETECTED internally and can affect
+ // the test.
+ FileUtils.delete(root, FileUtils.RECURSIVE | FileUtils.RETRY);
+ }
+
+ @Test
+ public void testInitAndClone() throws IOException, GitAPIException {
+ File remote = new File(root, "remote");
+ File local = new File(root, "local");
+
+ try (Git git = Git.init().setDirectory(remote).call()) {
+ JGitTestUtil.write(new File(remote, "hello.txt"), "Hello world!");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("Initial commit").call();
+ }
+
+ try (Git git = Git.cloneRepository().setURI(remote.toURI().toString())
+ .setDirectory(local).call()) {
+ assertTrue(new File(local, ".git").exists());
+
+ JGitTestUtil.write(new File(local, "hi.txt"), "Hi!");
+ git.add().addFilepattern(".").call();
+ RevCommit commit1 = git.commit().setMessage("Commit on local repo")
+ .call();
+ assertEquals("Commit on local repo", commit1.getFullMessage());
+ assertNotNull(TreeWalk.forPath(git.getRepository(), "hello.txt",
+ commit1.getTree()));
+ }
+
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AlternatesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AlternatesTest.java
index b09db03ea7..2306e0bbb1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AlternatesTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AlternatesTest.java
@@ -42,6 +42,7 @@
*/
package org.eclipse.jgit.internal.storage.file;
+import static org.eclipse.jgit.lib.Constants.INFO_ALTERNATES;
import static org.junit.Assert.assertTrue;
import java.io.File;
@@ -76,7 +77,7 @@ public class AlternatesTest extends SampleDataRepositoryTestCase {
private void setAlternate(FileRepository from, FileRepository to)
throws IOException {
File alt = new File(from.getObjectDatabase().getDirectory(),
- "info/alternates");
+ INFO_ALTERNATES);
alt.getParentFile().mkdirs();
File fromDir = from.getObjectDatabase().getDirectory();
File toDir = to.getObjectDatabase().getDirectory();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
index 5d0a7e2a0b..1e2341b6a5 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
@@ -44,6 +44,7 @@
package org.eclipse.jgit.internal.storage.file;
import static org.eclipse.jgit.internal.storage.pack.PackWriter.NONE;
+import static org.eclipse.jgit.lib.Constants.INFO_ALTERNATES;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -138,7 +139,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
config = new PackConfig(db);
dst = createBareRepository();
- File alt = new File(dst.getObjectDatabase().getDirectory(), "info/alternates");
+ File alt = new File(dst.getObjectDatabase().getDirectory(), INFO_ALTERNATES);
alt.getParentFile().mkdirs();
write(alt, db.getObjectDatabase().getDirectory().getAbsolutePath() + "\n");
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
index e2887d9053..43f30d8ca8 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
@@ -98,7 +98,7 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
public void test001_Initalize() {
final File gitdir = new File(trash, Constants.DOT_GIT);
final File hooks = new File(gitdir, "hooks");
- final File objects = new File(gitdir, "objects");
+ final File objects = new File(gitdir, Constants.OBJECTS);
final File objects_pack = new File(objects, "pack");
final File objects_info = new File(objects, "info");
final File refs = new File(gitdir, "refs");
@@ -150,7 +150,7 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
assertEqualsPath(theDir, r.getDirectory());
assertEqualsPath(repo1Parent, r.getWorkTree());
assertEqualsPath(new File(theDir, "index"), r.getIndexFile());
- assertEqualsPath(new File(theDir, "objects"), r.getObjectDatabase()
+ assertEqualsPath(new File(theDir, Constants.OBJECTS), r.getObjectDatabase()
.getDirectory());
}
@@ -176,7 +176,7 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
assertEqualsPath(theDir, r.getDirectory());
assertEqualsPath(repo1Parent.getParentFile(), r.getWorkTree());
assertEqualsPath(new File(theDir, "index"), r.getIndexFile());
- assertEqualsPath(new File(theDir, "objects"), r.getObjectDatabase()
+ assertEqualsPath(new File(theDir, Constants.OBJECTS), r.getObjectDatabase()
.getDirectory());
}
@@ -200,7 +200,7 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
assertEqualsPath(theDir, r.getDirectory());
assertEqualsPath(repo1Parent, r.getWorkTree());
assertEqualsPath(new File(theDir, "index"), r.getIndexFile());
- assertEqualsPath(new File(theDir, "objects"), r.getObjectDatabase()
+ assertEqualsPath(new File(theDir, Constants.OBJECTS), r.getObjectDatabase()
.getDirectory());
}
@@ -229,7 +229,7 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
assertEqualsPath(theDir, r.getDirectory());
assertEqualsPath(workdir, r.getWorkTree());
assertEqualsPath(new File(theDir, "index"), r.getIndexFile());
- assertEqualsPath(new File(theDir, "objects"), r.getObjectDatabase()
+ assertEqualsPath(new File(theDir, Constants.OBJECTS), r.getObjectDatabase()
.getDirectory());
}
@@ -258,7 +258,7 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
assertEqualsPath(theDir, r.getDirectory());
assertEqualsPath(workdir, r.getWorkTree());
assertEqualsPath(new File(theDir, "index"), r.getIndexFile());
- assertEqualsPath(new File(theDir, "objects"), r.getObjectDatabase()
+ assertEqualsPath(new File(theDir, Constants.OBJECTS), r.getObjectDatabase()
.getDirectory());
}
@@ -314,7 +314,7 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
}
final File o = new File(new File(new File(newdb.getDirectory(),
- "objects"), "4b"), "825dc642cb6eb9a060e54bf8d69288fbee4904");
+ Constants.OBJECTS), "4b"), "825dc642cb6eb9a060e54bf8d69288fbee4904");
assertTrue("Exists " + o, o.isFile());
assertTrue("Read-only " + o, !o.canWrite());
}
@@ -326,7 +326,7 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
final ObjectId treeId = insertTree(new TreeFormatter());
assertEquals("4b825dc642cb6eb9a060e54bf8d69288fbee4904", treeId.name());
final File o = new File(new File(
- new File(db.getDirectory(), "objects"), "4b"),
+ new File(db.getDirectory(), Constants.OBJECTS), "4b"),
"825dc642cb6eb9a060e54bf8d69288fbee4904");
assertFalse("Exists " + o, o.isFile());
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java
index a142166983..0e33fa6e76 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java
@@ -46,13 +46,16 @@ package org.eclipse.jgit.internal.storage.reftable;
import static org.eclipse.jgit.lib.Constants.HEAD;
import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
import static org.eclipse.jgit.lib.Constants.R_HEADS;
+import static org.eclipse.jgit.lib.MoreAsserts.assertThrows;
import static org.eclipse.jgit.lib.Ref.Storage.NEW;
import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
+import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -415,6 +418,54 @@ public class ReftableTest {
}
@Test
+ public void invalidRefWriteOrder() throws IOException {
+ Ref master = ref(MASTER, 1);
+ Ref next = ref(NEXT, 2);
+ ReftableWriter writer = new ReftableWriter()
+ .setMinUpdateIndex(1)
+ .setMaxUpdateIndex(1)
+ .begin(new ByteArrayOutputStream());
+
+ writer.writeRef(next);
+ IllegalArgumentException e = assertThrows(
+ IllegalArgumentException.class,
+ () -> writer.writeRef(master));
+ assertThat(e.getMessage(), containsString("records must be increasing"));
+ }
+
+ @Test
+ public void invalidReflogWriteOrderUpdateIndex() throws IOException {
+ ReftableWriter writer = new ReftableWriter()
+ .setMinUpdateIndex(1)
+ .setMaxUpdateIndex(2)
+ .begin(new ByteArrayOutputStream());
+ PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60);
+ String msg = "test";
+
+ writer.writeLog(MASTER, 1, who, ObjectId.zeroId(), id(1), msg);
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> writer.writeLog(
+ MASTER, 2, who, ObjectId.zeroId(), id(2), msg));
+ assertThat(e.getMessage(), containsString("records must be increasing"));
+ }
+
+ @Test
+ public void invalidReflogWriteOrderName() throws IOException {
+ ReftableWriter writer = new ReftableWriter()
+ .setMinUpdateIndex(1)
+ .setMaxUpdateIndex(1)
+ .begin(new ByteArrayOutputStream());
+ PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60);
+ String msg = "test";
+
+ writer.writeLog(NEXT, 1, who, ObjectId.zeroId(), id(1), msg);
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> writer.writeLog(
+ MASTER, 1, who, ObjectId.zeroId(), id(2), msg));
+ assertThat(e.getMessage(), containsString("records must be increasing"));
+ }
+
+ @Test
public void withReflog() throws IOException {
Ref master = ref(MASTER, 1);
Ref next = ref(NEXT, 2);
@@ -472,6 +523,74 @@ public class ReftableTest {
}
@Test
+ public void reflogSeek() throws IOException {
+ PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60);
+ String msg = "test";
+ String msgNext = "test next";
+
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ ReftableWriter writer = new ReftableWriter()
+ .setMinUpdateIndex(1)
+ .setMaxUpdateIndex(1)
+ .begin(buffer);
+
+ writer.writeLog(MASTER, 1, who, ObjectId.zeroId(), id(1), msg);
+ writer.writeLog(NEXT, 1, who, ObjectId.zeroId(), id(2), msgNext);
+
+ writer.finish();
+ byte[] table = buffer.toByteArray();
+
+ ReftableReader t = read(table);
+ try (LogCursor c = t.seekLog(MASTER, Long.MAX_VALUE)) {
+ assertTrue(c.next());
+ assertEquals(c.getReflogEntry().getComment(), msg);
+ }
+ try (LogCursor c = t.seekLog(MASTER, 0)) {
+ assertFalse(c.next());
+ }
+ try (LogCursor c = t.seekLog(MASTER, 1)) {
+ assertTrue(c.next());
+ assertEquals(c.getUpdateIndex(), 1);
+ assertEquals(c.getReflogEntry().getComment(), msg);
+ }
+ try (LogCursor c = t.seekLog(NEXT, Long.MAX_VALUE)) {
+ assertTrue(c.next());
+ assertEquals(c.getReflogEntry().getComment(), msgNext);
+ }
+ try (LogCursor c = t.seekLog(NEXT, 0)) {
+ assertFalse(c.next());
+ }
+ try (LogCursor c = t.seekLog(NEXT, 1)) {
+ assertTrue(c.next());
+ assertEquals(c.getUpdateIndex(), 1);
+ assertEquals(c.getReflogEntry().getComment(), msgNext);
+ }
+ }
+
+ @Test
+ public void reflogSeekPrefix() throws IOException {
+ PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60);
+
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ ReftableWriter writer = new ReftableWriter()
+ .setMinUpdateIndex(1)
+ .setMaxUpdateIndex(1)
+ .begin(buffer);
+
+ writer.writeLog("branchname", 1, who, ObjectId.zeroId(), id(1), "branchname");
+
+ writer.finish();
+ byte[] table = buffer.toByteArray();
+
+ ReftableReader t = read(table);
+ try (LogCursor c = t.seekLog("branch", Long.MAX_VALUE)) {
+ // We find a reflog block, but the iteration won't confuse branchname
+ // and branch.
+ assertFalse(c.next());
+ }
+ }
+
+ @Test
public void onlyReflog() throws IOException {
PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60);
String msg = "test";
@@ -505,6 +624,8 @@ public class ReftableTest {
assertEquals(ObjectId.zeroId(), lc.getReflogEntry().getOldId());
assertEquals(id(1), lc.getReflogEntry().getNewId());
assertEquals(who, lc.getReflogEntry().getWho());
+ // compare string too, to catch tz differences.
+ assertEquals(who.toExternalString(), lc.getReflogEntry().getWho().toExternalString());
assertEquals(msg, lc.getReflogEntry().getComment());
assertTrue(lc.next());
@@ -532,7 +653,7 @@ public class ReftableTest {
List<Ref> refs = new ArrayList<>();
for (int i = 1; i <= 5670; i++) {
- Ref ref = ref(String.format("refs/heads/%03d", i), i);
+ Ref ref = ref(String.format("refs/heads/%04d", i), i);
refs.add(ref);
writer.writeRef(ref);
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
index 483051ceeb..8092c3134b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
@@ -1977,6 +1977,29 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
}
}
+ @Test
+ public void testCheckoutWithEmptyIndexDoesntOverwrite() throws Exception {
+ try (Git git = new Git(db);
+ TestRepository<Repository> db_t = new TestRepository<>(db)) {
+ // prepare the commits
+ BranchBuilder master = db_t.branch("master");
+ RevCommit mergeCommit = master.commit()
+ .add("p/x", "headContent")
+ .message("m0").create();
+ master.commit().add("p/x", "headContent").message("m1").create();
+ git.checkout().setName("master").call();
+
+ // empty index and write unsaved data in 'p'
+ git.rm().addFilepattern("p").call();
+ writeTrashFile("p", "important data");
+
+ git.checkout().setName(mergeCommit.getName()).call();
+
+ assertEquals("", indexState(CONTENT));
+ assertEquals("important data", read("p"));
+ }
+ }
+
private static class TestFileTreeIterator extends FileTreeIterator {
// For assertions only
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RebaseTodoFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RebaseTodoFileTest.java
index 5cfc75ca93..3d3c697107 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RebaseTodoFileTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RebaseTodoFileTest.java
@@ -68,7 +68,7 @@ public class RebaseTodoFileTest extends RepositoryTestCase {
@Test
public void testReadTodoFile() throws Exception {
String[] expected = { "reword " + ObjectId.zeroId().name() + " Foo",
- "# A comment in the the todo list",
+ "# A comment in the todo list",
"pick " + ObjectId.zeroId().name() + " Foo fie",
"squash " + ObjectId.zeroId().name() + " F",
"fixup " + ObjectId.zeroId().name(),
@@ -93,7 +93,7 @@ public class RebaseTodoFileTest extends RepositoryTestCase {
assertEquals("Expected COMMENT", RebaseTodoLine.Action.COMMENT,
line.getAction());
assertEquals("Unexpected Message",
- "# A comment in the the todo list",
+ "# A comment in the todo list",
line.getComment());
break;
case 2:
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java
new file mode 100644
index 0000000000..1fc7a55457
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2019, Google LLC.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.filter.MessageRevFilter;
+import org.eclipse.jgit.revwalk.filter.RevFilter;
+import org.junit.Test;
+
+public class FirstParentRevWalkTest extends RevWalkTestCase {
+ @Test
+ public void testStringOfPearls() throws Exception {
+ RevCommit a = commit();
+ RevCommit b = commit(a);
+ RevCommit c = commit(b);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ markStart(c);
+ assertCommit(c, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testSideBranch() throws Exception {
+ RevCommit a = commit();
+ RevCommit b1 = commit(a);
+ RevCommit b2 = commit(a);
+ RevCommit c1 = commit(b1);
+ RevCommit c2 = commit(b2);
+ RevCommit d = commit(c1, c2);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ markStart(d);
+ assertCommit(d, rw.next());
+ assertCommit(c1, rw.next());
+ assertCommit(b1, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testSecondParentAncestorOfFirstParent() throws Exception {
+ RevCommit a = commit();
+ RevCommit b = commit(a);
+ RevCommit c = commit(b, a);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ markStart(c);
+ assertCommit(c, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testFirstParentMultipleOccurrences() throws Exception {
+ RevCommit a = commit();
+ RevCommit b = commit(a);
+ RevCommit c = commit(b);
+ RevCommit d = commit(b);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ markStart(c);
+ markStart(d);
+ assertCommit(d, rw.next());
+ assertCommit(c, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testReachableAlongFirstAndLaterParents() throws Exception {
+ RevCommit a = commit();
+ RevCommit b1 = commit(a);
+ RevCommit b2 = commit(a);
+ RevCommit b3 = commit(a);
+ RevCommit c = commit(b1, b2);
+ RevCommit d = commit(b2, b3);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ markStart(c);
+ markStart(d);
+ assertCommit(d, rw.next());
+ assertCommit(c, rw.next());
+ // b3 is only reachable from c's second parent.
+ // b2 is reachable from c's second parent but d's first parent.
+ assertCommit(b2, rw.next());
+ assertCommit(b1, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testStartCommitReachableOnlyFromLaterParents()
+ throws Exception {
+ RevCommit a = commit();
+ RevCommit b1 = commit(a);
+ RevCommit b2 = commit(a);
+ RevCommit c = commit(b1, b2);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ markStart(c);
+ markStart(b2);
+ assertCommit(c, rw.next());
+ // b2 is only reachable from second parent, but is itself a start
+ // commit.
+ assertCommit(b2, rw.next());
+ assertCommit(b1, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testRevFilter() throws Exception {
+ RevCommit a = commit();
+ RevCommit b1 = commitBuilder().parent(a).message("commit b1").create();
+ RevCommit b2 = commitBuilder().parent(a).message("commit b2").create();
+ RevCommit c = commit(b1, b2);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ rw.setRevFilter(MessageRevFilter.create("commit b"));
+ rw.markStart(c);
+ assertCommit(b1, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testTopoSort() throws Exception {
+ RevCommit a = commit();
+ RevCommit b1 = commit(a);
+ RevCommit b2 = commit(a);
+ RevCommit c = commit(b1, b2);
+
+ rw.reset();
+ rw.sort(RevSort.TOPO);
+ rw.setFirstParent(true);
+ markStart(c);
+ assertCommit(c, rw.next());
+ assertCommit(b1, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testCommitTimeSort() throws Exception {
+ RevCommit a = commit();
+ RevCommit b1 = commit(a);
+ RevCommit b2 = commit(a);
+ RevCommit c = commit(b1, b2);
+
+ rw.reset();
+ rw.sort(RevSort.COMMIT_TIME_DESC);
+ rw.setFirstParent(true);
+ markStart(c);
+ assertCommit(c, rw.next());
+ assertCommit(b1, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testReverseSort() throws Exception {
+ RevCommit a = commit();
+ RevCommit b1 = commit(a);
+ RevCommit b2 = commit(a);
+ RevCommit c = commit(b1, b2);
+
+ rw.reset();
+ rw.sort(RevSort.REVERSE);
+ rw.setFirstParent(true);
+ markStart(c);
+ assertCommit(a, rw.next());
+ assertCommit(b1, rw.next());
+ assertCommit(c, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testBoundarySort() throws Exception {
+ RevCommit a = commit();
+ RevCommit b = commit(a);
+ RevCommit c1 = commit(b);
+ RevCommit c2 = commit(b);
+ RevCommit d = commit(c1, c2);
+
+ rw.reset();
+ rw.sort(RevSort.BOUNDARY);
+ rw.setFirstParent(true);
+ markStart(d);
+ markUninteresting(a);
+ assertCommit(d, rw.next());
+ assertCommit(c1, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testFirstParentOfFirstParentMarkedUninteresting()
+ throws Exception {
+ RevCommit a = commit();
+ RevCommit b1 = commit(a);
+ RevCommit b2 = commit(a);
+ RevCommit c1 = commit(b1);
+ RevCommit c2 = commit(b2);
+ RevCommit d = commit(c1, c2);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ markStart(d);
+ markUninteresting(b1);
+ assertCommit(d, rw.next());
+ assertCommit(c1, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testUnparsedFirstParentOfFirstParentMarkedUninteresting()
+ throws Exception {
+ ObjectId a = unparsedCommit();
+ ObjectId b1 = unparsedCommit(a);
+ ObjectId b2 = unparsedCommit(a);
+ ObjectId c1 = unparsedCommit(b1);
+ ObjectId c2 = unparsedCommit(b2);
+ ObjectId d = unparsedCommit(c1, c2);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ RevCommit parsedD = rw.parseCommit(d);
+ markStart(parsedD);
+ markUninteresting(rw.parseCommit(b1));
+ assertCommit(parsedD, rw.next());
+ assertCommit(rw.parseCommit(c1), rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testFirstParentMarkedUninteresting() throws Exception {
+ RevCommit a = commit();
+ RevCommit b1 = commit(a);
+ RevCommit b2 = commit(a);
+ RevCommit c = commit(b1, b2);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ markStart(c);
+ markUninteresting(b1);
+ assertCommit(c, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testUnparsedFirstParentMarkedUninteresting() throws Exception {
+ ObjectId a = unparsedCommit();
+ ObjectId b1 = unparsedCommit(a);
+ ObjectId b2 = unparsedCommit(a);
+ ObjectId c = unparsedCommit(b1, b2);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ RevCommit parsedC = rw.parseCommit(c);
+ markStart(parsedC);
+ markUninteresting(rw.parseCommit(b1));
+ assertCommit(parsedC, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testUninterestingCommitWithTwoParents() throws Exception {
+ RevCommit a = commit();
+ RevCommit b = commit(a);
+ RevCommit c1 = commit(b);
+ RevCommit c2 = commit(b);
+ RevCommit d = commit(c1);
+ RevCommit e = commit(c1, c2);
+
+ RevCommit uA = commit(a, b);
+ RevCommit uB1 = commit(uA, c2);
+ RevCommit uB2 = commit(uA, d);
+ RevCommit uninteresting = commit(uB1, uB2);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ markStart(e);
+ markUninteresting(uninteresting);
+
+ assertCommit(e, rw.next());
+ assertNull(rw.next());
+ }
+
+ /**
+ * This fails if we try to propagate flags before parsing commits.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testUnparsedUninterestingCommitWithTwoParents()
+ throws Exception {
+ ObjectId a = unparsedCommit();
+ ObjectId b = unparsedCommit(a);
+ ObjectId c1 = unparsedCommit(b);
+ ObjectId c2 = unparsedCommit(b);
+ ObjectId d = unparsedCommit(c1);
+ ObjectId e = unparsedCommit(c1, c2);
+
+ ObjectId uA = unparsedCommit(a, b);
+ ObjectId uB1 = unparsedCommit(uA, c2);
+ ObjectId uB2 = unparsedCommit(uA, d);
+ ObjectId uninteresting = unparsedCommit(uB1, uB2);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ RevCommit parsedE = rw.parseCommit(e);
+ markStart(parsedE);
+ markUninteresting(rw.parseCommit(uninteresting));
+
+ assertCommit(parsedE, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testDepthWalk() throws Exception {
+ RevCommit a = commit();
+ RevCommit b1 = commit(a);
+ RevCommit b2 = commit(a);
+ RevCommit c = commit(b1, b2);
+
+ try (DepthWalk.RevWalk dw = new DepthWalk.RevWalk(db, 1)) {
+ dw.setFirstParent(true);
+ dw.markRoot(dw.parseCommit(c));
+ dw.markStart(dw.parseCommit(c));
+ assertEquals(c, dw.next());
+ assertEquals(b1, dw.next());
+ assertNull(dw.next());
+ }
+ }
+
+ @Test
+ public void testDoNotRewriteParents() throws Exception {
+ RevCommit a = commit();
+ RevCommit b1 = commit(a);
+ RevCommit b2 = commit(a);
+ RevCommit c = commit(b1, b2);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ rw.setRewriteParents(false);
+ markStart(c);
+ assertCommit(c, rw.next());
+ assertCommit(b1, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testMarkStartBeforeSetFirstParent() throws Exception {
+ RevCommit a = commit();
+
+ rw.reset();
+ markStart(a);
+ rw.setFirstParent(true);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testMergeBaseWithFirstParentNotAllowed() throws Exception {
+ RevCommit a = commit();
+
+ rw.reset();
+ rw.setFirstParent(true);
+ rw.setRevFilter(RevFilter.MERGE_BASE);
+ markStart(a);
+ assertNull(rw.next());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java
index 544398219f..a0056ae217 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java
@@ -51,6 +51,7 @@ import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.junit.TestRepository.CommitBuilder;
+import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
/** Support for tests of the {@link RevWalk} class. */
@@ -96,6 +97,10 @@ public abstract class RevWalkTestCase extends RepositoryTestCase {
return util.get(tree, path);
}
+ protected ObjectId unparsedCommit(ObjectId... parents) throws Exception {
+ return util.unparsedCommit(parents);
+ }
+
protected RevCommit commit(RevCommit... parents) throws Exception {
return util.commit(parents);
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PostUploadHookChainTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PostUploadHookChainTest.java
new file mode 100644
index 0000000000..ea7e8ed672
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PostUploadHookChainTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2019, Google LLC.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.transport;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.eclipse.jgit.storage.pack.PackStatistics;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class PostUploadHookChainTest {
+
+ @Test
+ public void testDefaultIfEmpty() {
+ PostUploadHook[] noHooks = {};
+ PostUploadHook newChain = PostUploadHookChain
+ .newChain(Arrays.asList(noHooks));
+ assertEquals(newChain, PostUploadHook.NULL);
+ }
+
+ @Test
+ public void testFlattenChainIfOnlyOne() {
+ FakePostUploadHook hook1 = new FakePostUploadHook();
+ PostUploadHook newChain = PostUploadHookChain
+ .newChain(Arrays.asList(PostUploadHook.NULL, hook1));
+ assertEquals(newChain, hook1);
+ }
+
+ @Test
+ public void testMultipleHooks() {
+ FakePostUploadHook hook1 = new FakePostUploadHook();
+ FakePostUploadHook hook2 = new FakePostUploadHook();
+
+ PostUploadHook chained = PostUploadHookChain
+ .newChain(Arrays.asList(hook1, hook2));
+ chained.onPostUpload(null);
+
+ assertTrue(hook1.wasInvoked());
+ assertTrue(hook2.wasInvoked());
+ }
+
+ private static final class FakePostUploadHook implements PostUploadHook {
+ boolean invoked;
+
+ public boolean wasInvoked() {
+ return invoked;
+ }
+
+ @Override
+ public void onPostUpload(PackStatistics stats) {
+ invoked = true;
+ }
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PreUploadHookChainTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PreUploadHookChainTest.java
new file mode 100644
index 0000000000..2a36d8a599
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PreUploadHookChainTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2019, Google LLC.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.transport;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class PreUploadHookChainTest {
+
+ @Test
+ public void testDefaultIfEmpty() {
+ PreUploadHook[] noHooks = {};
+ PreUploadHook newChain = PreUploadHookChain
+ .newChain(Arrays.asList(noHooks));
+ assertEquals(newChain, PreUploadHook.NULL);
+ }
+
+ @Test
+ public void testFlattenChainIfOnlyOne() {
+ FakePreUploadHook hook1 = new FakePreUploadHook();
+ PreUploadHook newChain = PreUploadHookChain
+ .newChain(Arrays.asList(PreUploadHook.NULL, hook1));
+ assertEquals(newChain, hook1);
+ }
+
+ @Test
+ public void testMultipleHooks() throws ServiceMayNotContinueException {
+ FakePreUploadHook hook1 = new FakePreUploadHook();
+ FakePreUploadHook hook2 = new FakePreUploadHook();
+
+ PreUploadHook chained = PreUploadHookChain
+ .newChain(Arrays.asList(hook1, hook2));
+ chained.onBeginNegotiateRound(null, null, 0);
+
+ assertTrue(hook1.wasInvoked());
+ assertTrue(hook2.wasInvoked());
+ }
+
+ private static final class FakePreUploadHook implements PreUploadHook {
+ boolean invoked;
+
+ @Override
+ public void onBeginNegotiateRound(UploadPack up,
+ Collection<? extends ObjectId> wants, int cntOffered)
+ throws ServiceMayNotContinueException {
+ invoked = true;
+ }
+
+ @Override
+ public void onEndNegotiateRound(UploadPack up,
+ Collection<? extends ObjectId> wants, int cntCommon,
+ int cntNotFound, boolean ready)
+ throws ServiceMayNotContinueException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void onSendPack(UploadPack up,
+ Collection<? extends ObjectId> wants,
+ Collection<? extends ObjectId> haves)
+ throws ServiceMayNotContinueException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean wasInvoked() {
+ return invoked;
+ }
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2HookChainTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2HookChainTest.java
new file mode 100644
index 0000000000..8fb1ca8199
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2HookChainTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2019, Google LLC.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.transport;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ProtocolV2HookChainTest {
+
+ @Test
+ public void testDefaultIfEmpty() {
+ ProtocolV2Hook[] noHooks = {};
+ ProtocolV2Hook newChain = ProtocolV2HookChain
+ .newChain(Arrays.asList(noHooks));
+ assertEquals(newChain, ProtocolV2Hook.DEFAULT);
+ }
+
+ @Test
+ public void testFlattenChainIfOnlyOne() {
+ FakeProtocolV2Hook hook1 = new FakeProtocolV2Hook();
+ ProtocolV2Hook newChain = ProtocolV2HookChain
+ .newChain(Arrays.asList(ProtocolV2Hook.DEFAULT, hook1));
+ assertEquals(newChain, hook1);
+ }
+
+ @Test
+ public void testMultipleHooks() throws ServiceMayNotContinueException {
+ FakeProtocolV2Hook hook1 = new FakeProtocolV2Hook();
+ FakeProtocolV2Hook hook2 = new FakeProtocolV2Hook();
+
+ ProtocolV2Hook chained = ProtocolV2HookChain
+ .newChain(Arrays.asList(hook1, hook2));
+ chained.onLsRefs(LsRefsV2Request.builder().build());
+
+ assertTrue(hook1.wasInvoked());
+ assertTrue(hook2.wasInvoked());
+ }
+
+ private static final class FakeProtocolV2Hook implements ProtocolV2Hook {
+ boolean invoked;
+
+ @Override
+ public void onLsRefs(LsRefsV2Request req)
+ throws ServiceMayNotContinueException {
+ invoked = true;
+ }
+
+ @Override
+ public void onCapabilities(CapabilitiesV2Request req)
+ throws ServiceMayNotContinueException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void onFetch(FetchV2Request req)
+ throws ServiceMayNotContinueException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean wasInvoked() {
+ return invoked;
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
index 260130b2bd..528a63f9c0 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
@@ -1,5 +1,7 @@
package org.eclipse.jgit.transport;
+import static org.eclipse.jgit.lib.MoreAsserts.assertThrows;
+import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.is;
@@ -9,27 +11,32 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.function.Consumer;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEntry;
-import org.eclipse.jgit.errors.PackProtocolException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.storage.dfs.DfsGarbageCollector;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.internal.storage.file.PackLock;
+import org.eclipse.jgit.internal.storage.pack.CachedPack;
+import org.eclipse.jgit.internal.storage.pack.CachedPackUriProvider;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
@@ -47,25 +54,19 @@ import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.storage.pack.PackStatistics;
import org.eclipse.jgit.transport.UploadPack.RequestPolicy;
import org.eclipse.jgit.util.io.NullOutputStream;
-import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
/**
* Tests for server upload-pack utilities.
*/
public class UploadPackTest {
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
private URIish uri;
private TestProtocol<Object> testProtocol;
- private Object ctx = new Object();
+ private final Object ctx = new Object();
private InMemoryRepository server;
@@ -144,11 +145,11 @@ public class UploadPackTest {
assertFalse(client.getObjectDatabase().has(blob.toObjectId()));
try (Transport tn = testProtocol.open(uri, client, "server")) {
- thrown.expect(TransportException.class);
- thrown.expectMessage(Matchers.containsString(
- "want " + blob.name() + " not valid"));
- tn.fetch(NullProgressMonitor.INSTANCE,
- Collections.singletonList(new RefSpec(blob.name())));
+ TransportException e = assertThrows(TransportException.class,
+ () -> tn.fetch(NullProgressMonitor.INSTANCE, Collections
+ .singletonList(new RefSpec(blob.name()))));
+ assertThat(e.getMessage(),
+ containsString("want " + blob.name() + " not valid"));
}
}
@@ -183,11 +184,41 @@ public class UploadPackTest {
assertFalse(client.getObjectDatabase().has(blob.toObjectId()));
try (Transport tn = testProtocol.open(uri, client, "server")) {
- thrown.expect(TransportException.class);
- thrown.expectMessage(Matchers.containsString(
+ TransportException e = assertThrows(TransportException.class,
+ () -> tn.fetch(NullProgressMonitor.INSTANCE, Collections
+ .singletonList(new RefSpec(blob.name()))));
+ assertThat(e.getMessage(),
+ containsString(
"want " + blob.name() + " not valid"));
- tn.fetch(NullProgressMonitor.INSTANCE,
- Collections.singletonList(new RefSpec(blob.name())));
+ }
+ }
+
+ @Test
+ public void testFetchReachableBlobWithoutBitmapButFilterAllowed() throws Exception {
+ InMemoryRepository server2 = newRepo("server2");
+ try (TestRepository<InMemoryRepository> remote2 = new TestRepository<>(
+ server2)) {
+ RevBlob blob = remote2.blob("foo");
+ RevCommit commit = remote2.commit(remote2.tree(remote2.file("foo", blob)));
+ remote2.update("master", commit);
+
+ server2.getConfig().setBoolean("uploadpack", null, "allowfilter",
+ true);
+
+ testProtocol = new TestProtocol<>((Object req, Repository db) -> {
+ UploadPack up = new UploadPack(db);
+ up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT);
+ return up;
+ }, null);
+ uri = testProtocol.register(ctx, server2);
+
+ assertFalse(client.getObjectDatabase().has(blob.toObjectId()));
+
+ try (Transport tn = testProtocol.open(uri, client, "server2")) {
+ tn.fetch(NullProgressMonitor.INSTANCE,
+ Collections.singletonList(new RefSpec(blob.name())));
+ assertTrue(client.getObjectDatabase().has(blob.toObjectId()));
+ }
}
}
@@ -384,12 +415,11 @@ public class UploadPackTest {
try (Transport tn = testProtocol.open(uri, client, "server2")) {
tn.setFilterSpec(FilterSpec.withBlobLimit(0));
- thrown.expect(TransportException.class);
- thrown.expectMessage(
- "filter requires server to advertise that capability");
-
- tn.fetch(NullProgressMonitor.INSTANCE,
- Collections.singletonList(new RefSpec(commit.name())));
+ TransportException e = assertThrows(TransportException.class,
+ () -> tn.fetch(NullProgressMonitor.INSTANCE, Collections
+ .singletonList(new RefSpec(commit.name()))));
+ assertThat(e.getMessage(), containsString(
+ "filter requires server to advertise that capability"));
}
}
}
@@ -398,22 +428,18 @@ public class UploadPackTest {
* Invokes UploadPack with protocol v2 and sends it the given lines,
* and returns UploadPack's output stream.
*/
- private ByteArrayInputStream uploadPackV2Setup(RequestPolicy requestPolicy,
- RefFilter refFilter, ProtocolV2Hook hook, String... inputLines)
+ private ByteArrayInputStream uploadPackV2Setup(
+ Consumer<UploadPack> postConstructionSetup, String... inputLines)
throws Exception {
ByteArrayInputStream send = linesAsInputStream(inputLines);
server.getConfig().setString("protocol", null, "version", "2");
UploadPack up = new UploadPack(server);
- if (requestPolicy != null)
- up.setRequestPolicy(requestPolicy);
- if (refFilter != null)
- up.setRefFilter(refFilter);
- up.setExtraParameters(Sets.of("version=2"));
- if (hook != null) {
- up.setProtocolV2Hook(hook);
+ if (postConstructionSetup != null) {
+ postConstructionSetup.accept(up);
}
+ up.setExtraParameters(Sets.of("version=2"));
ByteArrayOutputStream recv = new ByteArrayOutputStream();
up.upload(send, recv, null);
@@ -427,6 +453,7 @@ public class UploadPackTest {
try (ByteArrayOutputStream send = new ByteArrayOutputStream()) {
PacketLineOut pckOut = new PacketLineOut(send);
for (String line : inputLines) {
+ Objects.requireNonNull(line);
if (PacketLineIn.isEnd(line)) {
pckOut.end();
} else if (PacketLineIn.isDelimiter(line)) {
@@ -444,11 +471,12 @@ public class UploadPackTest {
* Returns UploadPack's output stream, not including the capability
* advertisement by the server.
*/
- private ByteArrayInputStream uploadPackV2(RequestPolicy requestPolicy,
- RefFilter refFilter, ProtocolV2Hook hook, String... inputLines)
+ private ByteArrayInputStream uploadPackV2(
+ Consumer<UploadPack> postConstructionSetup,
+ String... inputLines)
throws Exception {
ByteArrayInputStream recvStream =
- uploadPackV2Setup(requestPolicy, refFilter, hook, inputLines);
+ uploadPackV2Setup(postConstructionSetup, inputLines);
PacketLineIn pckIn = new PacketLineIn(recvStream);
// drain capabilities
@@ -459,7 +487,7 @@ public class UploadPackTest {
}
private ByteArrayInputStream uploadPackV2(String... inputLines) throws Exception {
- return uploadPackV2(null, null, null, inputLines);
+ return uploadPackV2(null, inputLines);
}
private static class TestV2Hook implements ProtocolV2Hook {
@@ -488,8 +516,9 @@ public class UploadPackTest {
@Test
public void testV2Capabilities() throws Exception {
TestV2Hook hook = new TestV2Hook();
- ByteArrayInputStream recvStream =
- uploadPackV2Setup(null, null, hook, PacketLineIn.end());
+ ByteArrayInputStream recvStream = uploadPackV2Setup(
+ (UploadPack up) -> {up.setProtocolV2Hook(hook);},
+ PacketLineIn.end());
PacketLineIn pckIn = new PacketLineIn(recvStream);
assertThat(hook.capabilitiesRequest, notNullValue());
assertThat(pckIn.readString(), is("version 2"));
@@ -506,54 +535,72 @@ public class UploadPackTest {
assertTrue(PacketLineIn.isEnd(pckIn.readString()));
}
- @Test
- public void testV2CapabilitiesAllowFilter() throws Exception {
- server.getConfig().setBoolean("uploadpack", null, "allowfilter", true);
+ private void checkAdvertisedIfAllowed(String configSection, String configName,
+ String fetchCapability) throws Exception {
+ server.getConfig().setBoolean(configSection, null, configName, true);
ByteArrayInputStream recvStream =
- uploadPackV2Setup(null, null, null, PacketLineIn.end());
+ uploadPackV2Setup(null, PacketLineIn.end());
PacketLineIn pckIn = new PacketLineIn(recvStream);
assertThat(pckIn.readString(), is("version 2"));
- assertThat(
- Arrays.asList(pckIn.readString(), pckIn.readString(),
- pckIn.readString()),
- // TODO(jonathantanmy) This check overspecifies the
- // order of the capabilities of "fetch".
- hasItems("ls-refs", "fetch=filter shallow", "server-option"));
- assertTrue(PacketLineIn.isEnd(pckIn.readString()));
+
+ ArrayList<String> lines = new ArrayList<>();
+ String line;
+ while (!PacketLineIn.isEnd((line = pckIn.readString()))) {
+ if (line.startsWith("fetch=")) {
+ assertThat(
+ Arrays.asList(line.substring(6).split(" ")),
+ containsInAnyOrder(fetchCapability, "shallow"));
+ lines.add("fetch");
+ } else {
+ lines.add(line);
+ }
+ }
+ assertThat(lines, containsInAnyOrder("ls-refs", "fetch", "server-option"));
}
- @Test
- public void testV2CapabilitiesRefInWant() throws Exception {
- server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true);
+ private void checkUnadvertisedIfUnallowed(String fetchCapability) throws Exception {
ByteArrayInputStream recvStream =
- uploadPackV2Setup(null, null, null, PacketLineIn.end());
+ uploadPackV2Setup(null, PacketLineIn.end());
PacketLineIn pckIn = new PacketLineIn(recvStream);
assertThat(pckIn.readString(), is("version 2"));
- assertThat(
- Arrays.asList(pckIn.readString(), pckIn.readString(),
- pckIn.readString()),
- // TODO(jonathantanmy) This check overspecifies the
- // order of the capabilities of "fetch".
- hasItems("ls-refs", "fetch=ref-in-want shallow",
- "server-option"));
- assertTrue(PacketLineIn.isEnd(pckIn.readString()));
+
+ ArrayList<String> lines = new ArrayList<>();
+ String line;
+ while (!PacketLineIn.isEnd((line = pckIn.readString()))) {
+ if (line.startsWith("fetch=")) {
+ assertThat(
+ Arrays.asList(line.substring(6).split(" ")),
+ hasItems("shallow"));
+ lines.add("fetch");
+ } else {
+ lines.add(line);
+ }
+ }
+ assertThat(lines, hasItems("ls-refs", "fetch", "server-option"));
+ }
+
+ @Test
+ public void testV2CapabilitiesAllowFilter() throws Exception {
+ checkAdvertisedIfAllowed("uploadpack", "allowfilter", "filter");
+ checkUnadvertisedIfUnallowed("filter");
+ }
+
+ @Test
+ public void testV2CapabilitiesRefInWant() throws Exception {
+ checkAdvertisedIfAllowed("uploadpack", "allowrefinwant", "ref-in-want");
}
@Test
public void testV2CapabilitiesRefInWantNotAdvertisedIfUnallowed() throws Exception {
- server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", false);
- ByteArrayInputStream recvStream =
- uploadPackV2Setup(null, null, null, PacketLineIn.end());
- PacketLineIn pckIn = new PacketLineIn(recvStream);
+ checkUnadvertisedIfUnallowed("ref-in-want");
+ }
- assertThat(pckIn.readString(), is("version 2"));
- assertThat(
- Arrays.asList(pckIn.readString(), pckIn.readString(),
- pckIn.readString()),
- hasItems("ls-refs", "fetch=shallow", "server-option"));
- assertTrue(PacketLineIn.isEnd(pckIn.readString()));
+ @Test
+ public void testV2CapabilitiesAllowSidebandAll() throws Exception {
+ checkAdvertisedIfAllowed("uploadpack", "allowsidebandall", "sideband-all");
+ checkUnadvertisedIfUnallowed("sideband-all");
}
@Test
@@ -561,7 +608,7 @@ public class UploadPackTest {
server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true);
server.getConfig().setBoolean("uploadpack", null, "advertiserefinwant", false);
ByteArrayInputStream recvStream =
- uploadPackV2Setup(null, null, null, PacketLineIn.end());
+ uploadPackV2Setup(null, PacketLineIn.end());
PacketLineIn pckIn = new PacketLineIn(recvStream);
assertThat(pckIn.readString(), is("version 2"));
@@ -589,7 +636,8 @@ public class UploadPackTest {
remote.update("refs/tags/tag", tag);
TestV2Hook hook = new TestV2Hook();
- ByteArrayInputStream recvStream = uploadPackV2(null, null, hook,
+ ByteArrayInputStream recvStream = uploadPackV2(
+ (UploadPack up) -> {up.setProtocolV2Hook(hook);},
"command=ls-refs\n", PacketLineIn.end());
PacketLineIn pckIn = new PacketLineIn(recvStream);
@@ -707,13 +755,13 @@ public class UploadPackTest {
@Test
public void testV2LsRefsUnrecognizedArgument() throws Exception {
- thrown.expect(PackProtocolException.class);
- thrown.expectMessage("unexpected invalid-argument");
- uploadPackV2(
- "command=ls-refs\n",
- PacketLineIn.delimiter(),
- "invalid-argument\n",
- PacketLineIn.end());
+ UploadPackInternalServerErrorException e = assertThrows(
+ UploadPackInternalServerErrorException.class,
+ () -> uploadPackV2("command=ls-refs\n",
+ PacketLineIn.delimiter(), "invalid-argument\n",
+ PacketLineIn.end()));
+ assertThat(e.getCause().getMessage(),
+ containsString("unexpected invalid-argument"));
}
@Test
@@ -724,7 +772,7 @@ public class UploadPackTest {
PacketLineIn.end() };
TestV2Hook testHook = new TestV2Hook();
- uploadPackV2Setup(null, null, testHook, lines);
+ uploadPackV2Setup((UploadPack up) -> {up.setProtocolV2Hook(testHook);}, lines);
LsRefsV2Request req = testHook.lsRefsRequest;
assertEquals(2, req.getServerOptions().size());
@@ -761,118 +809,117 @@ public class UploadPackTest {
// This works
uploadPackV2(
- RequestPolicy.ADVERTISED,
- null,
- null,
+ (UploadPack up) -> {up.setRequestPolicy(RequestPolicy.ADVERTISED);},
"command=fetch\n",
PacketLineIn.delimiter(),
"want " + advertized.name() + "\n",
- PacketLineIn.end());
+ PacketLineIn.end());
// This doesn't
- thrown.expect(TransportException.class);
- thrown.expectMessage(Matchers.containsString(
- "want " + unadvertized.name() + " not valid"));
- uploadPackV2(
- RequestPolicy.ADVERTISED,
- null,
- null,
- "command=fetch\n",
- PacketLineIn.delimiter(),
- "want " + unadvertized.name() + "\n",
- PacketLineIn.end());
+ UploadPackInternalServerErrorException e = assertThrows(
+ UploadPackInternalServerErrorException.class,
+ () -> uploadPackV2(
+ (UploadPack up) -> {up.setRequestPolicy(RequestPolicy.ADVERTISED);},
+ "command=fetch\n", PacketLineIn.delimiter(),
+ "want " + unadvertized.name() + "\n",
+ PacketLineIn.end()));
+ assertThat(e.getCause().getMessage(),
+ containsString("want " + unadvertized.name() + " not valid"));
}
@Test
public void testV2FetchRequestPolicyReachableCommit() throws Exception {
RevCommit reachable = remote.commit().message("x").create();
- RevCommit advertized = remote.commit().message("x").parent(reachable).create();
+ RevCommit advertized = remote.commit().message("x").parent(reachable)
+ .create();
RevCommit unreachable = remote.commit().message("y").create();
remote.update("branch1", advertized);
// This works
uploadPackV2(
- RequestPolicy.REACHABLE_COMMIT,
- null,
- null,
+ (UploadPack up) -> {up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT);},
"command=fetch\n",
PacketLineIn.delimiter(),
"want " + reachable.name() + "\n",
PacketLineIn.end());
// This doesn't
- thrown.expect(TransportException.class);
- thrown.expectMessage(Matchers.containsString(
- "want " + unreachable.name() + " not valid"));
- uploadPackV2(
- RequestPolicy.REACHABLE_COMMIT,
- null,
- null,
- "command=fetch\n",
- PacketLineIn.delimiter(),
- "want " + unreachable.name() + "\n",
- PacketLineIn.end());
+ UploadPackInternalServerErrorException e = assertThrows(
+ UploadPackInternalServerErrorException.class,
+ () -> uploadPackV2(
+ (UploadPack up) -> {up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT);},
+ "command=fetch\n", PacketLineIn.delimiter(),
+ "want " + unreachable.name() + "\n",
+ PacketLineIn.end()));
+ assertThat(e.getCause().getMessage(),
+ containsString("want " + unreachable.name() + " not valid"));
}
@Test
public void testV2FetchRequestPolicyTip() throws Exception {
RevCommit parentOfTip = remote.commit().message("x").create();
- RevCommit tip = remote.commit().message("y").parent(parentOfTip).create();
+ RevCommit tip = remote.commit().message("y").parent(parentOfTip)
+ .create();
remote.update("secret", tip);
// This works
uploadPackV2(
- RequestPolicy.TIP,
- new RejectAllRefFilter(),
- null,
+ (UploadPack up) -> {
+ up.setRequestPolicy(RequestPolicy.TIP);
+ up.setRefFilter(new RejectAllRefFilter());
+ },
"command=fetch\n",
PacketLineIn.delimiter(),
"want " + tip.name() + "\n",
PacketLineIn.end());
// This doesn't
- thrown.expect(TransportException.class);
- thrown.expectMessage(Matchers.containsString(
- "want " + parentOfTip.name() + " not valid"));
- uploadPackV2(
- RequestPolicy.TIP,
- new RejectAllRefFilter(),
- null,
- "command=fetch\n",
- PacketLineIn.delimiter(),
- "want " + parentOfTip.name() + "\n",
- PacketLineIn.end());
+ UploadPackInternalServerErrorException e = assertThrows(
+ UploadPackInternalServerErrorException.class,
+ () -> uploadPackV2(
+ (UploadPack up) -> {
+ up.setRequestPolicy(RequestPolicy.TIP);
+ up.setRefFilter(new RejectAllRefFilter());
+ },
+ "command=fetch\n", PacketLineIn.delimiter(),
+ "want " + parentOfTip.name() + "\n",
+ PacketLineIn.end()));
+ assertThat(e.getCause().getMessage(),
+ containsString("want " + parentOfTip.name() + " not valid"));
}
@Test
public void testV2FetchRequestPolicyReachableCommitTip() throws Exception {
RevCommit parentOfTip = remote.commit().message("x").create();
- RevCommit tip = remote.commit().message("y").parent(parentOfTip).create();
+ RevCommit tip = remote.commit().message("y").parent(parentOfTip)
+ .create();
RevCommit unreachable = remote.commit().message("y").create();
remote.update("secret", tip);
// This works
uploadPackV2(
- RequestPolicy.REACHABLE_COMMIT_TIP,
- new RejectAllRefFilter(),
- null,
- "command=fetch\n",
- PacketLineIn.delimiter(),
- "want " + parentOfTip.name() + "\n",
+ (UploadPack up) -> {
+ up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT_TIP);
+ up.setRefFilter(new RejectAllRefFilter());
+ },
+ "command=fetch\n",
+ PacketLineIn.delimiter(), "want " + parentOfTip.name() + "\n",
PacketLineIn.end());
// This doesn't
- thrown.expect(TransportException.class);
- thrown.expectMessage(Matchers.containsString(
- "want " + unreachable.name() + " not valid"));
- uploadPackV2(
- RequestPolicy.REACHABLE_COMMIT_TIP,
- new RejectAllRefFilter(),
- null,
- "command=fetch\n",
- PacketLineIn.delimiter(),
- "want " + unreachable.name() + "\n",
- PacketLineIn.end());
+ UploadPackInternalServerErrorException e = assertThrows(
+ UploadPackInternalServerErrorException.class,
+ () -> uploadPackV2(
+ (UploadPack up) -> {
+ up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT_TIP);
+ up.setRefFilter(new RejectAllRefFilter());
+ },
+ "command=fetch\n",
+ PacketLineIn.delimiter(),
+ "want " + unreachable.name() + "\n",
+ PacketLineIn.end()));
+ assertThat(e.getCause().getMessage(),
+ containsString("want " + unreachable.name() + " not valid"));
}
@Test
@@ -881,9 +928,7 @@ public class UploadPackTest {
// Exercise to make sure that even unreachable commits can be fetched
uploadPackV2(
- RequestPolicy.ANY,
- null,
- null,
+ (UploadPack up) -> {up.setRequestPolicy(RequestPolicy.ANY);},
"command=fetch\n",
PacketLineIn.delimiter(),
"want " + unreachable.name() + "\n",
@@ -980,29 +1025,29 @@ public class UploadPackTest {
String commonInBlob = "abcdefghijklmnopqrstuvwxyz";
RevBlob parentBlob = remote.blob(commonInBlob + "a");
- RevCommit parent = remote.commit(remote.tree(remote.file("foo", parentBlob)));
+ RevCommit parent = remote
+ .commit(remote.tree(remote.file("foo", parentBlob)));
RevBlob childBlob = remote.blob(commonInBlob + "b");
- RevCommit child = remote.commit(remote.tree(remote.file("foo", childBlob)), parent);
+ RevCommit child = remote
+ .commit(remote.tree(remote.file("foo", childBlob)), parent);
remote.update("branch1", child);
// Pretend that we have parent to get a thin pack based on it.
- ByteArrayInputStream recvStream = uploadPackV2(
- "command=fetch\n",
- PacketLineIn.delimiter(),
- "want " + child.toObjectId().getName() + "\n",
- "have " + parent.toObjectId().getName() + "\n",
- "thin-pack\n",
- "done\n",
- PacketLineIn.end());
+ ByteArrayInputStream recvStream = uploadPackV2("command=fetch\n",
+ PacketLineIn.delimiter(),
+ "want " + child.toObjectId().getName() + "\n",
+ "have " + parent.toObjectId().getName() + "\n", "thin-pack\n",
+ "done\n", PacketLineIn.end());
PacketLineIn pckIn = new PacketLineIn(recvStream);
assertThat(pckIn.readString(), is("packfile"));
// Verify that we received a thin pack by trying to apply it
// against the client repo, which does not have parent.
- thrown.expect(IOException.class);
- thrown.expectMessage("pack has unresolved deltas");
- parsePack(recvStream);
+ IOException e = assertThrows(IOException.class,
+ () -> parsePack(recvStream));
+ assertThat(e.getMessage(),
+ containsString("pack has unresolved deltas"));
}
@Test
@@ -1303,19 +1348,18 @@ public class UploadPackTest {
PersonIdent person = new PersonIdent(remote.getRepository());
RevCommit tooOld = remote.commit()
- .committer(new PersonIdent(person, 1500000000, 0)).create();
+ .committer(new PersonIdent(person, 1500000000, 0)).create();
remote.update("branch1", tooOld);
- thrown.expect(PackProtocolException.class);
- thrown.expectMessage("No commits selected for shallow request");
- uploadPackV2(
- "command=fetch\n",
- PacketLineIn.delimiter(),
- "deepen-since 1510000\n",
- "want " + tooOld.toObjectId().getName() + "\n",
- "done\n",
- PacketLineIn.end());
+ UploadPackInternalServerErrorException e = assertThrows(
+ UploadPackInternalServerErrorException.class,
+ () -> uploadPackV2("command=fetch\n", PacketLineIn.delimiter(),
+ "deepen-since 1510000\n",
+ "want " + tooOld.toObjectId().getName() + "\n",
+ "done\n", PacketLineIn.end()));
+ assertThat(e.getCause().getMessage(),
+ containsString("No commits selected for shallow request"));
}
@Test
@@ -1374,7 +1418,8 @@ public class UploadPackTest {
}
@Test
- public void testV2FetchDeepenNot_excludeDescendantOfWant() throws Exception {
+ public void testV2FetchDeepenNot_excludeDescendantOfWant()
+ throws Exception {
RevCommit one = remote.commit().message("one").create();
RevCommit two = remote.commit().message("two").parent(one).create();
RevCommit three = remote.commit().message("three").parent(two).create();
@@ -1383,15 +1428,14 @@ public class UploadPackTest {
remote.update("two", two);
remote.update("four", four);
- thrown.expect(PackProtocolException.class);
- thrown.expectMessage("No commits selected for shallow request");
- uploadPackV2(
- "command=fetch\n",
- PacketLineIn.delimiter(),
- "deepen-not four\n",
- "want " + two.toObjectId().getName() + "\n",
- "done\n",
- PacketLineIn.end());
+ UploadPackInternalServerErrorException e = assertThrows(
+ UploadPackInternalServerErrorException.class,
+ () -> uploadPackV2("command=fetch\n", PacketLineIn.delimiter(),
+ "deepen-not four\n",
+ "want " + two.toObjectId().getName() + "\n", "done\n",
+ PacketLineIn.end()));
+ assertThat(e.getCause().getMessage(),
+ containsString("No commits selected for shallow request"));
}
@Test
@@ -1469,13 +1513,12 @@ public class UploadPackTest {
@Test
public void testV2FetchUnrecognizedArgument() throws Exception {
- thrown.expect(PackProtocolException.class);
- thrown.expectMessage("unexpected invalid-argument");
- uploadPackV2(
- "command=fetch\n",
- PacketLineIn.delimiter(),
- "invalid-argument\n",
- PacketLineIn.end());
+ UploadPackInternalServerErrorException e = assertThrows(
+ UploadPackInternalServerErrorException.class,
+ () -> uploadPackV2("command=fetch\n", PacketLineIn.delimiter(),
+ "invalid-argument\n", PacketLineIn.end()));
+ assertThat(e.getCause().getMessage(),
+ containsString("unexpected invalid-argument"));
}
@Test
@@ -1485,7 +1528,7 @@ public class UploadPackTest {
PacketLineIn.end() };
TestV2Hook testHook = new TestV2Hook();
- uploadPackV2Setup(null, null, testHook, lines);
+ uploadPackV2Setup((UploadPack up) -> {up.setProtocolV2Hook(testHook);}, lines);
FetchV2Request req = testHook.fetchRequest;
assertNotNull(req);
@@ -1569,8 +1612,9 @@ public class UploadPackTest {
input.add("done\n");
input.add(PacketLineIn.end());
ByteArrayInputStream recvStream =
- uploadPackV2(RequestPolicy.ANY, /*refFilter=*/null,
- /*hook=*/null, input.toArray(new String[0]));
+ uploadPackV2(
+ (UploadPack up) -> {up.setRequestPolicy(RequestPolicy.ANY);},
+ input.toArray(new String[0]));
PacketLineIn pckIn = new PacketLineIn(recvStream);
assertThat(pckIn.readString(), is("packfile"));
parsePack(recvStream);
@@ -1837,43 +1881,39 @@ public class UploadPackTest {
.has(preparator.subtree3.toObjectId()));
}
- @Test
- public void testV2FetchFilterWhenNotAllowed() throws Exception {
+ private void checkV2FetchWhenNotAllowed(String fetchLine, String expectedMessage)
+ throws Exception {
RevCommit commit = remote.commit().message("0").create();
remote.update("master", commit);
- server.getConfig().setBoolean("uploadpack", null, "allowfilter", false);
+ UploadPackInternalServerErrorException e = assertThrows(
+ UploadPackInternalServerErrorException.class,
+ () -> uploadPackV2("command=fetch\n", PacketLineIn.delimiter(),
+ "want " + commit.toObjectId().getName() + "\n",
+ fetchLine, "done\n", PacketLineIn.end()));
+ assertThat(e.getCause().getMessage(),
+ containsString(expectedMessage));
+ }
- thrown.expect(PackProtocolException.class);
- thrown.expectMessage("unexpected filter blob:limit=5");
- uploadPackV2(
- "command=fetch\n",
- PacketLineIn.delimiter(),
- "want " + commit.toObjectId().getName() + "\n",
+ @Test
+ public void testV2FetchFilterWhenNotAllowed() throws Exception {
+ checkV2FetchWhenNotAllowed(
"filter blob:limit=5\n",
- "done\n",
- PacketLineIn.end());
+ "unexpected filter blob:limit=5");
}
@Test
public void testV2FetchWantRefIfNotAllowed() throws Exception {
- RevCommit one = remote.commit().message("1").create();
- remote.update("one", one);
+ checkV2FetchWhenNotAllowed(
+ "want-ref refs/heads/one\n",
+ "unexpected want-ref refs/heads/one");
+ }
- try {
- uploadPackV2(
- "command=fetch\n",
- PacketLineIn.delimiter(),
- "want-ref refs/heads/one\n",
- "done\n",
- PacketLineIn.end());
- } catch (PackProtocolException e) {
- assertThat(
- e.getMessage(),
- containsString("unexpected want-ref refs/heads/one"));
- return;
- }
- fail("expected PackProtocolException");
+ @Test
+ public void testV2FetchSidebandAllIfNotAllowed() throws Exception {
+ checkV2FetchWhenNotAllowed(
+ "sideband-all\n",
+ "unexpected sideband-all");
}
@Test
@@ -1915,23 +1955,17 @@ public class UploadPackTest {
RevCommit one = remote.commit().message("1").create();
remote.update("one", one);
- server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true);
+ server.getConfig().setBoolean("uploadpack", null, "allowrefinwant",
+ true);
- try {
- uploadPackV2(
- "command=fetch\n",
- PacketLineIn.delimiter(),
- "want-ref refs/heads/one\n",
- "want-ref refs/heads/nonExistentRef\n",
- "done\n",
- PacketLineIn.end());
- } catch (PackProtocolException e) {
- assertThat(
- e.getMessage(),
+ UploadPackInternalServerErrorException e = assertThrows(
+ UploadPackInternalServerErrorException.class,
+ () -> uploadPackV2("command=fetch\n", PacketLineIn.delimiter(),
+ "want-ref refs/heads/one\n",
+ "want-ref refs/heads/nonExistentRef\n", "done\n",
+ PacketLineIn.end()));
+ assertThat(e.getCause().getMessage(),
containsString("Invalid ref name: refs/heads/nonExistentRef"));
- return;
- }
- fail("expected PackProtocolException");
}
@Test
@@ -2066,6 +2100,110 @@ public class UploadPackTest {
}
@Test
+ public void testV2FetchSidebandAllNoPackfile() throws Exception {
+ RevCommit fooParent = remote.commit().message("x").create();
+ RevCommit fooChild = remote.commit().message("x").parent(fooParent).create();
+ RevCommit barParent = remote.commit().message("y").create();
+ RevCommit barChild = remote.commit().message("y").parent(barParent).create();
+ remote.update("branch1", fooChild);
+ remote.update("branch2", barChild);
+
+ server.getConfig().setBoolean("uploadpack", null, "allowsidebandall", true);
+
+ ByteArrayInputStream recvStream = uploadPackV2(
+ "command=fetch\n",
+ PacketLineIn.DELIM,
+ "sideband-all\n",
+ "want " + fooChild.toObjectId().getName() + "\n",
+ "want " + barChild.toObjectId().getName() + "\n",
+ "have " + fooParent.toObjectId().getName() + "\n",
+ PacketLineIn.END);
+ PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+ assertThat(pckIn.readString(), is("\001acknowledgments"));
+ assertThat(pckIn.readString(), is("\001ACK " + fooParent.getName()));
+ assertTrue(PacketLineIn.isEnd(pckIn.readString()));
+ }
+
+ @Test
+ public void testV2FetchSidebandAllPackfile() throws Exception {
+ RevCommit commit = remote.commit().message("x").create();
+ remote.update("master", commit);
+
+ server.getConfig().setBoolean("uploadpack", null, "allowsidebandall", true);
+
+ ByteArrayInputStream recvStream = uploadPackV2("command=fetch\n",
+ PacketLineIn.DELIM,
+ "want " + commit.getName() + "\n",
+ "sideband-all\n",
+ "done\n",
+ PacketLineIn.END);
+ PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+ String s;
+ // When sideband-all is used, object counting happens before
+ // "packfile" is written, and object counting outputs progress
+ // in sideband 2. Skip all these lines.
+ for (s = pckIn.readString(); s.startsWith("\002"); s = pckIn.readString()) {
+ // do nothing
+ }
+ assertThat(s, is("\001packfile"));
+ parsePack(recvStream);
+ }
+
+ @Test
+ public void testV2FetchPackfileUris() throws Exception {
+ // Inside the pack
+ RevCommit commit = remote.commit().message("x").create();
+ remote.update("master", commit);
+ generateBitmaps(server);
+
+ // Outside the pack
+ RevCommit commit2 = remote.commit().message("x").parent(commit).create();
+ remote.update("master", commit2);
+
+ server.getConfig().setBoolean("uploadpack", null, "allowsidebandall", true);
+
+ ByteArrayInputStream recvStream = uploadPackV2(
+ (UploadPack up) -> {
+ up.setCachedPackUriProvider(new CachedPackUriProvider() {
+ @Override
+ public PackInfo getInfo(CachedPack pack,
+ Collection<String> protocolsSupported)
+ throws IOException {
+ assertThat(protocolsSupported, hasItems("https"));
+ if (!protocolsSupported.contains("https"))
+ return null;
+ return new PackInfo("myhash", "myuri");
+ }
+
+ });
+ },
+ "command=fetch\n",
+ PacketLineIn.DELIM,
+ "want " + commit2.getName() + "\n",
+ "sideband-all\n",
+ "packfile-uris https\n",
+ "done\n",
+ PacketLineIn.END);
+ PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+ String s;
+ // skip all \002 strings
+ for (s = pckIn.readString(); s.startsWith("\002"); s = pckIn.readString()) {
+ // do nothing
+ }
+ assertThat(s, is("\001packfile-uris"));
+ assertThat(pckIn.readString(), is("\001myhash myuri"));
+ assertTrue(PacketLineIn.isDelimiter(pckIn.readString()));
+ assertThat(pckIn.readString(), is("\001packfile"));
+ parsePack(recvStream);
+
+ assertFalse(client.getObjectDatabase().has(commit.toObjectId()));
+ assertTrue(client.getObjectDatabase().has(commit2.toObjectId()));
+ }
+
+ @Test
public void testGetPeerAgentProtocolV0() throws Exception {
RevCommit one = remote.commit().message("1").create();
remote.update("one", one);
@@ -2110,4 +2248,84 @@ public class UploadPackTest {
return new HashMap<>();
}
}
+
+ @Test
+ public void testSingleBranchCloneTagChain() throws Exception {
+ RevBlob blob0 = remote.blob("Initial content of first file");
+ RevBlob blob1 = remote.blob("Second file content");
+ RevCommit commit0 = remote
+ .commit(remote.tree(remote.file("prvni.txt", blob0)));
+ RevCommit commit1 = remote
+ .commit(remote.tree(remote.file("druhy.txt", blob1)), commit0);
+ remote.update("master", commit1);
+
+ RevTag heavyTag1 = remote.tag("commitTagRing", commit0);
+ remote.getRevWalk().parseHeaders(heavyTag1);
+ RevTag heavyTag2 = remote.tag("middleTagRing", heavyTag1);
+ remote.lightweightTag("refTagRing", heavyTag2);
+
+ UploadPack uploadPack = new UploadPack(remote.getRepository());
+
+ ByteArrayOutputStream cli = new ByteArrayOutputStream();
+ PacketLineOut clientWant = new PacketLineOut(cli);
+ clientWant.writeString("want " + commit1.name()
+ + " multi_ack_detailed include-tag thin-pack ofs-delta agent=tempo/pflaska");
+ clientWant.end();
+ clientWant.writeString("done\n");
+
+ try (ByteArrayOutputStream serverResponse = new ByteArrayOutputStream()) {
+
+ uploadPack.setPreUploadHook(new PreUploadHook() {
+ @Override
+ public void onBeginNegotiateRound(UploadPack up,
+ Collection<? extends ObjectId> wants, int cntOffered)
+ throws ServiceMayNotContinueException {
+ // Do nothing.
+ }
+
+ @Override
+ public void onEndNegotiateRound(UploadPack up,
+ Collection<? extends ObjectId> wants, int cntCommon,
+ int cntNotFound, boolean ready)
+ throws ServiceMayNotContinueException {
+ // Do nothing.
+ }
+
+ @Override
+ public void onSendPack(UploadPack up,
+ Collection<? extends ObjectId> wants,
+ Collection<? extends ObjectId> haves)
+ throws ServiceMayNotContinueException {
+ // collect pack data
+ serverResponse.reset();
+ }
+ });
+ uploadPack.upload(new ByteArrayInputStream(cli.toByteArray()),
+ serverResponse, System.err);
+ InputStream packReceived = new ByteArrayInputStream(
+ serverResponse.toByteArray());
+ PackLock lock = null;
+ try (ObjectInserter ins = client.newObjectInserter()) {
+ PackParser parser = ins.newPackParser(packReceived);
+ parser.setAllowThin(true);
+ parser.setLockMessage("receive-tag-chain");
+ ProgressMonitor mlc = NullProgressMonitor.INSTANCE;
+ lock = parser.parse(mlc, mlc);
+ ins.flush();
+ } finally {
+ if (lock != null) {
+ lock.unlock();
+ }
+ }
+ InMemoryRepository.MemObjDatabase objDb = client
+ .getObjectDatabase();
+ assertTrue(objDb.has(blob0.toObjectId()));
+ assertTrue(objDb.has(blob1.toObjectId()));
+ assertTrue(objDb.has(commit0.toObjectId()));
+ assertTrue(objDb.has(commit1.toObjectId()));
+ assertTrue(objDb.has(heavyTag1.toObjectId()));
+ assertTrue(objDb.has(heavyTag2.toObjectId()));
+ }
+ }
+
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FS_POSIXTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FS_POSIXTest.java
index 87349a25a4..d7a7d86775 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FS_POSIXTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FS_POSIXTest.java
@@ -59,7 +59,7 @@ import org.junit.Before;
import org.junit.Test;
public class FS_POSIXTest {
- private SystemReader originalSystemReaderInstance;
+ private FileBasedConfig jgitConfig;
private FileBasedConfig systemConfig;
@@ -70,6 +70,7 @@ public class FS_POSIXTest {
@Before
public void setUp() throws Exception {
tmp = Files.createTempDirectory("jgit_test_");
+
MockSystemReader mockSystemReader = new MockSystemReader();
SystemReader.setInstance(mockSystemReader);
@@ -78,7 +79,10 @@ public class FS_POSIXTest {
// The MockSystemReader must be configured first since we need to use
// the same one here
FS.getFileStoreAttributes(tmp.getParent());
- systemConfig = new FileBasedConfig(
+
+ jgitConfig = new FileBasedConfig(new File(tmp.toFile(), "jgitconfig"),
+ FS.DETECTED);
+ systemConfig = new FileBasedConfig(jgitConfig,
new File(tmp.toFile(), "systemgitconfig"), FS.DETECTED);
userConfig = new FileBasedConfig(systemConfig,
new File(tmp.toFile(), "usergitconfig"), FS.DETECTED);
@@ -89,16 +93,14 @@ public class FS_POSIXTest {
userConfig.setBoolean(ConfigConstants.CONFIG_GC_SECTION, null,
ConfigConstants.CONFIG_KEY_AUTODETACH, false);
userConfig.save();
+ mockSystemReader.setJGitConfig(jgitConfig);
mockSystemReader.setSystemGitConfig(systemConfig);
mockSystemReader.setUserGitConfig(userConfig);
-
- originalSystemReaderInstance = SystemReader.getInstance();
- SystemReader.setInstance(mockSystemReader);
}
@After
public void tearDown() throws IOException {
- SystemReader.setInstance(originalSystemReaderInstance);
+ SystemReader.setInstance(null);
FileUtils.delete(tmp.toFile(), FileUtils.RECURSIVE | FileUtils.RETRY);
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitDateFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitDateFormatterTest.java
index d52166f2ba..59ff2adcdd 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitDateFormatterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitDateFormatterTest.java
@@ -44,6 +44,7 @@
package org.eclipse.jgit.util;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import org.eclipse.jgit.junit.MockSystemReader;
import org.eclipse.jgit.lib.PersonIdent;
@@ -120,13 +121,16 @@ public class GitDateFormatterTest {
@Test
public void LOCALE() {
- assertEquals("Sep 20, 2011 7:09:25 PM -0400", new GitDateFormatter(
- Format.LOCALE).formatDate(ident));
+ String date = new GitDateFormatter(Format.LOCALE).formatDate(ident);
+ assertTrue("Sep 20, 2011 7:09:25 PM -0400".equals(date)
+ || "Sep 20, 2011, 7:09:25 PM -0400".equals(date)); // JDK-8206961
}
@Test
public void LOCALELOCAL() {
- assertEquals("Sep 20, 2011 7:39:25 PM", new GitDateFormatter(
- Format.LOCALELOCAL).formatDate(ident));
+ String date = new GitDateFormatter(Format.LOCALELOCAL)
+ .formatDate(ident);
+ assertTrue("Sep 20, 2011 7:39:25 PM".equals(date)
+ || "Sep 20, 2011, 7:39:25 PM".equals(date)); // JDK-8206961
}
}