diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmoduleSectionParserIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmoduleSectionParserIT.java new file mode 100644 index 0000000000..3ef02ff7b6 --- /dev/null +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmoduleSectionParserIT.java @@ -0,0 +1,365 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.acceptance.git; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.Sets; +import com.google.gerrit.acceptance.AbstractDaemonTest; +import com.google.gerrit.reviewdb.client.Branch; +import com.google.gerrit.reviewdb.client.Project; +import com.google.gerrit.reviewdb.client.SubmoduleSubscription; +import com.google.gerrit.server.util.SubmoduleSectionParser; + +import org.eclipse.jgit.lib.Config; +import org.junit.Test; + +import java.util.Set; + +public class SubmoduleSectionParserIT extends AbstractDaemonTest { + private static final String THIS_SERVER = "localhost"; + + @Test + public void testFollowMasterBranch() throws Exception { + Project.NameKey p = createProject("a"); + Config cfg = new Config(); + cfg.fromText("" + + "[submodule \"a\"]\n" + + "path = localpath-to-a\n" + + "url = ssh://localhost/" + p.get() + "\n" + + "branch = master\n"); + Branch.NameKey targetBranch = new Branch.NameKey( + new Project.NameKey("project"), "master"); + + Set res = new SubmoduleSectionParser(projectCache, + cfg, THIS_SERVER, targetBranch).parseAllSections(); + + Set expected = Sets.newHashSet( + new SubmoduleSubscription(targetBranch, new Branch.NameKey( + p, "master"), "localpath-to-a")); + + assertThat(res).containsExactlyElementsIn(expected); + } + + @Test + public void testFollowMatchingBranch() throws Exception { + Project.NameKey p = createProject("a"); + Config cfg = new Config(); + cfg.fromText("" + + "[submodule \"a\"]\n" + + "path = a\n" + + "url = ssh://localhost/" + p.get() + "\n" + + "branch = .\n"); + + Branch.NameKey targetBranch1 = new Branch.NameKey( + new Project.NameKey("project"), "master"); + + Set res1 = new SubmoduleSectionParser(projectCache, + cfg, THIS_SERVER, targetBranch1).parseAllSections(); + + Set expected1 = Sets.newHashSet( + new SubmoduleSubscription(targetBranch1, new Branch.NameKey( + p, "master"), "a")); + + assertThat(res1).containsExactlyElementsIn(expected1); + + Branch.NameKey targetBranch2 = new Branch.NameKey( + new Project.NameKey("project"), "somebranch"); + + Set res2 = new SubmoduleSectionParser(projectCache, + cfg, THIS_SERVER, targetBranch2).parseAllSections(); + + Set expected2 = Sets.newHashSet( + new SubmoduleSubscription(targetBranch2, new Branch.NameKey( + p, "somebranch"), "a")); + + assertThat(res2).containsExactlyElementsIn(expected2); + } + + @Test + public void testFollowAnotherBranch() throws Exception { + Project.NameKey p = createProject("a"); + Config cfg = new Config(); + cfg.fromText("" + + "[submodule \"a\"]\n" + + "path = a\n" + + "url = ssh://localhost/" + p.get() + "\n" + + "branch = anotherbranch\n"); + + Branch.NameKey targetBranch = new Branch.NameKey( + new Project.NameKey("project"), "master"); + + Set res = new SubmoduleSectionParser(projectCache, + cfg, THIS_SERVER, targetBranch).parseAllSections(); + + Set expected = Sets.newHashSet( + new SubmoduleSubscription(targetBranch, new Branch.NameKey( + p, "anotherbranch"), "a")); + + assertThat(res).containsExactlyElementsIn(expected); + } + + @Test + public void testWithAnotherURI() throws Exception { + Project.NameKey p = createProject("a"); + Config cfg = new Config(); + cfg.fromText("" + + "[submodule \"a\"]\n" + + "path = a\n" + + "url = http://localhost:80/" + p.get() + "\n" + + "branch = master\n"); + + Branch.NameKey targetBranch = new Branch.NameKey( + new Project.NameKey("project"), "master"); + + Set res =new SubmoduleSectionParser(projectCache, + cfg, THIS_SERVER, targetBranch).parseAllSections(); + + Set expected = Sets.newHashSet( + new SubmoduleSubscription(targetBranch, new Branch.NameKey( + p, "master"), "a")); + + assertThat(res).containsExactlyElementsIn(expected); + } + + @Test + public void testWithSlashesInProjectName() throws Exception { + Project.NameKey p = createProject("project/with/slashes/a"); + Config cfg = new Config(); + cfg.fromText("" + + "[submodule \"project/with/slashes/a\"]\n" + + "path = a\n" + + "url = http://localhost:80/" + p.get() + "\n" + + "branch = master\n"); + + Branch.NameKey targetBranch = new Branch.NameKey( + new Project.NameKey("project"), "master"); + + Set res = new SubmoduleSectionParser(projectCache, + cfg, THIS_SERVER, targetBranch).parseAllSections(); + + Set expected = Sets.newHashSet( + new SubmoduleSubscription(targetBranch, new Branch.NameKey( + p, "master"), "a")); + + assertThat(res).containsExactlyElementsIn(expected); + } + + @Test + public void testWithSlashesInPath() throws Exception { + Project.NameKey p = createProject("a"); + Config cfg = new Config(); + cfg.fromText("" + + "[submodule \"a\"]\n" + + "path = a/b/c/d/e\n" + + "url = http://localhost:80/" + p.get() + "\n" + + "branch = master\n"); + + Branch.NameKey targetBranch = new Branch.NameKey( + new Project.NameKey("project"), "master"); + + Set res = new SubmoduleSectionParser(projectCache, + cfg, THIS_SERVER, targetBranch).parseAllSections(); + + Set expected = Sets.newHashSet( + new SubmoduleSubscription(targetBranch, new Branch.NameKey( + p, "master"), "a/b/c/d/e")); + + assertThat(res).containsExactlyElementsIn(expected); + } + + @Test + public void testWithMoreSections() throws Exception { + Project.NameKey p1 = createProject("a"); + Project.NameKey p2 = createProject("b"); + Config cfg = new Config(); + cfg.fromText("" + + "[submodule \"a\"]\n" + + " path = a\n" + + " url = ssh://localhost/" + p1.get() + "\n" + + " branch = .\n" + + "[submodule \"b\"]\n" + + " path = b\n" + + " url = http://localhost:80/" + p2.get() + "\n" + + " branch = master\n"); + + Branch.NameKey targetBranch = new Branch.NameKey( + new Project.NameKey("project"), "master"); + Set res = new SubmoduleSectionParser(projectCache, + cfg, THIS_SERVER, targetBranch).parseAllSections(); + + Set expected = Sets.newHashSet( + new SubmoduleSubscription(targetBranch, new Branch.NameKey( + p1, "master"), "a"), + new SubmoduleSubscription(targetBranch, new Branch.NameKey( + p2, "master"), "b")); + + assertThat(res).containsExactlyElementsIn(expected); + } + + @Test + public void testWithSubProjectFound() throws Exception { + Project.NameKey p1 = createProject("a/b"); + Project.NameKey p2 = createProject("b"); + Config cfg = new Config(); + cfg.fromText("\n" + + "[submodule \"a/b\"]\n" + + "path = a/b\n" + + "url = ssh://localhost/" + p1.get() + "\n" + + "branch = .\n" + + "[submodule \"b\"]\n" + + "path = b\n" + + "url = http://localhost/" + p2.get() + "\n" + + "branch = .\n"); + + Branch.NameKey targetBranch = new Branch.NameKey( + new Project.NameKey("project"), "master"); + Set res = new SubmoduleSectionParser(projectCache, + cfg, THIS_SERVER, targetBranch).parseAllSections(); + + Set expected = Sets.newHashSet( + new SubmoduleSubscription(targetBranch, new Branch.NameKey( + p2, "master"), "b"), + new SubmoduleSubscription(targetBranch, new Branch.NameKey( + p1, "master"), "a/b")); + + assertThat(res).containsExactlyElementsIn(expected); + } + + @Test + public void testWithAnInvalidSection() throws Exception { + Project.NameKey p1 = createProject("a"); + Project.NameKey p2 = createProject("b"); + Project.NameKey p3 = createProject("d"); + Project.NameKey p4 = createProject("e"); + Config cfg = new Config(); + cfg.fromText("\n" + + "[submodule \"a\"]\n" + + " path = a\n" + + " url = ssh://localhost/" + p1.get() + "\n" + + " branch = .\n" + + "[submodule \"b\"]\n" + // path missing + + " url = http://localhost:80/" + p2.get() + "\n" + + " branch = master\n" + + "[submodule \"c\"]\n" + + " path = c\n" + // url missing + + " branch = .\n" + + "[submodule \"d\"]\n" + + " path = d-parent/the-d-folder\n" + + " url = ssh://localhost/" + p3.get() + "\n" + // branch missing + + "[submodule \"e\"]\n" + + " path = e\n" + + " url = ssh://localhost/" + p4.get() + "\n" + + " branch = refs/heads/master\n"); + + Branch.NameKey targetBranch = new Branch.NameKey( + new Project.NameKey("project"), "master"); + Set res = new SubmoduleSectionParser(projectCache, + cfg, THIS_SERVER, targetBranch).parseAllSections(); + + Set expected = Sets.newHashSet( + new SubmoduleSubscription(targetBranch, new Branch.NameKey( + p1, "master"), "a"), + new SubmoduleSubscription(targetBranch, new Branch.NameKey( + p4, "master"), "e")); + + assertThat(res).containsExactlyElementsIn(expected); + } + + @Test + public void testWithSectionOfNonexistingProject() throws Exception { + Config cfg = new Config(); + cfg.fromText("\n" + + "[submodule \"a\"]\n" + + "path = a\n" + + "url = ssh://non-localhost/a\n" + // Project "a" doesn't exist + + "branch = .\\n"); + + Branch.NameKey targetBranch = new Branch.NameKey( + new Project.NameKey("project"), "master"); + Set res = new SubmoduleSectionParser(projectCache, + cfg, THIS_SERVER, targetBranch).parseAllSections(); + + assertThat(res).isEmpty(); + } + + @Test + public void testWithSectionToOtherServer() throws Exception { + Project.NameKey p1 = createProject("a"); + Config cfg = new Config(); + cfg.fromText("" + + "[submodule \"a\"]" + + "path = a" + + "url = ssh://non-localhost/" + p1.get() + "\n" + + "branch = ."); + + Branch.NameKey targetBranch = new Branch.NameKey( + new Project.NameKey("project"), "master"); + Set res = new SubmoduleSectionParser(projectCache, + cfg, THIS_SERVER, targetBranch).parseAllSections(); + + assertThat(res).isEmpty(); + } + + @Test + public void testWithRelativeURI() throws Exception { + Project.NameKey p1 = createProject("a"); + Config cfg = new Config(); + cfg.fromText("" + + "[submodule \"a\"]\n" + + "path = a\n" + + "url = ../" + p1.get() + "\n" + + "branch = master\n"); + + Branch.NameKey targetBranch = new Branch.NameKey( + new Project.NameKey("project"), "master"); + + Set res = new SubmoduleSectionParser(projectCache, + cfg, THIS_SERVER, targetBranch).parseAllSections(); + + Set expected = Sets.newHashSet( + new SubmoduleSubscription(targetBranch, new Branch.NameKey( + p1, "master"), "a")); + + assertThat(res).containsExactlyElementsIn(expected); + } + + @Test + public void testWithDeepRelativeURI() throws Exception { + Project.NameKey p1 = createProject("a"); + Config cfg = new Config(); + cfg.fromText("" + + "[submodule \"a\"]\n" + + "path = a\n" + + "url = ../../" + p1.get() + "\n" + + "branch = master\n"); + + Branch.NameKey targetBranch = new Branch.NameKey( + new Project.NameKey("nested/project"), "master"); + + Set res = new SubmoduleSectionParser(projectCache, + cfg, THIS_SERVER, targetBranch).parseAllSections(); + + Set expected = Sets.newHashSet( + new SubmoduleSubscription(targetBranch, new Branch.NameKey( + p1, "master"), "a")); + + assertThat(res).containsExactlyElementsIn(expected); + } +} diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java deleted file mode 100644 index ba62cf7b39..0000000000 --- a/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright (C) 2011 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package com.google.gerrit.server.util; - -import static org.easymock.EasyMock.createNiceMock; -import static org.easymock.EasyMock.createStrictMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.verify; -import static org.junit.Assert.assertEquals; - -import com.google.gerrit.reviewdb.client.Branch; -import com.google.gerrit.reviewdb.client.Project; -import com.google.gerrit.reviewdb.client.SubmoduleSubscription; -import com.google.gerrit.server.project.ProjectCache; -import com.google.gerrit.server.project.ProjectState; - -import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; -import org.eclipse.jgit.lib.BlobBasedConfig; -import org.eclipse.jgit.lib.Constants; -import org.junit.Before; -import org.junit.Test; - -import java.net.URI; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - -public class SubmoduleSectionParserTest extends LocalDiskRepositoryTestCase { - private static final String THIS_SERVER = "localhost"; - private ProjectCache projectCache; - private BlobBasedConfig bbc; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - - projectCache = createStrictMock(ProjectCache.class); - bbc = createStrictMock(BlobBasedConfig.class); - } - - private void doReplay() { - replay(projectCache, bbc); - } - - private void doVerify() { - verify(projectCache, bbc); - } - - @Test - public void testSubmodulesParseWithCorrectSections() throws Exception { - final Map sectionsToReturn = new TreeMap<>(); - sectionsToReturn.put("a", new SubmoduleSection("ssh://localhost/a", "a", - ".")); - sectionsToReturn.put("b", new SubmoduleSection("ssh://localhost/b", "b", - ".")); - sectionsToReturn.put("c", new SubmoduleSection("ssh://localhost/test/c", - "c-path", "refs/heads/master")); - sectionsToReturn.put("d", new SubmoduleSection("ssh://localhost/d", - "d-parent/the-d-folder", "refs/heads/test")); - sectionsToReturn.put("e", new SubmoduleSection("ssh://localhost/e.git", "e", - ".")); - - Map reposToBeFound = new HashMap<>(); - reposToBeFound.put("a", "a"); - reposToBeFound.put("b", "b"); - reposToBeFound.put("c", "test/c"); - reposToBeFound.put("d", "d"); - reposToBeFound.put("e", "e"); - - final Branch.NameKey superBranchNameKey = - new Branch.NameKey(new Project.NameKey("super-project"), - "refs/heads/master"); - - Set expectedSubscriptions = new HashSet<>(); - expectedSubscriptions - .add(new SubmoduleSubscription(superBranchNameKey, new Branch.NameKey( - new Project.NameKey("a"), "refs/heads/master"), "a")); - expectedSubscriptions - .add(new SubmoduleSubscription(superBranchNameKey, new Branch.NameKey( - new Project.NameKey("b"), "refs/heads/master"), "b")); - expectedSubscriptions.add(new SubmoduleSubscription(superBranchNameKey, - new Branch.NameKey(new Project.NameKey("test/c"), "refs/heads/master"), - "c-path")); - expectedSubscriptions.add(new SubmoduleSubscription(superBranchNameKey, - new Branch.NameKey(new Project.NameKey("d"), "refs/heads/test"), - "d-parent/the-d-folder")); - expectedSubscriptions - .add(new SubmoduleSubscription(superBranchNameKey, new Branch.NameKey( - new Project.NameKey("e"), "refs/heads/master"), "e")); - - execute(superBranchNameKey, sectionsToReturn, reposToBeFound, - expectedSubscriptions); - } - - @Test - public void testSubmodulesParseWithAnInvalidSection() throws Exception { - final Map sectionsToReturn = new TreeMap<>(); - sectionsToReturn.put("a", new SubmoduleSection("ssh://localhost/a", "a", - ".")); - // This one is invalid since "b" is not a recognized project - sectionsToReturn.put("b", new SubmoduleSection("ssh://localhost/b", "b", - ".")); - sectionsToReturn.put("c", new SubmoduleSection("ssh://localhost/test/c", - "c-path", "refs/heads/master")); - sectionsToReturn.put("d", new SubmoduleSection("ssh://localhost/d", - "d-parent/the-d-folder", "refs/heads/test")); - sectionsToReturn.put("e", new SubmoduleSection("ssh://localhost/e.git", "e", - ".")); - - // "b" will not be in this list - Map reposToBeFound = new HashMap<>(); - reposToBeFound.put("a", "a"); - reposToBeFound.put("c", "test/c"); - reposToBeFound.put("d", "d"); - reposToBeFound.put("e", "e"); - - final Branch.NameKey superBranchNameKey = - new Branch.NameKey(new Project.NameKey("super-project"), - "refs/heads/master"); - - Set expectedSubscriptions = new HashSet<>(); - expectedSubscriptions - .add(new SubmoduleSubscription(superBranchNameKey, new Branch.NameKey( - new Project.NameKey("a"), "refs/heads/master"), "a")); - expectedSubscriptions.add(new SubmoduleSubscription(superBranchNameKey, - new Branch.NameKey(new Project.NameKey("test/c"), "refs/heads/master"), - "c-path")); - expectedSubscriptions.add(new SubmoduleSubscription(superBranchNameKey, - new Branch.NameKey(new Project.NameKey("d"), "refs/heads/test"), - "d-parent/the-d-folder")); - expectedSubscriptions - .add(new SubmoduleSubscription(superBranchNameKey, new Branch.NameKey( - new Project.NameKey("e"), "refs/heads/master"), "e")); - - execute(superBranchNameKey, sectionsToReturn, reposToBeFound, - expectedSubscriptions); - } - - @Test - public void testSubmoduleSectionToOtherServer() throws Exception { - Map sectionsToReturn = new HashMap<>(); - // The url is not to this server. - sectionsToReturn.put("a", new SubmoduleSection("ssh://review.source.com/a", - "a", ".")); - - Set expectedSubscriptions = Collections.emptySet(); - execute(new Branch.NameKey(new Project.NameKey("super-project"), - "refs/heads/master"), sectionsToReturn, new HashMap(), - expectedSubscriptions); - } - - @Test - public void testProjectNotFound() throws Exception { - Map sectionsToReturn = new HashMap<>(); - sectionsToReturn.put("a", new SubmoduleSection("ssh://localhost/a", "a", - ".")); - - Set expectedSubscriptions = Collections.emptySet(); - execute(new Branch.NameKey(new Project.NameKey("super-project"), - "refs/heads/master"), sectionsToReturn, new HashMap(), - expectedSubscriptions); - } - - @Test - public void testProjectWithSlashesNotFound() throws Exception { - Map sectionsToReturn = new HashMap<>(); - sectionsToReturn.put("project", new SubmoduleSection( - "ssh://localhost/company/tools/project", "project", ".")); - - Set expectedSubscriptions = Collections.emptySet(); - execute(new Branch.NameKey(new Project.NameKey("super-project"), - "refs/heads/master"), sectionsToReturn, new HashMap(), - expectedSubscriptions); - } - - @Test - public void testSubmodulesParseWithSubProjectFound() throws Exception { - Map sectionsToReturn = new TreeMap<>(); - sectionsToReturn.put("a/b", new SubmoduleSection( - "ssh://localhost/a/b", "a/b", ".")); - - Map reposToBeFound = new HashMap<>(); - reposToBeFound.put("a/b", "a/b"); - reposToBeFound.put("b", "b"); - - Branch.NameKey superBranchNameKey = - new Branch.NameKey(new Project.NameKey("super-project"), - "refs/heads/master"); - - Set expectedSubscriptions = new HashSet<>(); - expectedSubscriptions - .add(new SubmoduleSubscription(superBranchNameKey, new Branch.NameKey( - new Project.NameKey("a/b"), "refs/heads/master"), "a/b")); - execute(superBranchNameKey, sectionsToReturn, reposToBeFound, - expectedSubscriptions); - } - - private void execute(final Branch.NameKey superProjectBranch, - final Map sectionsToReturn, - final Map reposToBeFound, - final Set expectedSubscriptions) throws Exception { - expect(bbc.getSubsections("submodule")) - .andReturn(sectionsToReturn.keySet()); - - for (Map.Entry entry : sectionsToReturn.entrySet()) { - String id = entry.getKey(); - final SubmoduleSection section = entry.getValue(); - expect(bbc.getString("submodule", id, "url")).andReturn(section.getUrl()); - expect(bbc.getString("submodule", id, "path")).andReturn( - section.getPath()); - expect(bbc.getString("submodule", id, "branch")).andReturn( - section.getBranch()); - - if (THIS_SERVER.equals(new URI(section.getUrl()).getHost())) { - String projectNameCandidate; - final String urlExtractedPath = new URI(section.getUrl()).getPath(); - int fromIndex = urlExtractedPath.length() - 1; - while (fromIndex > 0) { - fromIndex = urlExtractedPath.lastIndexOf('/', fromIndex - 1); - projectNameCandidate = urlExtractedPath.substring(fromIndex + 1); - if (projectNameCandidate.endsWith(Constants.DOT_GIT_EXT)) { - projectNameCandidate = projectNameCandidate.substring(0, // - projectNameCandidate.length() - Constants.DOT_GIT_EXT.length()); - } - if (reposToBeFound.containsValue(projectNameCandidate)) { - expect(projectCache.get(new Project.NameKey(projectNameCandidate))) - .andReturn(createNiceMock(ProjectState.class)); - } else { - expect(projectCache.get(new Project.NameKey(projectNameCandidate))) - .andReturn(null); - } - } - } - } - - doReplay(); - - final SubmoduleSectionParser ssp = - new SubmoduleSectionParser(projectCache, bbc, THIS_SERVER, - superProjectBranch); - - Set returnedSubscriptions = ssp.parseAllSections(); - - doVerify(); - - assertEquals(expectedSubscriptions, returnedSubscriptions); - } - - private static final class SubmoduleSection { - private final String url; - private final String path; - private final String branch; - - SubmoduleSection(final String url, final String path, - final String branch) { - this.url = url; - this.path = path; - this.branch = branch; - } - - public String getUrl() { - return url; - } - - public String getPath() { - return path; - } - - public String getBranch() { - return branch; - } - } -}