diff options
Diffstat (limited to 'org.eclipse.jgit.test')
31 files changed, 1409 insertions, 238 deletions
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF index ca557df032..e0ad0b43d1 100644 --- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF @@ -3,58 +3,58 @@ Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Automatic-Module-Name: org.eclipse.jgit.test Bundle-SymbolicName: org.eclipse.jgit.test -Bundle-Version: 5.0.3.qualifier +Bundle-Version: 5.1.0.qualifier Bundle-Localization: plugin Bundle-Vendor: %provider_name Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)", com.jcraft.jsch;version="[0.1.54,0.2.0)", - org.eclipse.jgit.api;version="[5.0.3,5.1.0)", - org.eclipse.jgit.api.errors;version="[5.0.3,5.1.0)", - org.eclipse.jgit.attributes;version="[5.0.3,5.1.0)", - org.eclipse.jgit.awtui;version="[5.0.3,5.1.0)", - org.eclipse.jgit.blame;version="[5.0.3,5.1.0)", - org.eclipse.jgit.diff;version="[5.0.3,5.1.0)", - org.eclipse.jgit.dircache;version="[5.0.3,5.1.0)", - org.eclipse.jgit.errors;version="[5.0.3,5.1.0)", - org.eclipse.jgit.events;version="[5.0.3,5.1.0)", - org.eclipse.jgit.fnmatch;version="[5.0.3,5.1.0)", - org.eclipse.jgit.gitrepo;version="[5.0.3,5.1.0)", - org.eclipse.jgit.hooks;version="[5.0.3,5.1.0)", - org.eclipse.jgit.ignore;version="[5.0.3,5.1.0)", - org.eclipse.jgit.ignore.internal;version="[5.0.3,5.1.0)", - org.eclipse.jgit.internal;version="[5.0.3,5.1.0)", - org.eclipse.jgit.internal.fsck;version="[5.0.3,5.1.0)", - org.eclipse.jgit.internal.storage.dfs;version="[5.0.3,5.1.0)", - org.eclipse.jgit.internal.storage.file;version="[5.0.3,5.1.0)", - org.eclipse.jgit.internal.storage.io;version="[5.0.3,5.1.0)", - org.eclipse.jgit.internal.storage.pack;version="[5.0.3,5.1.0)", - org.eclipse.jgit.internal.storage.reftable;version="[5.0.3,5.1.0)", - org.eclipse.jgit.internal.storage.reftree;version="[5.0.3,5.1.0)", - org.eclipse.jgit.junit;version="[5.0.3,5.1.0)", - org.eclipse.jgit.lfs;version="[5.0.3,5.1.0)", - org.eclipse.jgit.lib;version="[5.0.3,5.1.0)", - org.eclipse.jgit.merge;version="[5.0.3,5.1.0)", - org.eclipse.jgit.nls;version="[5.0.3,5.1.0)", - org.eclipse.jgit.notes;version="[5.0.3,5.1.0)", - org.eclipse.jgit.patch;version="[5.0.3,5.1.0)", - org.eclipse.jgit.pgm;version="[5.0.3,5.1.0)", - org.eclipse.jgit.pgm.internal;version="[5.0.3,5.1.0)", - org.eclipse.jgit.revplot;version="[5.0.3,5.1.0)", - org.eclipse.jgit.revwalk;version="[5.0.3,5.1.0)", - org.eclipse.jgit.revwalk.filter;version="[5.0.3,5.1.0)", - org.eclipse.jgit.storage.file;version="[5.0.3,5.1.0)", - org.eclipse.jgit.storage.pack;version="[5.0.3,5.1.0)", - org.eclipse.jgit.submodule;version="[5.0.3,5.1.0)", - org.eclipse.jgit.transport;version="[5.0.3,5.1.0)", - org.eclipse.jgit.transport.http;version="[5.0.3,5.1.0)", - org.eclipse.jgit.transport.resolver;version="[5.0.3,5.1.0)", - org.eclipse.jgit.treewalk;version="[5.0.3,5.1.0)", - org.eclipse.jgit.treewalk.filter;version="[5.0.3,5.1.0)", - org.eclipse.jgit.util;version="[5.0.3,5.1.0)", - org.eclipse.jgit.util.io;version="[5.0.3,5.1.0)", - org.eclipse.jgit.util.sha1;version="[5.0.3,5.1.0)", + org.eclipse.jgit.api;version="[5.1.0,5.2.0)", + org.eclipse.jgit.api.errors;version="[5.1.0,5.2.0)", + org.eclipse.jgit.attributes;version="[5.1.0,5.2.0)", + org.eclipse.jgit.awtui;version="[5.1.0,5.2.0)", + org.eclipse.jgit.blame;version="[5.1.0,5.2.0)", + org.eclipse.jgit.diff;version="[5.1.0,5.2.0)", + org.eclipse.jgit.dircache;version="[5.1.0,5.2.0)", + org.eclipse.jgit.errors;version="[5.1.0,5.2.0)", + org.eclipse.jgit.events;version="[5.1.0,5.2.0)", + org.eclipse.jgit.fnmatch;version="[5.1.0,5.2.0)", + org.eclipse.jgit.gitrepo;version="[5.1.0,5.2.0)", + org.eclipse.jgit.hooks;version="[5.1.0,5.2.0)", + org.eclipse.jgit.ignore;version="[5.1.0,5.2.0)", + org.eclipse.jgit.ignore.internal;version="[5.1.0,5.2.0)", + org.eclipse.jgit.internal;version="[5.1.0,5.2.0)", + org.eclipse.jgit.internal.fsck;version="[5.1.0,5.2.0)", + org.eclipse.jgit.internal.storage.dfs;version="[5.1.0,5.2.0)", + org.eclipse.jgit.internal.storage.file;version="[5.1.0,5.2.0)", + org.eclipse.jgit.internal.storage.io;version="[5.1.0,5.2.0)", + org.eclipse.jgit.internal.storage.pack;version="[5.1.0,5.2.0)", + org.eclipse.jgit.internal.storage.reftable;version="[5.1.0,5.2.0)", + org.eclipse.jgit.internal.storage.reftree;version="[5.1.0,5.2.0)", + org.eclipse.jgit.junit;version="[5.1.0,5.2.0)", + org.eclipse.jgit.lfs;version="[5.1.0,5.2.0)", + org.eclipse.jgit.lib;version="[5.1.0,5.2.0)", + org.eclipse.jgit.merge;version="[5.1.0,5.2.0)", + org.eclipse.jgit.nls;version="[5.1.0,5.2.0)", + org.eclipse.jgit.notes;version="[5.1.0,5.2.0)", + org.eclipse.jgit.patch;version="[5.1.0,5.2.0)", + org.eclipse.jgit.pgm;version="[5.1.0,5.2.0)", + org.eclipse.jgit.pgm.internal;version="[5.1.0,5.2.0)", + org.eclipse.jgit.revplot;version="[5.1.0,5.2.0)", + org.eclipse.jgit.revwalk;version="[5.1.0,5.2.0)", + org.eclipse.jgit.revwalk.filter;version="[5.1.0,5.2.0)", + org.eclipse.jgit.storage.file;version="[5.1.0,5.2.0)", + org.eclipse.jgit.storage.pack;version="[5.1.0,5.2.0)", + org.eclipse.jgit.submodule;version="[5.1.0,5.2.0)", + org.eclipse.jgit.transport;version="[5.1.0,5.2.0)", + org.eclipse.jgit.transport.http;version="[5.1.0,5.2.0)", + org.eclipse.jgit.transport.resolver;version="[5.1.0,5.2.0)", + org.eclipse.jgit.treewalk;version="[5.1.0,5.2.0)", + org.eclipse.jgit.treewalk.filter;version="[5.1.0,5.2.0)", + org.eclipse.jgit.util;version="[5.1.0,5.2.0)", + org.eclipse.jgit.util.io;version="[5.1.0,5.2.0)", + org.eclipse.jgit.util.sha1;version="[5.1.0,5.2.0)", org.junit;version="[4.12,5.0.0)", org.junit.experimental.theories;version="[4.12,5.0.0)", org.junit.rules;version="[4.12,5.0.0)", diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml index f6ad0cee4c..017db3df6c 100644 --- a/org.eclipse.jgit.test/pom.xml +++ b/org.eclipse.jgit.test/pom.xml @@ -52,7 +52,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>5.0.3-SNAPSHOT</version> + <version>5.1.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.test</artifactId> @@ -157,7 +157,7 @@ <plugin> <artifactId>maven-surefire-plugin</artifactId> <configuration> - <argLine>-Xmx256m -Dfile.encoding=UTF-8 -Djava.io.tmpdir=${project.build.directory}</argLine> + <argLine>-Xmx1024m -Dfile.encoding=UTF-8 -Djava.io.tmpdir=${project.build.directory}</argLine> <includes> <include>**/*Test.java</include> <include>**/*Tests.java</include> diff --git a/org.eclipse.jgit.test/src/org/eclipse/jgit/events/ChangeRecorder.java b/org.eclipse.jgit.test/src/org/eclipse/jgit/events/ChangeRecorder.java index c5582a8601..228df35c76 100644 --- a/org.eclipse.jgit.test/src/org/eclipse/jgit/events/ChangeRecorder.java +++ b/org.eclipse.jgit.test/src/org/eclipse/jgit/events/ChangeRecorder.java @@ -74,11 +74,11 @@ public class ChangeRecorder implements WorkingTreeModifiedListener { } private String[] getModified() { - return modified.toArray(new String[modified.size()]); + return modified.toArray(new String[0]); } private String[] getDeleted() { - return deleted.toArray(new String[deleted.size()]); + return deleted.toArray(new String[0]); } private void reset() { diff --git a/org.eclipse.jgit.test/tests.bzl b/org.eclipse.jgit.test/tests.bzl index b1b7b7a9de..64dfe071cf 100644 --- a/org.eclipse.jgit.test/tests.bzl +++ b/org.eclipse.jgit.test/tests.bzl @@ -42,6 +42,10 @@ def tests(tests): '//lib:jsch', ] + heap_size = "-Xmx256m" + if src.endswith("HugeCommitMessageTest.java"): + heap_size = "-Xmx512m" + junit_tests( name = name, tags = labels, @@ -57,5 +61,5 @@ def tests(tests): '//org.eclipse.jgit.lfs:jgit-lfs', ], flaky = flaky, - jvm_flags = ["-Xmx256m", "-Dfile.encoding=UTF-8"], + jvm_flags = [heap_size, "-Dfile.encoding=UTF-8"], ) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java index 1af37e25f5..ca86d81301 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java @@ -245,7 +245,7 @@ public class PushCommandTest extends RepositoryTestCase { git.add().addFilepattern("f" + i).call(); commit = git.commit().setMessage("adding f" + i).call(); git.push().setRemote("test").call(); - git2.getRepository().getAllRefs(); + git2.getRepository().getRefDatabase().getRefs(); assertEquals("failed to update on attempt " + i, commit.getId(), git2.getRepository().resolve("refs/heads/test")); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java index 96e7091ae1..621e061c79 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java @@ -57,9 +57,12 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; import org.eclipse.jgit.api.MergeResult.MergeStatus; import org.eclipse.jgit.api.RebaseCommand.InteractiveHandler; @@ -75,6 +78,7 @@ import org.eclipse.jgit.errors.AmbiguousObjectException; import org.eclipse.jgit.errors.IllegalTodoFileModification; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.events.ListenerHandle; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.AbbreviatedObjectId; import org.eclipse.jgit.lib.ConfigConstants; @@ -1981,6 +1985,62 @@ public class RebaseCommandTest extends RepositoryTestCase { } @Test + public void testRebaseWithAutoStashAndSubdirs() throws Exception { + // create file0, add and commit + db.getConfig().setBoolean(ConfigConstants.CONFIG_REBASE_SECTION, null, + ConfigConstants.CONFIG_KEY_AUTOSTASH, true); + writeTrashFile("sub/file0", "file0"); + git.add().addFilepattern("sub/file0").call(); + git.commit().setMessage("commit0").call(); + // create file1, add and commit + writeTrashFile(FILE1, "file1"); + git.add().addFilepattern(FILE1).call(); + RevCommit commit = git.commit().setMessage("commit1").call(); + + // create topic branch and checkout / create file2, add and commit + createBranch(commit, "refs/heads/topic"); + checkoutBranch("refs/heads/topic"); + writeTrashFile("file2", "file2"); + git.add().addFilepattern("file2").call(); + git.commit().setMessage("commit2").call(); + + // checkout master branch / modify file1, add and commit + checkoutBranch("refs/heads/master"); + writeTrashFile(FILE1, "modified file1"); + git.add().addFilepattern(FILE1).call(); + git.commit().setMessage("commit3").call(); + + // checkout topic branch / modify file0 + checkoutBranch("refs/heads/topic"); + writeTrashFile("sub/file0", "unstaged modified file0"); + + Set<String> modifiedFiles = new HashSet<>(); + ListenerHandle handle = db.getListenerList() + .addWorkingTreeModifiedListener( + event -> modifiedFiles.addAll(event.getModified())); + try { + // rebase + assertEquals(Status.OK, git.rebase() + .setUpstream("refs/heads/master").call().getStatus()); + } finally { + handle.remove(); + } + checkFile(new File(new File(db.getWorkTree(), "sub"), "file0"), + "unstaged modified file0"); + checkFile(new File(db.getWorkTree(), FILE1), "modified file1"); + checkFile(new File(db.getWorkTree(), "file2"), "file2"); + assertEquals( + "[file1, mode:100644, content:modified file1]" + + "[file2, mode:100644, content:file2]" + + "[sub/file0, mode:100644, content:file0]", + indexState(CONTENT)); + assertEquals(RepositoryState.SAFE, db.getRepositoryState()); + List<String> modified = new ArrayList<>(modifiedFiles); + Collections.sort(modified); + assertEquals("[file1, sub/file0]", modified.toString()); + } + + @Test public void testRebaseWithAutoStashConflictOnApply() throws Exception { // create file0, add and commit db.getConfig().setBoolean(ConfigConstants.CONFIG_REBASE_SECTION, null, diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ReflogCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ReflogCommandTest.java index b07c7033f5..8922837139 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ReflogCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ReflogCommandTest.java @@ -89,7 +89,7 @@ public class ReflogCommandTest extends RepositoryTestCase { Collection<ReflogEntry> reflog = git.reflog().call(); assertNotNull(reflog); assertEquals(3, reflog.size()); - ReflogEntry[] reflogs = reflog.toArray(new ReflogEntry[reflog.size()]); + ReflogEntry[] reflogs = reflog.toArray(new ReflogEntry[0]); assertEquals(reflogs[2].getComment(), "commit (initial): Initial commit"); assertEquals(reflogs[2].getNewId(), commit1.getId()); @@ -114,7 +114,7 @@ public class ReflogCommandTest extends RepositoryTestCase { .setRef(Constants.R_HEADS + "b1").call(); assertNotNull(reflog); assertEquals(2, reflog.size()); - ReflogEntry[] reflogs = reflog.toArray(new ReflogEntry[reflog.size()]); + ReflogEntry[] reflogs = reflog.toArray(new ReflogEntry[0]); assertEquals(reflogs[0].getComment(), "commit: Removed file"); assertEquals(reflogs[0].getNewId(), commit2.getId()); assertEquals(reflogs[0].getOldId(), commit1.getId()); @@ -136,7 +136,7 @@ public class ReflogCommandTest extends RepositoryTestCase { Collection<ReflogEntry> reflog = git.reflog().call(); assertNotNull(reflog); assertEquals(4, reflog.size()); - ReflogEntry[] reflogs = reflog.toArray(new ReflogEntry[reflog.size()]); + ReflogEntry[] reflogs = reflog.toArray(new ReflogEntry[0]); assertEquals(reflogs[3].getComment(), "commit (initial): Initial commit"); assertEquals(reflogs[3].getNewId(), commit1.getId()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashApplyCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashApplyCommandTest.java index ad3ab7fbdf..fa6c9609f5 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashApplyCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashApplyCommandTest.java @@ -234,7 +234,7 @@ public class StashApplyCommandTest extends RepositoryTestCase { ObjectId unstashed = git.stashApply().call(); assertEquals(stashed, unstashed); assertEquals("content2", read(subfolderFile)); - recorder.assertEvent(new String[] { "d1/d2/f.txt", "d1/d2", "d1" }, + recorder.assertEvent(new String[] { "d1/d2/f.txt" }, ChangeRecorder.EMPTY); Status status = git.status().call(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java index 69a48cc4b5..024f054807 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java @@ -43,6 +43,7 @@ package org.eclipse.jgit.gitrepo; import static org.eclipse.jgit.lib.Constants.CHARSET; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -51,6 +52,8 @@ import java.io.IOException; import java.net.URI; import java.util.HashSet; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.junit.Test; import org.xml.sax.SAXException; @@ -145,6 +148,29 @@ public class ManifestParserTest { } } + @Test + public void testRemoveProject() throws Exception { + StringBuilder xmlContent = new StringBuilder(); + xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + .append("<manifest>") + .append("<remote name=\"remote1\" fetch=\".\" />") + .append("<default revision=\"master\" remote=\"remote1\" />") + .append("<project path=\"foo\" name=\"foo\" />") + .append("<project path=\"bar\" name=\"bar\" />") + .append("<remove-project name=\"foo\" />") + .append("<project path=\"foo\" name=\"baz\" />") + .append("</manifest>"); + + ManifestParser parser = new ManifestParser(null, null, "master", + "https://git.google.com/", null, null); + parser.read(new ByteArrayInputStream( + xmlContent.toString().getBytes(CHARSET))); + + assertEquals(Stream.of("bar", "baz").collect(Collectors.toSet()), + parser.getProjects().stream().map(RepoProject::getName) + .collect(Collectors.toSet())); + } + void testNormalize(String in, String want) { URI got = ManifestParser.normalizeEmptyPath(URI.create(in)); if (!got.toString().equals(want)) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java index df31ab0869..1eca587bfb 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java @@ -268,7 +268,8 @@ public class RepoCommandTest extends RepositoryTestCase { .getCachedBytes(Integer.MAX_VALUE); Config base = new Config(); BlobBasedConfig cfg = new BlobBasedConfig(base, bytes); - String subUrl = cfg.getString("submodule", "base", "url"); + String subUrl = cfg.getString("submodule", "platform/base", + "url"); assertEquals(subUrl, "../base"); } } @@ -301,7 +302,8 @@ public class RepoCommandTest extends RepositoryTestCase { .getCachedBytes(Integer.MAX_VALUE); Config base = new Config(); BlobBasedConfig cfg = new BlobBasedConfig(base, bytes); - String subUrl = cfg.getString("submodule", "base", "url"); + String subUrl = cfg.getString("submodule", "platform/base", + "url"); assertEquals(subUrl, "https://host.com/platform/base"); } } @@ -387,8 +389,8 @@ public class RepoCommandTest extends RepositoryTestCase { .getCachedBytes(Integer.MAX_VALUE); Config base = new Config(); BlobBasedConfig cfg = new BlobBasedConfig(base, bytes); - String subUrl = cfg.getString("submodule", "src", - "url"); + String subUrl = cfg.getString("submodule", + "chromium/src", "url"); assertEquals( "https://chromium.googlesource.com/chromium/src", subUrl); @@ -443,8 +445,8 @@ public class RepoCommandTest extends RepositoryTestCase { .getCachedBytes(Integer.MAX_VALUE); Config base = new Config(); BlobBasedConfig cfg = new BlobBasedConfig(base, bytes); - String subUrl = cfg.getString("submodule", "src", - "url"); + String subUrl = cfg.getString("submodule", + "chromium/src", "url"); assertEquals("../chromium/src", subUrl); } fetchSlash = !fetchSlash; @@ -613,7 +615,7 @@ public class RepoCommandTest extends RepositoryTestCase { String content = reader.readLine(); assertEquals( "The first line of .gitmodules file should be as expected", - "[submodule \"foo\"]", content); + "[submodule \"" + defaultUri + "\"]", content); } // The gitlink should be the same as remote head sha1 String gitlink = localDb.resolve(Constants.HEAD + ":foo").name(); @@ -801,9 +803,9 @@ public class RepoCommandTest extends RepositoryTestCase { .append("<manifest>") .append("<remote name=\"remote1\" fetch=\".\" />") .append("<default revision=\"master\" remote=\"remote1\" />") - .append("<project path=\"bar\" name=\"").append(defaultUri) - .append("\" revision=\"").append(BRANCH).append("\" >") - .append("<copyfile src=\"hello.txt\" dest=\"Hello.txt\" />") + .append("<project path=\"bar\" name=\"").append(notDefaultUri) + .append("\" >") + .append("<copyfile src=\"world.txt\" dest=\"World.txt\" />") .append("</project>").append("</manifest>"); JGitTestUtil.writeTrashFile(tempDb, "new.xml", xmlContent.toString()); command = new RepoCommand(remoteDb); @@ -819,8 +821,8 @@ public class RepoCommandTest extends RepositoryTestCase { File hello = new File(localDb.getWorkTree(), "Hello"); assertFalse("The Hello file shouldn't exist", hello.exists()); // The Hello.txt file should exist - File hellotxt = new File(localDb.getWorkTree(), "Hello.txt"); - assertTrue("The Hello.txt file should exist", hellotxt.exists()); + File hellotxt = new File(localDb.getWorkTree(), "World.txt"); + assertTrue("The World.txt file should exist", hellotxt.exists()); dotmodules = new File(localDb.getWorkTree(), Constants.DOT_GIT_MODULES); } @@ -835,9 +837,9 @@ public class RepoCommandTest extends RepositoryTestCase { String line = reader.readLine(); if (line == null) break; - if (line.contains("submodule \"foo\"")) + if (line.contains("submodule \"" + defaultUri + "\"")) foo = true; - if (line.contains("submodule \"bar\"")) + if (line.contains("submodule \"" + notDefaultUri + "\"")) bar = true; } assertTrue("The bar submodule should exist", bar); @@ -876,9 +878,7 @@ public class RepoCommandTest extends RepositoryTestCase { Constants.DOT_GIT_MODULES); } - // The .gitmodules file should have 'submodule "foo"' and shouldn't - // have - // 'submodule "foo/bar"' lines. + // Check .gitmodules file try (BufferedReader reader = new BufferedReader( new FileReader(dotmodules))) { boolean foo = false; @@ -888,16 +888,17 @@ public class RepoCommandTest extends RepositoryTestCase { String line = reader.readLine(); if (line == null) break; - if (line.contains("submodule \"foo\"")) + if (line.contains("submodule \"" + defaultUri + "\"")) foo = true; - if (line.contains("submodule \"foo/bar\"")) + if (line.contains("submodule \"" + groupBUri + "\"")) foobar = true; - if (line.contains("submodule \"a\"")) + if (line.contains("submodule \"" + groupAUri + "\"")) a = true; } - assertTrue("The foo submodule should exist", foo); - assertFalse("The foo/bar submodule shouldn't exist", foobar); - assertTrue("The a submodule should exist", a); + assertTrue("The " + defaultUri + " submodule should exist", foo); + assertFalse("The " + groupBUri + " submodule shouldn't exist", + foobar); + assertTrue("The " + groupAUri + " submodule should exist", a); } } @@ -1033,11 +1034,11 @@ public class RepoCommandTest extends RepositoryTestCase { assertEquals( "Recording remote branches should work for short branch descriptions", "master", - c.getString("submodule", "with-branch", "branch")); + c.getString("submodule", notDefaultUri, "branch")); assertEquals( "Recording remote branches should work for full ref specs", "refs/heads/master", - c.getString("submodule", "with-long-branch", "branch")); + c.getString("submodule", defaultUri, "branch")); } } @@ -1095,7 +1096,7 @@ public class RepoCommandTest extends RepositoryTestCase { .append("<project path=\"shallow-please\" ").append("name=\"") .append(defaultUri).append("\" ").append("clone-depth=\"1\" />") .append("<project path=\"non-shallow\" ").append("name=\"") - .append(defaultUri).append("\" />").append("</manifest>"); + .append(notDefaultUri).append("\" />").append("</manifest>"); JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", xmlContent.toString()); @@ -1115,9 +1116,9 @@ public class RepoCommandTest extends RepositoryTestCase { FileBasedConfig c = new FileBasedConfig(gitmodules, FS.DETECTED); c.load(); assertEquals("Recording shallow configuration should work", "true", - c.getString("submodule", "shallow-please", "shallow")); + c.getString("submodule", defaultUri, "shallow")); assertNull("Recording non shallow configuration should work", - c.getString("submodule", "non-shallow", "shallow")); + c.getString("submodule", notDefaultUri, "shallow")); } } @@ -1176,6 +1177,43 @@ public class RepoCommandTest extends RepositoryTestCase { } } + @Test + public void testTwoPathUseTheSameName() throws Exception { + Repository remoteDb = createBareRepository(); + Repository tempDb = createWorkRepository(); + + StringBuilder xmlContent = new StringBuilder(); + xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + .append("<manifest>") + .append("<remote name=\"remote1\" fetch=\".\" />") + .append("<default revision=\"master\" remote=\"remote1\" />") + .append("<project path=\"path1\" ").append("name=\"") + .append(defaultUri).append("\" />") + .append("<project path=\"path2\" ").append("name=\"") + .append(defaultUri).append("\" />").append("</manifest>"); + JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", + xmlContent.toString()); + + RepoCommand command = new RepoCommand(remoteDb); + command.setPath( + tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") + .setURI(rootUri).setRecommendShallow(true).call(); + File directory = createTempDirectory("testBareRepo"); + try (Repository localDb = Git.cloneRepository().setDirectory(directory) + .setURI(remoteDb.getDirectory().toURI().toString()).call() + .getRepository();) { + File gitmodules = new File(localDb.getWorkTree(), ".gitmodules"); + assertTrue("The .gitmodules file should exist", + gitmodules.exists()); + FileBasedConfig c = new FileBasedConfig(gitmodules, FS.DETECTED); + c.load(); + assertEquals("A module should exist for path1", "path1", + c.getString("submodule", defaultUri + "/path1", "path")); + assertEquals("A module should exist for path2", "path2", + c.getString("submodule", defaultUri + "/path2", "path")); + } + } + private void resolveRelativeUris() { // Find the longest common prefix ends with "/" as rootUri. defaultUri = defaultDb.getDirectory().toURI().toString(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java index 5b567d00f7..bfa30d5b4b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java @@ -972,7 +972,7 @@ public class DfsGarbageCollectorTest { private static boolean isReachable(Repository repo, AnyObjectId id) throws IOException { try (RevWalk rw = new RevWalk(repo)) { - for (Ref ref : repo.getAllRefs().values()) { + for (Ref ref : repo.getRefDatabase().getRefs()) { rw.markStart(rw.parseCommit(ref.getObjectId())); } for (RevCommit next; (next = rw.next()) != null;) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackDescriptionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackDescriptionTest.java new file mode 100644 index 0000000000..55e1a9c4cc --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackDescriptionTest.java @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2018, 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.internal.storage.dfs; + +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.COMPACT; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC_REST; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC_TXN; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.INSERT; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.RECEIVE; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.UNREACHABLE_GARBAGE; +import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; +import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; +import static org.junit.Assert.assertEquals; + +import java.util.Comparator; +import java.util.concurrent.atomic.AtomicInteger; + +import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource; +import org.junit.Before; +import org.junit.Test; + +public final class DfsPackDescriptionTest { + private AtomicInteger counter; + + @Before + public void setUp() { + counter = new AtomicInteger(); + } + + @Test + public void objectLookupComparatorEqual() throws Exception { + DfsPackDescription a = create(RECEIVE); + a.setFileSize(PACK, 1); + a.setFileSize(INDEX, 1); + a.setLastModified(1); + a.setObjectCount(1); + a.setMaxUpdateIndex(1); + + DfsPackDescription b = create(INSERT); + b.setFileSize(PACK, 1); + b.setFileSize(INDEX, 2); + b.setLastModified(1); + b.setObjectCount(1); + b.setMaxUpdateIndex(2); + + assertComparesEqual(DfsPackDescription.objectLookupComparator(), a, b); + } + + @Test + public void objectLookupComparatorPackSource() throws Exception { + DfsPackDescription a = create(COMPACT); + a.setFileSize(PACK, 2); + a.setLastModified(1); + a.setObjectCount(2); + + DfsPackDescription b = create(GC); + b.setFileSize(PACK, 1); + b.setLastModified(2); + b.setObjectCount(1); + + assertComparesLessThan(DfsPackDescription.objectLookupComparator(), a, b); + } + + @Test + public void objectLookupComparatorCustomPackSourceComparator() + throws Exception { + DfsPackDescription a = create(GC); + + DfsPackDescription b = create(COMPACT); + + assertComparesLessThan(DfsPackDescription.objectLookupComparator(), b, a); + assertComparesLessThan( + DfsPackDescription.objectLookupComparator( + new PackSource.ComparatorBuilder() + .add(GC) + .add(INSERT, RECEIVE, GC_REST, GC_TXN, UNREACHABLE_GARBAGE) + .add(COMPACT) + .build()), + a, b); + } + + @Test + public void objectLookupComparatorGcFileSize() throws Exception { + // a is older and smaller. + DfsPackDescription a = create(GC_REST); + a.setFileSize(PACK, 100); + a.setLastModified(1); + a.setObjectCount(2); + + // b is newer and larger. + DfsPackDescription b = create(GC_REST); + b.setFileSize(PACK, 200); + b.setLastModified(2); + b.setObjectCount(1); + + // Since they have the same GC type, tiebreaker is size, and a comes first. + assertComparesLessThan(DfsPackDescription.objectLookupComparator(), a, b); + } + + @Test + public void objectLookupComparatorNonGcLastModified() + throws Exception { + // a is older and smaller. + DfsPackDescription a = create(INSERT); + a.setFileSize(PACK, 100); + a.setLastModified(1); + a.setObjectCount(2); + + // b is newer and larger. + DfsPackDescription b = create(INSERT); + b.setFileSize(PACK, 200); + b.setLastModified(2); + b.setObjectCount(1); + + // Since they have the same type but not GC, tiebreaker is last modified, + // and b comes first. + assertComparesLessThan(DfsPackDescription.objectLookupComparator(), b, a); + } + + @Test + public void objectLookupComparatorObjectCount() throws Exception { + DfsPackDescription a = create(INSERT); + a.setObjectCount(1); + + DfsPackDescription b = create(INSERT); + b.setObjectCount(2); + + assertComparesLessThan(DfsPackDescription.objectLookupComparator(), a, b); + } + + @Test + public void reftableComparatorEqual() throws Exception { + DfsPackDescription a = create(INSERT); + a.setFileSize(PACK, 100); + a.setObjectCount(1); + + DfsPackDescription b = create(INSERT); + b.setFileSize(PACK, 200); + a.setObjectCount(2); + + assertComparesEqual(DfsPackDescription.reftableComparator(), a, b); + } + + @Test + public void reftableComparatorPackSource() throws Exception { + DfsPackDescription a = create(INSERT); + a.setMaxUpdateIndex(1); + a.setLastModified(1); + + DfsPackDescription b = create(GC); + b.setMaxUpdateIndex(2); + b.setLastModified(2); + + assertComparesLessThan(DfsPackDescription.reftableComparator(), b, a); + } + + @Test + public void reftableComparatorMaxUpdateIndex() throws Exception { + DfsPackDescription a = create(INSERT); + a.setMaxUpdateIndex(1); + a.setLastModified(2); + + DfsPackDescription b = create(INSERT); + b.setMaxUpdateIndex(2); + b.setLastModified(1); + + assertComparesLessThan(DfsPackDescription.reftableComparator(), a, b); + } + + @Test + public void reftableComparatorLastModified() throws Exception { + DfsPackDescription a = create(INSERT); + a.setLastModified(1); + + DfsPackDescription b = create(INSERT); + b.setLastModified(2); + + assertComparesLessThan(DfsPackDescription.reftableComparator(), a, b); + } + + @Test + public void reuseComparatorEqual() throws Exception { + DfsPackDescription a = create(RECEIVE); + a.setFileSize(PACK, 1); + a.setFileSize(INDEX, 1); + a.setLastModified(1); + a.setObjectCount(1); + a.setMaxUpdateIndex(1); + + DfsPackDescription b = create(INSERT); + b.setFileSize(PACK, 2); + b.setFileSize(INDEX, 2); + b.setLastModified(2); + b.setObjectCount(2); + b.setMaxUpdateIndex(2); + + assertComparesEqual(DfsPackDescription.reuseComparator(), a, b); + } + + @Test + public void reuseComparatorGcPackSize() throws Exception { + DfsPackDescription a = create(GC_REST); + a.setFileSize(PACK, 1); + a.setFileSize(INDEX, 1); + a.setLastModified(2); + a.setObjectCount(1); + a.setMaxUpdateIndex(1); + + DfsPackDescription b = create(GC_REST); + b.setFileSize(PACK, 2); + b.setFileSize(INDEX, 2); + b.setLastModified(1); + b.setObjectCount(2); + b.setMaxUpdateIndex(2); + + assertComparesLessThan(DfsPackDescription.reuseComparator(), b, a); + } + + private DfsPackDescription create(PackSource source) { + return new DfsPackDescription( + new DfsRepositoryDescription("repo"), + "pack_" + counter.incrementAndGet(), + source); + } + + private static <T> void assertComparesEqual( + Comparator<T> comparator, T o1, T o2) { + assertEquals( + "first object must compare equal to itself", + 0, comparator.compare(o1, o1)); + assertEquals( + "second object must compare equal to itself", + 0, comparator.compare(o2, o2)); + assertEquals( + "first object must compare equal to second object", + 0, comparator.compare(o1, o2)); + } + + private static <T> void assertComparesLessThan( + Comparator<T> comparator, T o1, T o2) { + assertEquals( + "first object must compare equal to itself", + 0, comparator.compare(o1, o1)); + assertEquals( + "second object must compare equal to itself", + 0, comparator.compare(o2, o2)); + assertEquals( + "first object must compare less than second object", + -1, comparator.compare(o1, o2)); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/PackSourceTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/PackSourceTest.java new file mode 100644 index 0000000000..7bf1f587f8 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/PackSourceTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2018, 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.internal.storage.dfs; + +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.COMPACT; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.DEFAULT_COMPARATOR; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC_REST; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC_TXN; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.INSERT; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.RECEIVE; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.UNREACHABLE_GARBAGE; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class PackSourceTest { + @Test + public void defaultComaprator() throws Exception { + assertEquals(0, DEFAULT_COMPARATOR.compare(INSERT, INSERT)); + assertEquals(0, DEFAULT_COMPARATOR.compare(RECEIVE, RECEIVE)); + assertEquals(0, DEFAULT_COMPARATOR.compare(COMPACT, COMPACT)); + assertEquals(0, DEFAULT_COMPARATOR.compare(GC, GC)); + assertEquals(0, DEFAULT_COMPARATOR.compare(GC_REST, GC_REST)); + assertEquals(0, DEFAULT_COMPARATOR.compare(GC_TXN, GC_TXN)); + assertEquals(0, DEFAULT_COMPARATOR.compare(UNREACHABLE_GARBAGE, UNREACHABLE_GARBAGE)); + + assertEquals(0, DEFAULT_COMPARATOR.compare(INSERT, RECEIVE)); + assertEquals(0, DEFAULT_COMPARATOR.compare(RECEIVE, INSERT)); + + assertEquals(-1, DEFAULT_COMPARATOR.compare(INSERT, COMPACT)); + assertEquals(1, DEFAULT_COMPARATOR.compare(COMPACT, INSERT)); + + assertEquals(-1, DEFAULT_COMPARATOR.compare(RECEIVE, COMPACT)); + assertEquals(1, DEFAULT_COMPARATOR.compare(COMPACT, RECEIVE)); + + assertEquals(-1, DEFAULT_COMPARATOR.compare(COMPACT, GC)); + assertEquals(1, DEFAULT_COMPARATOR.compare(GC, COMPACT)); + + assertEquals(-1, DEFAULT_COMPARATOR.compare(GC, GC_REST)); + assertEquals(1, DEFAULT_COMPARATOR.compare(GC_REST, GC)); + + assertEquals(-1, DEFAULT_COMPARATOR.compare(GC_REST, GC_TXN)); + assertEquals(1, DEFAULT_COMPARATOR.compare(GC_TXN, GC_REST)); + + assertEquals(-1, DEFAULT_COMPARATOR.compare(GC_TXN, UNREACHABLE_GARBAGE)); + assertEquals(1, DEFAULT_COMPARATOR.compare(UNREACHABLE_GARBAGE, GC_TXN)); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java index d9b58e206f..ffb6f4ee77 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java @@ -50,6 +50,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Set; @@ -243,7 +244,8 @@ public class GcCommitSelectionTest extends GcTestCase { List<RevCommit> commits = Arrays.asList(m0, m1, m2, b3, m4, b5, m6, b7, m8, m9); - PackWriterBitmapPreparer preparer = newPeparer(m9, commits); + PackWriterBitmapPreparer preparer = newPreparer( + Collections.singleton(m9), commits, new PackConfig()); List<BitmapCommit> selection = new ArrayList<>( preparer.selectCommits(commits.size(), PackWriter.NONE)); @@ -267,15 +269,107 @@ public class GcCommitSelectionTest extends GcTestCase { return commit.create(); } - private PackWriterBitmapPreparer newPeparer(RevCommit want, - List<RevCommit> commits) - throws IOException { + @Test + public void testDistributionOnMultipleBranches() throws Exception { + BranchBuilder[] branches = { tr.branch("refs/heads/main"), + tr.branch("refs/heads/a"), tr.branch("refs/heads/b"), + tr.branch("refs/heads/c") }; + RevCommit[] tips = new RevCommit[branches.length]; + List<RevCommit> commits = createHistory(branches, tips); + PackConfig config = new PackConfig(); + config.setBitmapContiguousCommitCount(1); + config.setBitmapRecentCommitSpan(5); + config.setBitmapDistantCommitSpan(20); + config.setBitmapRecentCommitCount(100); + Set<RevCommit> wants = new HashSet<>(Arrays.asList(tips)); + PackWriterBitmapPreparer preparer = newPreparer(wants, commits, config); + List<BitmapCommit> selection = new ArrayList<>( + preparer.selectCommits(commits.size(), PackWriter.NONE)); + Set<ObjectId> selected = new HashSet<>(); + for (BitmapCommit c : selection) { + selected.add(c.toObjectId()); + } + + // Verify that each branch has uniform bitmap selection coverage + for (RevCommit c : wants) { + assertTrue(selected.contains(c.toObjectId())); + int count = 1; + int selectedCount = 1; + RevCommit parent = c; + while (parent.getParentCount() != 0) { + parent = parent.getParent(0); + count++; + if (selected.contains(parent.toObjectId())) { + selectedCount++; + } + } + // The selection algorithm prefers merges and will look in the + // current range plus the recent commit span before selecting a + // commit. Since this history has no merges, we expect the recent + // span should have 100/10=10 and distant commit spans should have + // 100/25=4 per 100 commit range. + int expectedCount = 10 + (count - 100 - 24) / 25; + assertTrue(expectedCount <= selectedCount); + } + } + + private List<RevCommit> createHistory(BranchBuilder[] branches, + RevCommit[] tips) throws Exception { + /*- + * Create a history like this, where branches a, b and c branch off of the main branch + * at commits 100, 200 and 300, and where commit times move forward alternating between + * branches. + * + * o...o...o...o...o commits root,m0,m1,...,m399 + * \ \ \ + * \ \ o... commits branch_c,c300,c301,...,c399 + * \ \ + * \ o...o... commits branch_b,b200,b201,...,b399 + * \ + * o...o...o... commits branch_a,b100,b101,...,a399 + */ + List<RevCommit> commits = new ArrayList<>(); + String[] prefixes = { "m", "a", "b", "c" }; + int branchCount = branches.length; + tips[0] = addCommit(commits, branches[0], "root"); + int counter = 0; + + for (int b = 0; b < branchCount; b++) { + for (int i = 0; i < 100; i++, counter++) { + for (int j = 0; j <= b; j++) { + tips[j] = addCommit(commits, branches[j], + prefixes[j] + counter); + } + } + // Create a new branch from current value of the master branch + if (b < branchCount - 1) { + tips[b + 1] = addCommit(branches[b + 1], + "branch_" + prefixes[b + 1], tips[0]); + } + } + return commits; + } + + private RevCommit addCommit(List<RevCommit> commits, BranchBuilder bb, + String msg, RevCommit... parents) throws Exception { + CommitBuilder commit = bb.commit().message(msg).add(msg, msg).tick(1); + if (parents.length > 0) { + commit.noParents(); + for (RevCommit parent : parents) { + commit.parent(parent); + } + } + RevCommit c = commit.create(); + commits.add(c); + return c; + } + + private PackWriterBitmapPreparer newPreparer(Set<RevCommit> wants, + List<RevCommit> commits, PackConfig config) throws IOException { List<ObjectToPack> objects = new ArrayList<>(commits.size()); for (RevCommit commit : commits) { objects.add(new ObjectToPack(commit, Constants.OBJ_COMMIT)); } - Set<ObjectId> wants = Collections.singleton((ObjectId) want); - PackConfig config = new PackConfig(); PackBitmapIndexBuilder builder = new PackBitmapIndexBuilder(objects); return new PackWriterBitmapPreparer( tr.getRepository().newObjectReader(), builder, diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java index ec60bd9137..1d11573b99 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java @@ -80,7 +80,7 @@ public class MergedReftableTest { try (RefCursor rc = mr.seekRef(HEAD)) { assertFalse(rc.next()); } - try (RefCursor rc = mr.seekRef(R_HEADS)) { + try (RefCursor rc = mr.seekRefsWithPrefix(R_HEADS)) { assertFalse(rc.next()); } } @@ -94,7 +94,7 @@ public class MergedReftableTest { try (RefCursor rc = mr.seekRef(HEAD)) { assertFalse(rc.next()); } - try (RefCursor rc = mr.seekRef(R_HEADS)) { + try (RefCursor rc = mr.seekRefsWithPrefix(R_HEADS)) { assertFalse(rc.next()); } } @@ -108,7 +108,7 @@ public class MergedReftableTest { try (RefCursor rc = mr.seekRef(HEAD)) { assertFalse(rc.next()); } - try (RefCursor rc = mr.seekRef(R_HEADS)) { + try (RefCursor rc = mr.seekRefsWithPrefix(R_HEADS)) { assertFalse(rc.next()); } } 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 3ea3061e38..0ee785c60c 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 @@ -101,7 +101,7 @@ public class ReftableTest { try (RefCursor rc = t.seekRef(HEAD)) { assertFalse(rc.next()); } - try (RefCursor rc = t.seekRef(R_HEADS)) { + try (RefCursor rc = t.seekRefsWithPrefix(R_HEADS)) { assertFalse(rc.next()); } try (LogCursor rc = t.allLogs()) { @@ -317,10 +317,10 @@ public class ReftableTest { public void namespaceNotFound() throws IOException { Ref exp = ref(MASTER, 1); ReftableReader t = read(write(exp)); - try (RefCursor rc = t.seekRef("refs/changes/")) { + try (RefCursor rc = t.seekRefsWithPrefix("refs/changes/")) { assertFalse(rc.next()); } - try (RefCursor rc = t.seekRef("refs/tags/")) { + try (RefCursor rc = t.seekRefsWithPrefix("refs/tags/")) { assertFalse(rc.next()); } } @@ -332,12 +332,12 @@ public class ReftableTest { Ref v1 = tag(V1_0, 3, 4); ReftableReader t = read(write(master, next, v1)); - try (RefCursor rc = t.seekRef("refs/tags/")) { + try (RefCursor rc = t.seekRefsWithPrefix("refs/tags/")) { assertTrue(rc.next()); assertEquals(V1_0, rc.getRef().getName()); assertFalse(rc.next()); } - try (RefCursor rc = t.seekRef("refs/heads/")) { + try (RefCursor rc = t.seekRefsWithPrefix("refs/heads/")) { assertTrue(rc.next()); assertEquals(MASTER, rc.getRef().getName()); @@ -484,7 +484,7 @@ public class ReftableTest { try (RefCursor rc = t.allRefs()) { assertFalse(rc.next()); } - try (RefCursor rc = t.seekRef("refs/heads/")) { + try (RefCursor rc = t.seekRefsWithPrefix("refs/heads/")) { assertFalse(rc.next()); } try (LogCursor lc = t.allLogs()) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/HugeCommitMessageTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/HugeCommitMessageTest.java new file mode 100644 index 0000000000..4193c4ba3e --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/HugeCommitMessageTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch> + * 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.lib; + +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.storage.file.WindowCacheConfig; +import org.eclipse.jgit.storage.pack.PackConfig; +import org.junit.Test; + +public class HugeCommitMessageTest extends RepositoryTestCase { + + private static final int HUGE_SIZE = Math.max(15 * WindowCacheConfig.MB, + PackConfig.DEFAULT_BIG_FILE_THRESHOLD + WindowCacheConfig.MB); + // Larger than the 5MB fallback limit in RevWalk.getCachedBytes(RevObject + // obj, ObjectLoader ldr), and also larger than the default + // streamFileThreshold. + + @Test + public void testHugeCommitMessage() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("foo", "foo"); + git.add().addFilepattern("foo").call(); + WindowCacheConfig wc = new WindowCacheConfig(); + wc.setStreamFileThreshold(HUGE_SIZE + WindowCacheConfig.MB); + wc.install(); + RevCommit commit = git.commit() + .setMessage(insanelyHugeCommitMessage()).call(); + Ref master = db.findRef("master"); + List<Ref> actual = git.branchList().setContains(commit.getName()) + .call(); + assertTrue("Should be contained in branch master", + actual.contains(master)); + } + } + + private String insanelyHugeCommitMessage() { + final String oneLine = "012345678901234567890123456789012345678901234567890123456789\n"; + StringBuilder b = new StringBuilder(HUGE_SIZE + oneLine.length()); + // Give the message a real header; otherwise even writing the reflog + // message may run into troubles because RevCommit.getShortMessage() + // will return the whole message. + b.append("An insanely huge commit message\n\n"); + while (b.length() < HUGE_SIZE) { + b.append(oneLine); + } + return b.toString(); + } + +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java index 8d9ccab1bd..3542dfad2d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java @@ -45,6 +45,7 @@ package org.eclipse.jgit.lib; import static java.lang.Long.valueOf; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import java.io.File; import java.io.FileOutputStream; @@ -157,10 +158,13 @@ public class RacyGitTests extends RepositoryTestCase { // Remember the last modTime of index file. All modifications times of // further modification are translated to this value so it looks that // files have been modified in the same time slot as the index file - modTimes.add(Long.valueOf(db.getIndexFile().lastModified())); + long indexMod = db.getIndexFile().lastModified(); + modTimes.add(Long.valueOf(indexMod)); // modify one file - addToWorkDir("a", "a2"); + long aMod = addToWorkDir("a", "a2").lastModified(); + assumeTrue(aMod == indexMod); + // now update the index the index. 'a' has to be racily clean -- because // it's modification time is exactly the same as the previous index file // mod time. diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java index 2481e64997..a42027b584 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java @@ -58,7 +58,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; -import java.util.Map; +import java.util.Optional; import java.util.TreeSet; import org.eclipse.jgit.lib.Ref.Storage; @@ -148,17 +148,22 @@ public class RefTest extends SampleDataRepositoryTestCase { ObjectId r = db.resolve("refs/remotes/origin/HEAD"); assertEquals(masterId, r); - Map<String, Ref> allRefs = db.getAllRefs(); - Ref refHEAD = allRefs.get("refs/remotes/origin/HEAD"); - assertNotNull(refHEAD); - assertEquals(masterId, refHEAD.getObjectId()); - assertFalse(refHEAD.isPeeled()); - assertNull(refHEAD.getPeeledObjectId()); - - Ref refmaster = allRefs.get("refs/remotes/origin/master"); - assertEquals(masterId, refmaster.getObjectId()); - assertFalse(refmaster.isPeeled()); - assertNull(refmaster.getPeeledObjectId()); + List<Ref> allRefs = db.getRefDatabase().getRefs(); + Optional<Ref> refHEAD = allRefs.stream() + .filter(ref -> ref.getName().equals("refs/remotes/origin/HEAD")) + .findAny(); + assertTrue(refHEAD.isPresent()); + assertEquals(masterId, refHEAD.get().getObjectId()); + assertFalse(refHEAD.get().isPeeled()); + assertNull(refHEAD.get().getPeeledObjectId()); + + Optional<Ref> refmaster = allRefs.stream().filter( + ref -> ref.getName().equals("refs/remotes/origin/master")) + .findAny(); + assertTrue(refmaster.isPresent()); + assertEquals(masterId, refmaster.get().getObjectId()); + assertFalse(refmaster.get().isPeeled()); + assertNull(refmaster.get().getPeeledObjectId()); } @Test diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java index 58093a3729..da4513d1f7 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java @@ -60,6 +60,7 @@ import java.util.Map; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.MergeResult; import org.eclipse.jgit.api.MergeResult.MergeStatus; +import org.eclipse.jgit.api.RebaseResult; import org.eclipse.jgit.api.errors.CheckoutConflictException; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.JGitInternalException; @@ -428,6 +429,44 @@ public class MergerTest extends RepositoryTestCase { indexState(CONTENT)); } + @Theory + public void rebaseWithCrlfAutoCrlfTrue(MergeStrategy strategy) + throws IOException, GitAPIException { + Git git = Git.wrap(db); + db.getConfig().setString("core", null, "autocrlf", "true"); + db.getConfig().save(); + writeTrashFile("crlf.txt", "line 1\r\nline 2\r\nline 3\r\n"); + git.add().addFilepattern("crlf.txt").call(); + RevCommit first = git.commit().setMessage("base").call(); + + git.checkout().setCreateBranch(true).setStartPoint(first) + .setName("brancha").call(); + + File testFile = writeTrashFile("crlf.txt", + "line 1\r\nmodified line\r\nline 3\r\n"); + git.add().addFilepattern("crlf.txt").call(); + git.commit().setMessage("on brancha").call(); + + git.checkout().setName("master").call(); + File otherFile = writeTrashFile("otherfile.txt", "a line\r\n"); + git.add().addFilepattern("otherfile.txt").call(); + git.commit().setMessage("on master").call(); + + git.checkout().setName("brancha").call(); + checkFile(testFile, "line 1\r\nmodified line\r\nline 3\r\n"); + assertFalse(otherFile.exists()); + + RebaseResult rebaseResult = git.rebase().setStrategy(strategy) + .setUpstream(db.resolve("master")).call(); + assertEquals(RebaseResult.Status.OK, rebaseResult.getStatus()); + checkFile(testFile, "line 1\r\nmodified line\r\nline 3\r\n"); + checkFile(otherFile, "a line\r\n"); + assertEquals( + "[crlf.txt, mode:100644, content:line 1\nmodified line\nline 3\n]" + + "[otherfile.txt, mode:100644, content:a line\n]", + indexState(CONTENT)); + } + /** * Merging two equal subtrees when the index does not contain any file in * that subtree should lead to a merged state. diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevObjectTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevObjectTest.java index 8e389ae252..4969305de0 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevObjectTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevObjectTest.java @@ -144,13 +144,13 @@ public class RevObjectTest extends RevWalkTestCase { final RevCommit a = commit(); final RevFlag flag1 = rw.newFlag("flag1"); final RevFlag flag2 = rw.newFlag("flag2"); - assertEquals(0, a.flags); + assertEquals(RevWalk.PARSED, a.flags); a.add(flag1); - assertEquals(flag1.mask, a.flags); + assertEquals(RevWalk.PARSED | flag1.mask, a.flags); a.add(flag2); - assertEquals(flag1.mask | flag2.mask, a.flags); + assertEquals(RevWalk.PARSED | flag1.mask | flag2.mask, a.flags); } @Test @@ -162,10 +162,10 @@ public class RevObjectTest extends RevWalkTestCase { s.add(flag1); s.add(flag2); - assertEquals(0, a.flags); + assertEquals(RevWalk.PARSED, a.flags); a.add(s); - assertEquals(flag1.mask | flag2.mask, a.flags); + assertEquals(RevWalk.PARSED | flag1.mask | flag2.mask, a.flags); } @Test @@ -175,9 +175,9 @@ public class RevObjectTest extends RevWalkTestCase { final RevFlag flag2 = rw.newFlag("flag2"); a.add(flag1); a.add(flag2); - assertEquals(flag1.mask | flag2.mask, a.flags); + assertEquals(RevWalk.PARSED | flag1.mask | flag2.mask, a.flags); a.remove(flag2); - assertEquals(flag1.mask, a.flags); + assertEquals(RevWalk.PARSED | flag1.mask, a.flags); } @Test @@ -191,8 +191,8 @@ public class RevObjectTest extends RevWalkTestCase { s.add(flag2); a.add(flag3); a.add(s); - assertEquals(flag1.mask | flag2.mask | flag3.mask, a.flags); + assertEquals(RevWalk.PARSED | flag1.mask | flag2.mask | flag3.mask, a.flags); a.remove(s); - assertEquals(flag3.mask, a.flags); + assertEquals(RevWalk.PARSED | flag3.mask, a.flags); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkCullTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkCullTest.java index fb52828c5b..7984a37193 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkCullTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkCullTest.java @@ -85,7 +85,7 @@ public class RevWalkCullTest extends RevWalkTestCase { @Test public void testProperlyCullAllAncestors_LongHistory() throws Exception { - final RevCommit a = commit(); + RevCommit a = commit(); RevCommit b = commit(a); for (int i = 0; i < 24; i++) { b = commit(b); @@ -94,6 +94,12 @@ public class RevWalkCullTest extends RevWalkTestCase { } final RevCommit c = commit(b); + // TestRepository eagerly parses newly created objects. The current rw + // is caching that parsed state. To verify that RevWalk itself is lazy, + // set up a new one. + rw.close(); + rw = createRevWalk(); + RevCommit a2 = rw.lookupCommit(a); markStart(c); markUninteresting(b); assertCommit(c, rw.next()); @@ -102,6 +108,6 @@ public class RevWalkCullTest extends RevWalkTestCase { // We should have aborted before we got back so far that "a" // would be parsed. Thus, its parents shouldn't be allocated. // - assertNull(a.parents); + assertNull(a2.parents); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkShallowTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkShallowTest.java index 6df36e78f1..7554d7a479 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkShallowTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkShallowTest.java @@ -58,138 +58,155 @@ public class RevWalkShallowTest extends RevWalkTestCase { @Test public void testDepth1() throws Exception { - final RevCommit a = commit(); - final RevCommit b = commit(a); - final RevCommit c = commit(b); - final RevCommit d = commit(c); + RevCommit[] commits = setupLinearChain(); - createShallowFile(d); + createShallowFile(commits[3]); + updateCommits(commits); - rw.reset(); - markStart(d); - assertCommit(d, rw.next()); + rw.markStart(commits[3]); + assertCommit(commits[3], rw.next()); assertNull(rw.next()); } @Test public void testDepth2() throws Exception { - final RevCommit a = commit(); - final RevCommit b = commit(a); - final RevCommit c = commit(b); - final RevCommit d = commit(c); + RevCommit[] commits = setupLinearChain(); - createShallowFile(c); + createShallowFile(commits[2]); + updateCommits(commits); - rw.reset(); - markStart(d); - assertCommit(d, rw.next()); - assertCommit(c, rw.next()); + rw.markStart(commits[3]); + assertCommit(commits[3], rw.next()); + assertCommit(commits[2], rw.next()); assertNull(rw.next()); } @Test public void testDepth3() throws Exception { - final RevCommit a = commit(); - final RevCommit b = commit(a); - final RevCommit c = commit(b); - final RevCommit d = commit(c); + RevCommit[] commits = setupLinearChain(); - createShallowFile(b); + createShallowFile(commits[1]); + updateCommits(commits); - rw.reset(); - markStart(d); - assertCommit(d, rw.next()); - assertCommit(c, rw.next()); - assertCommit(b, rw.next()); + rw.markStart(commits[3]); + assertCommit(commits[3], rw.next()); + assertCommit(commits[2], rw.next()); + assertCommit(commits[1], rw.next()); assertNull(rw.next()); } @Test - public void testMergeCommitOneParentShallow() throws Exception { - final RevCommit a = commit(); - final RevCommit b = commit(a); - final RevCommit c = commit(b); - final RevCommit d = commit(b); - final RevCommit e = commit(d); - final RevCommit merge = commit(c, e); - - createShallowFile(e); - - rw.reset(); - markStart(merge); - assertCommit(merge, rw.next()); - assertCommit(e, rw.next()); - assertCommit(c, rw.next()); - assertCommit(b, rw.next()); - assertCommit(a, rw.next()); + public void testObjectDirectorySnapshot() throws Exception { + RevCommit[] commits = setupLinearChain(); + + createShallowFile(commits[3]); + updateCommits(commits); + + markStart(commits[3]); + assertCommit(commits[3], rw.next()); assertNull(rw.next()); - } - @Test - public void testMergeCommitEntirelyShallow() throws Exception { - final RevCommit a = commit(); - final RevCommit b = commit(a); - final RevCommit c = commit(b); - final RevCommit d = commit(b); - final RevCommit e = commit(d); - final RevCommit merge = commit(c, e); - - createShallowFile(c, e); - - rw.reset(); - markStart(merge); - assertCommit(merge, rw.next()); - assertCommit(e, rw.next()); - assertCommit(c, rw.next()); + createShallowFile(commits[2]); + updateCommits(commits); + + markStart(commits[3]); + assertCommit(commits[3], rw.next()); + assertCommit(commits[2], rw.next()); assertNull(rw.next()); } + private RevCommit[] setupLinearChain() throws Exception { + RevCommit[] commits = new RevCommit[4]; + RevCommit parent = null; + for (int i = 0; i < commits.length; i++) { + commits[i] = parent != null ? commit(parent) : commit(); + parent = commits[i]; + } + return commits; + } + @Test - public void testObjectDirectorySnapshot() throws Exception { - RevCommit a = commit(); - RevCommit b = commit(a); - RevCommit c = commit(b); - RevCommit d = commit(c); + public void testMergeCommitOneParentShallow() throws Exception { + RevCommit[] commits = setupMergeChain(); - createShallowFile(d); + createShallowFile(commits[4]); + updateCommits(commits); - rw.reset(); - markStart(d); - assertCommit(d, rw.next()); + markStart(commits[5]); + assertCommit(commits[5], rw.next()); + assertCommit(commits[4], rw.next()); + assertCommit(commits[2], rw.next()); + assertCommit(commits[1], rw.next()); + assertCommit(commits[0], rw.next()); assertNull(rw.next()); + } - rw = createRevWalk(); - a = rw.lookupCommit(a); - b = rw.lookupCommit(b); - c = rw.lookupCommit(c); - d = rw.lookupCommit(d); - - rw.reset(); - markStart(d); - assertCommit(d, rw.next()); - assertNull(rw.next()); + @Test + public void testMergeCommitEntirelyShallow() throws Exception { + RevCommit[] commits = setupMergeChain(); - createShallowFile(c); + createShallowFile(commits[2], commits[4]); + updateCommits(commits); - rw = createRevWalk(); - a = rw.lookupCommit(a); - b = rw.lookupCommit(b); - c = rw.lookupCommit(c); - d = rw.lookupCommit(d); - - rw.reset(); - markStart(d); - assertCommit(d, rw.next()); - assertCommit(c, rw.next()); + markStart(commits[5]); + assertCommit(commits[5], rw.next()); + assertCommit(commits[4], rw.next()); + assertCommit(commits[2], rw.next()); assertNull(rw.next()); } + private RevCommit[] setupMergeChain() throws Exception { + /*- + * Create a history like this, diverging at 1 and merging at 5: + * + * ---o--o commits 3,4 + * / \ + * o--o--o------o commits 0,1,2,5 + */ + RevCommit[] commits = new RevCommit[6]; + commits[0] = commit(); + commits[1] = commit(commits[0]); + commits[2] = commit(commits[1]); + commits[3] = commit(commits[1]); + commits[4] = commit(commits[3]); + commits[5] = commit(commits[2], commits[4]); + return commits; + } + + private void updateCommits(RevCommit[] commits) { + // Relookup commits using the new RevWalk + for (int i = 0; i < commits.length; i++) { + commits[i] = rw.lookupCommit(commits[i].getId()); + } + } + private void createShallowFile(ObjectId... shallowCommits) throws IOException { - final StringBuilder builder = new StringBuilder(); - for (ObjectId commit : shallowCommits) + // Reset the RevWalk since the new shallow file invalidates the existing + // RevWalk's shallow state. + rw.close(); + rw = createRevWalk(); + StringBuilder builder = new StringBuilder(); + for (ObjectId commit : shallowCommits) { builder.append(commit.getName() + "\n"); + } JGitTestUtil.write(new File(db.getDirectory(), "shallow"), builder.toString()); } + + @Test + public void testShallowCommitParse() throws Exception { + RevCommit a = commit(); + RevCommit b = commit(a); + + createShallowFile(b); + + rw.close(); + rw = createRevWalk(); + b = rw.parseCommit(b); + + markStart(b); + assertCommit(b, rw.next()); + assertNull(rw.next()); + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java index a26ae10af3..cb92a955bc 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java @@ -115,7 +115,7 @@ public class RevWalkUtilsReachableTest extends RevWalkTestCase { } private void assertContains(RevCommit commit, Collection<Ref> refsThatShouldContainCommit) throws Exception { - Collection<Ref> allRefs = db.getAllRefs().values(); + Collection<Ref> allRefs = db.getRefDatabase().getRefs(); Collection<Ref> sortedRefs = RefComparator.sort(allRefs); List<Ref> actual = RevWalkUtils.findBranchesReachableFrom(commit, rw, sortedRefs); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java index 1a67e41976..0676eab2d6 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java @@ -136,7 +136,49 @@ public class SubmoduleAddTest extends RepositoryTestCase { } SubmoduleWalk generator = SubmoduleWalk.forIndex(db); + generator.loadModulesConfig(); assertTrue(generator.next()); + assertEquals(path, generator.getModuleName()); + assertEquals(path, generator.getPath()); + assertEquals(commit, generator.getObjectId()); + assertEquals(uri, generator.getModulesUrl()); + assertEquals(path, generator.getModulesPath()); + assertEquals(uri, generator.getConfigUrl()); + try (Repository subModRepo = generator.getRepository()) { + assertNotNull(subModRepo); + assertEquals(subCommit, commit); + } + + Status status = Git.wrap(db).status().call(); + assertTrue(status.getAdded().contains(Constants.DOT_GIT_MODULES)); + assertTrue(status.getAdded().contains(path)); + } + } + + @Test + public void addSubmoduleWithName() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("file.txt", "content"); + git.add().addFilepattern("file.txt").call(); + RevCommit commit = git.commit().setMessage("create file").call(); + + SubmoduleAddCommand command = new SubmoduleAddCommand(db); + String name = "testsub"; + command.setName(name); + String path = "sub"; + command.setPath(path); + String uri = db.getDirectory().toURI().toString(); + command.setURI(uri); + ObjectId subCommit; + try (Repository repo = command.call()) { + assertNotNull(repo); + subCommit = repo.resolve(Constants.HEAD); + } + + SubmoduleWalk generator = SubmoduleWalk.forIndex(db); + generator.loadModulesConfig(); + assertTrue(generator.next()); + assertEquals(name, generator.getModuleName()); assertEquals(path, generator.getPath()); assertEquals(commit, generator.getObjectId()); assertEquals(uri, generator.getModulesUrl()); @@ -268,4 +310,18 @@ public class SubmoduleAddTest extends RepositoryTestCase { ConfigConstants.CONFIG_KEY_URL)); } } + + @Test + public void denySubmoduleWithDotDot() throws Exception { + SubmoduleAddCommand command = new SubmoduleAddCommand(db); + command.setName("dir/../"); + command.setPath("sub"); + command.setURI(db.getDirectory().toURI().toString()); + try { + command.call(); + fail(); + } catch (IllegalArgumentException e) { + // Expected + } + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleDeinitTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleDeinitTest.java index df4b96398f..815ce9b350 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleDeinitTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleDeinitTest.java @@ -136,10 +136,12 @@ public class SubmoduleDeinitTest extends RepositoryTestCase { generator.next(); //want to create a commit inside the repo... - Repository submoduleLocalRepo = generator.getRepository(); - JGitTestUtil.writeTrashFile(submoduleLocalRepo, "file.txt", "new data"); - Git.wrap(submoduleLocalRepo).commit().setAll(true).setMessage("local commit").call(); - + try (Repository submoduleLocalRepo = generator.getRepository()) { + JGitTestUtil.writeTrashFile(submoduleLocalRepo, "file.txt", + "new data"); + Git.wrap(submoduleLocalRepo).commit().setAll(true) + .setMessage("local commit").call(); + } SubmoduleDeinitResult result = runDeinit(new SubmoduleDeinitCommand(db).addPath("sub")); assertEquals(path, result.getPath()); assertEquals(SubmoduleDeinitCommand.SubmoduleDeinitStatus.DIRTY, result.getStatus()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java index b77042220f..9cc6cfd393 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java @@ -259,6 +259,7 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas try (TransportLocal t = newTransportLocalWithStrictValidation()) { t.setPushThin(true); r = t.push(PM, Collections.singleton(u)); + dst.close(); } assertNotNull("have result", r); 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 ef083da183..79d3d87e2d 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,20 +1,24 @@ package org.eclipse.jgit.transport; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.theInstance; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringWriter; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + import org.eclipse.jgit.errors.PackProtocolException; import org.eclipse.jgit.errors.TransportException; import org.eclipse.jgit.internal.storage.dfs.DfsGarbageCollector; @@ -29,8 +33,8 @@ import org.eclipse.jgit.lib.Sets; import org.eclipse.jgit.lib.TextProgressMonitor; import org.eclipse.jgit.revwalk.RevBlob; import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevTag; +import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.transport.UploadPack.RequestPolicy; import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; @@ -227,6 +231,44 @@ public class UploadPackTest { } @Test + public void testFetchExplicitBlobWithFilter() throws Exception { + InMemoryRepository server2 = newRepo("server2"); + TestRepository<InMemoryRepository> remote2 = + new TestRepository<>(server2); + RevBlob blob1 = remote2.blob("foobar"); + RevBlob blob2 = remote2.blob("fooba"); + RevTree tree = remote2.tree(remote2.file("1", blob1), + remote2.file("2", blob2)); + RevCommit commit = remote2.commit(tree); + remote2.update("master", commit); + remote2.update("a_blob", blob1); + + server2.getConfig().setBoolean("uploadpack", null, "allowfilter", true); + + testProtocol = new TestProtocol<>( + new UploadPackFactory<Object>() { + @Override + public UploadPack create(Object req, Repository db) + throws ServiceNotEnabledException, + ServiceNotAuthorizedException { + UploadPack up = new UploadPack(db); + return up; + } + }, null); + uri = testProtocol.register(ctx, server2); + + try (Transport tn = testProtocol.open(uri, client, "server2")) { + tn.setFilterBlobLimit(0); + tn.fetch(NullProgressMonitor.INSTANCE, Arrays.asList( + new RefSpec(commit.name()), + new RefSpec(blob1.name()))); + assertTrue(client.hasObject(tree.toObjectId())); + assertTrue(client.hasObject(blob1.toObjectId())); + assertFalse(client.hasObject(blob2.toObjectId())); + } + } + + @Test public void testFetchWithBlobLimitFilter() throws Exception { InMemoryRepository server2 = newRepo("server2"); TestRepository<InMemoryRepository> remote2 = @@ -262,6 +304,47 @@ public class UploadPackTest { } @Test + public void testFetchExplicitBlobWithFilterAndBitmaps() throws Exception { + InMemoryRepository server2 = newRepo("server2"); + TestRepository<InMemoryRepository> remote2 = + new TestRepository<>(server2); + RevBlob blob1 = remote2.blob("foobar"); + RevBlob blob2 = remote2.blob("fooba"); + RevTree tree = remote2.tree(remote2.file("1", blob1), + remote2.file("2", blob2)); + RevCommit commit = remote2.commit(tree); + remote2.update("master", commit); + remote2.update("a_blob", blob1); + + server2.getConfig().setBoolean("uploadpack", null, "allowfilter", true); + + // generate bitmaps + new DfsGarbageCollector(server2).pack(null); + server2.scanForRepoChanges(); + + testProtocol = new TestProtocol<>( + new UploadPackFactory<Object>() { + @Override + public UploadPack create(Object req, Repository db) + throws ServiceNotEnabledException, + ServiceNotAuthorizedException { + UploadPack up = new UploadPack(db); + return up; + } + }, null); + uri = testProtocol.register(ctx, server2); + + try (Transport tn = testProtocol.open(uri, client, "server2")) { + tn.setFilterBlobLimit(0); + tn.fetch(NullProgressMonitor.INSTANCE, Arrays.asList( + new RefSpec(commit.name()), + new RefSpec(blob1.name()))); + assertTrue(client.hasObject(blob1.toObjectId())); + assertFalse(client.hasObject(blob2.toObjectId())); + } + } + + @Test public void testFetchWithBlobLimitFilterAndBitmaps() throws Exception { InMemoryRepository server2 = newRepo("server2"); TestRepository<InMemoryRepository> remote2 = @@ -340,7 +423,8 @@ public class UploadPackTest { * and returns UploadPack's output stream. */ private ByteArrayInputStream uploadPackV2Setup(RequestPolicy requestPolicy, - RefFilter refFilter, String... inputLines) throws Exception { + RefFilter refFilter, ProtocolV2Hook hook, String... inputLines) + throws Exception { ByteArrayOutputStream send = new ByteArrayOutputStream(); PacketLineOut pckOut = new PacketLineOut(send); @@ -361,6 +445,9 @@ public class UploadPackTest { if (refFilter != null) up.setRefFilter(refFilter); up.setExtraParameters(Sets.of("version=2")); + if (hook != null) { + up.setProtocolV2Hook(hook); + } ByteArrayOutputStream recv = new ByteArrayOutputStream(); up.upload(new ByteArrayInputStream(send.toByteArray()), recv, null); @@ -374,9 +461,10 @@ public class UploadPackTest { * advertisement by the server. */ private ByteArrayInputStream uploadPackV2(RequestPolicy requestPolicy, - RefFilter refFilter, String... inputLines) throws Exception { + RefFilter refFilter, ProtocolV2Hook hook, String... inputLines) + throws Exception { ByteArrayInputStream recvStream = - uploadPackV2Setup(requestPolicy, refFilter, inputLines); + uploadPackV2Setup(requestPolicy, refFilter, hook, inputLines); PacketLineIn pckIn = new PacketLineIn(recvStream); // drain capabilities @@ -387,15 +475,33 @@ public class UploadPackTest { } private ByteArrayInputStream uploadPackV2(String... inputLines) throws Exception { - return uploadPackV2(null, null, inputLines); + return uploadPackV2(null, null, null, inputLines); + } + + private static class TestV2Hook implements ProtocolV2Hook { + private CapabilitiesV2Request capabilitiesRequest; + + private LsRefsV2Request lsRefsRequest; + + @Override + public void onCapabilities(CapabilitiesV2Request req) { + capabilitiesRequest = req; + } + + @Override + public void onLsRefs(LsRefsV2Request req) { + lsRefsRequest = req; + } } @Test public void testV2Capabilities() throws Exception { + TestV2Hook hook = new TestV2Hook(); ByteArrayInputStream recvStream = - uploadPackV2Setup(null, null, PacketLineIn.END); + uploadPackV2Setup(null, null, hook, PacketLineIn.END); PacketLineIn pckIn = new PacketLineIn(recvStream); + assertThat(hook.capabilitiesRequest, notNullValue()); assertThat(pckIn.readString(), is("version 2")); assertThat( Arrays.asList(pckIn.readString(), pckIn.readString()), @@ -413,7 +519,7 @@ public class UploadPackTest { public void testV2CapabilitiesAllowFilter() throws Exception { server.getConfig().setBoolean("uploadpack", null, "allowfilter", true); ByteArrayInputStream recvStream = - uploadPackV2Setup(null, null, PacketLineIn.END); + uploadPackV2Setup(null, null, null, PacketLineIn.END); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("version 2")); @@ -426,6 +532,51 @@ public class UploadPackTest { } @Test + public void testV2CapabilitiesRefInWant() throws Exception { + server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true); + ByteArrayInputStream recvStream = + uploadPackV2Setup(null, null, null, PacketLineIn.END); + PacketLineIn pckIn = new PacketLineIn(recvStream); + + assertThat(pckIn.readString(), is("version 2")); + assertThat( + Arrays.asList(pckIn.readString(), pckIn.readString()), + // TODO(jonathantanmy) This check overspecifies the + // order of the capabilities of "fetch". + hasItems("ls-refs", "fetch=ref-in-want shallow")); + assertTrue(pckIn.readString() == PacketLineIn.END); + } + + @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); + + assertThat(pckIn.readString(), is("version 2")); + assertThat( + Arrays.asList(pckIn.readString(), pckIn.readString()), + hasItems("ls-refs", "fetch=shallow")); + assertTrue(pckIn.readString() == PacketLineIn.END); + } + + @Test + public void testV2CapabilitiesRefInWantNotAdvertisedIfAdvertisingForbidden() throws Exception { + server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true); + server.getConfig().setBoolean("uploadpack", null, "advertiserefinwant", false); + ByteArrayInputStream recvStream = + uploadPackV2Setup(null, null, null, PacketLineIn.END); + PacketLineIn pckIn = new PacketLineIn(recvStream); + + assertThat(pckIn.readString(), is("version 2")); + assertThat( + Arrays.asList(pckIn.readString(), pckIn.readString()), + hasItems("ls-refs", "fetch=shallow")); + assertTrue(pckIn.readString() == PacketLineIn.END); + } + + @Test @SuppressWarnings("boxing") public void testV2EmptyRequest() throws Exception { ByteArrayInputStream recvStream = uploadPackV2(PacketLineIn.END); @@ -442,9 +593,12 @@ public class UploadPackTest { RevTag tag = remote.tag("tag", tip); remote.update("refs/tags/tag", tag); - ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n", PacketLineIn.END); + TestV2Hook hook = new TestV2Hook(); + ByteArrayInputStream recvStream = uploadPackV2(null, null, hook, + "command=ls-refs\n", PacketLineIn.END); PacketLineIn pckIn = new PacketLineIn(recvStream); + assertThat(hook.lsRefsRequest, notNullValue()); assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD")); assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master")); assertThat(pckIn.readString(), is(tag.toObjectId().getName() + " refs/tags/tag")); @@ -579,6 +733,10 @@ public class UploadPackTest { new StringWriter(), NullOutputStream.INSTANCE); PackParser pp = client.newObjectInserter().newPackParser(sb); pp.parse(NullProgressMonitor.INSTANCE); + + // Ensure that there is nothing left in the stream. + assertThat(recvStream.read(), is(-1)); + return pp.getReceivedPackStatistics(); } @@ -592,6 +750,7 @@ public class UploadPackTest { uploadPackV2( RequestPolicy.ADVERTISED, null, + null, "command=fetch\n", PacketLineIn.DELIM, "want " + advertized.name() + "\n", @@ -604,6 +763,7 @@ public class UploadPackTest { uploadPackV2( RequestPolicy.ADVERTISED, null, + null, "command=fetch\n", PacketLineIn.DELIM, "want " + unadvertized.name() + "\n", @@ -621,6 +781,7 @@ public class UploadPackTest { uploadPackV2( RequestPolicy.REACHABLE_COMMIT, null, + null, "command=fetch\n", PacketLineIn.DELIM, "want " + reachable.name() + "\n", @@ -633,6 +794,7 @@ public class UploadPackTest { uploadPackV2( RequestPolicy.REACHABLE_COMMIT, null, + null, "command=fetch\n", PacketLineIn.DELIM, "want " + unreachable.name() + "\n", @@ -649,6 +811,7 @@ public class UploadPackTest { uploadPackV2( RequestPolicy.TIP, new RejectAllRefFilter(), + null, "command=fetch\n", PacketLineIn.DELIM, "want " + tip.name() + "\n", @@ -661,6 +824,7 @@ public class UploadPackTest { uploadPackV2( RequestPolicy.TIP, new RejectAllRefFilter(), + null, "command=fetch\n", PacketLineIn.DELIM, "want " + parentOfTip.name() + "\n", @@ -678,6 +842,7 @@ public class UploadPackTest { uploadPackV2( RequestPolicy.REACHABLE_COMMIT_TIP, new RejectAllRefFilter(), + null, "command=fetch\n", PacketLineIn.DELIM, "want " + parentOfTip.name() + "\n", @@ -690,6 +855,7 @@ public class UploadPackTest { uploadPackV2( RequestPolicy.REACHABLE_COMMIT_TIP, new RejectAllRefFilter(), + null, "command=fetch\n", PacketLineIn.DELIM, "want " + unreachable.name() + "\n", @@ -704,6 +870,7 @@ public class UploadPackTest { uploadPackV2( RequestPolicy.ANY, null, + null, "command=fetch\n", PacketLineIn.DELIM, "want " + unreachable.name() + "\n", @@ -1078,6 +1245,178 @@ public class UploadPackTest { PacketLineIn.END); } + @Test + public void testV2FetchWantRefIfNotAllowed() throws Exception { + RevCommit one = remote.commit().message("1").create(); + remote.update("one", one); + + try { + uploadPackV2( + "command=fetch\n", + PacketLineIn.DELIM, + "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 testV2FetchWantRef() throws Exception { + RevCommit one = remote.commit().message("1").create(); + RevCommit two = remote.commit().message("2").create(); + RevCommit three = remote.commit().message("3").create(); + remote.update("one", one); + remote.update("two", two); + remote.update("three", three); + + server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true); + + ByteArrayInputStream recvStream = uploadPackV2( + "command=fetch\n", + PacketLineIn.DELIM, + "want-ref refs/heads/one\n", + "want-ref refs/heads/two\n", + "done\n", + PacketLineIn.END); + PacketLineIn pckIn = new PacketLineIn(recvStream); + assertThat(pckIn.readString(), is("wanted-refs")); + assertThat( + Arrays.asList(pckIn.readString(), pckIn.readString()), + hasItems( + one.toObjectId().getName() + " refs/heads/one", + two.toObjectId().getName() + " refs/heads/two")); + assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertThat(pckIn.readString(), is("packfile")); + parsePack(recvStream); + + assertTrue(client.hasObject(one.toObjectId())); + assertTrue(client.hasObject(two.toObjectId())); + assertFalse(client.hasObject(three.toObjectId())); + } + + @Test + public void testV2FetchBadWantRef() throws Exception { + RevCommit one = remote.commit().message("1").create(); + remote.update("one", one); + + server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true); + + try { + uploadPackV2( + "command=fetch\n", + PacketLineIn.DELIM, + "want-ref refs/heads/one\n", + "want-ref refs/heads/nonExistentRef\n", + "done\n", + PacketLineIn.END); + } catch (PackProtocolException e) { + assertThat( + e.getMessage(), + containsString("Invalid ref name: refs/heads/nonExistentRef")); + return; + } + fail("expected PackProtocolException"); + } + + @Test + public void testV2FetchMixedWantRef() throws Exception { + RevCommit one = remote.commit().message("1").create(); + RevCommit two = remote.commit().message("2").create(); + RevCommit three = remote.commit().message("3").create(); + remote.update("one", one); + remote.update("two", two); + remote.update("three", three); + + server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true); + + ByteArrayInputStream recvStream = uploadPackV2( + "command=fetch\n", + PacketLineIn.DELIM, + "want-ref refs/heads/one\n", + "want " + two.toObjectId().getName() + "\n", + "done\n", + PacketLineIn.END); + PacketLineIn pckIn = new PacketLineIn(recvStream); + assertThat(pckIn.readString(), is("wanted-refs")); + assertThat( + pckIn.readString(), + is(one.toObjectId().getName() + " refs/heads/one")); + assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertThat(pckIn.readString(), is("packfile")); + parsePack(recvStream); + + assertTrue(client.hasObject(one.toObjectId())); + assertTrue(client.hasObject(two.toObjectId())); + assertFalse(client.hasObject(three.toObjectId())); + } + + @Test + public void testV2FetchWantRefWeAlreadyHave() throws Exception { + RevCommit one = remote.commit().message("1").create(); + remote.update("one", one); + + server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true); + + ByteArrayInputStream recvStream = uploadPackV2( + "command=fetch\n", + PacketLineIn.DELIM, + "want-ref refs/heads/one\n", + "have " + one.toObjectId().getName(), + "done\n", + PacketLineIn.END); + PacketLineIn pckIn = new PacketLineIn(recvStream); + + // The client still needs to know the hash of the object that + // refs/heads/one points to, even though it already has the + // object ... + assertThat(pckIn.readString(), is("wanted-refs")); + assertThat( + pckIn.readString(), + is(one.toObjectId().getName() + " refs/heads/one")); + assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + + // ... but the client does not need the object itself. + assertThat(pckIn.readString(), is("packfile")); + parsePack(recvStream); + assertFalse(client.hasObject(one.toObjectId())); + } + + @Test + public void testV2FetchWantRefAndDeepen() throws Exception { + RevCommit parent = remote.commit().message("parent").create(); + RevCommit child = remote.commit().message("x").parent(parent).create(); + remote.update("branch1", child); + + server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true); + + ByteArrayInputStream recvStream = uploadPackV2( + "command=fetch\n", + PacketLineIn.DELIM, + "want-ref refs/heads/branch1\n", + "deepen 1\n", + "done\n", + PacketLineIn.END); + PacketLineIn pckIn = new PacketLineIn(recvStream); + + // shallow-info appears first, then wanted-refs. + assertThat(pckIn.readString(), is("shallow-info")); + assertThat(pckIn.readString(), is("shallow " + child.toObjectId().getName())); + assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertThat(pckIn.readString(), is("wanted-refs")); + assertThat(pckIn.readString(), is(child.toObjectId().getName() + " refs/heads/branch1")); + assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertThat(pckIn.readString(), is("packfile")); + parsePack(recvStream); + assertTrue(client.hasObject(child.toObjectId())); + assertFalse(client.hasObject(parent.toObjectId())); + } + private static class RejectAllRefFilter implements RefFilter { @Override public Map<String, Ref> filter(Map<String, Ref> refs) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java index 0e009b9540..e031678339 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java @@ -331,7 +331,7 @@ public class FileTreeIteratorTest extends RepositoryTestCase { DirCacheEntry dce = db.readDirCache().getEntry("symlink"); dce.setFileMode(FileMode.SYMLINK); try (ObjectReader objectReader = db.newObjectReader()) { - DirCacheCheckout.checkoutEntry(db, dce, objectReader); + DirCacheCheckout.checkoutEntry(db, dce, objectReader, false, null); FileTreeIterator fti = new FileTreeIterator(trash, db.getFS(), db.getConfig().get(WorkingTreeOptions.KEY)); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java index 71a2f327c8..15d03d38e7 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java @@ -231,8 +231,8 @@ public class PathFilterGroupTest { } } - String[] e = expect.toArray(new String[expect.size()]); - String[] a = actual.toArray(new String[actual.size()]); + String[] e = expect.toArray(new String[0]); + String[] a = actual.toArray(new String[0]); Arrays.sort(e); Arrays.sort(a); assertArrayEquals(e, a); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FilterCommandsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FilterCommandsTest.java index 0d31811257..8dfdd0fc7c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FilterCommandsTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FilterCommandsTest.java @@ -85,6 +85,8 @@ public class FilterCommandsTest extends RepositoryTestCase { public int run() throws IOException { int b = in.read(); if (b == -1) { + in.close(); + out.close(); return b; } out.write(prefix); |