Merge branch 'stable-3.5' into stable-3.6 * stable-3.5: Add JGit client test for unset mirror Add mirror replication option for CGit client Change-Id: I2ee7ccd772ca50bd650329cb6da7a6973d3f3569
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/fetch/CGitFetch.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/fetch/CGitFetch.java index d3e45da..43ec9bf 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/fetch/CGitFetch.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/fetch/CGitFetch.java
@@ -44,6 +44,7 @@ private URIish uri; private int timeout; private final String taskIdHex; + private final boolean isMirror; @Inject public CGitFetch( @@ -56,12 +57,17 @@ this.taskIdHex = taskIdHex; this.uri = appendCredentials(uri, cpFactory.create(config.getRemoteConfig().getName())); this.timeout = config.getRemoteConfig().getTimeout(); + this.isMirror = config.getRemoteConfig().isMirror(); } @Override public List<RefUpdateState> fetch(List<RefSpec> refsSpec) throws IOException { List<String> refs = refsSpec.stream().map(s -> s.toString()).collect(Collectors.toList()); - List<String> command = Lists.newArrayList("git", "fetch", uri.toPrivateASCIIString()); + List<String> command = Lists.newArrayList("git", "fetch"); + if (isMirror) { + command.add("--prune"); + } + command.add(uri.toPrivateASCIIString()); command.addAll(refs); ProcessBuilder pb = new ProcessBuilder().command(command).directory(localProjectDirectory); repLog.info("[{}] Fetch references {} from {}", taskIdHex, refs, uri);
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md index b7db2c0..61d62b4 100644 --- a/src/main/resources/Documentation/config.md +++ b/src/main/resources/Documentation/config.md
@@ -526,8 +526,7 @@ remote.NAME.mirror : If true, replication will remove local branches and tags that are absent remotely or invisible to the replication (for example read access -denied via `authGroup` option). Note that this option is currently -implemented for the JGit client only. +denied via `authGroup` option). By default, false, do not remove remote branches or tags.
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/CGitFetchIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/CGitFetchIT.java index baacf20..3ca937c 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/CGitFetchIT.java +++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/CGitFetchIT.java
@@ -15,6 +15,9 @@ package com.googlesource.gerrit.plugins.replication.pull; import static com.google.common.truth.Truth.assertThat; +import static com.google.gerrit.acceptance.GitUtil.deleteRef; +import static com.google.gerrit.acceptance.GitUtil.pushHead; +import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow; import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -22,35 +25,33 @@ import static org.mockito.Mockito.when; import com.google.common.collect.Lists; +import com.google.gerrit.acceptance.PushOneCommit; import com.google.gerrit.acceptance.PushOneCommit.Result; import com.google.gerrit.acceptance.SkipProjectClone; import com.google.gerrit.acceptance.TestPlugin; import com.google.gerrit.acceptance.UseLocalDisk; +import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; +import com.google.gerrit.entities.Permission; import com.google.gerrit.extensions.api.projects.BranchInput; -import com.google.gerrit.extensions.config.FactoryModule; -import com.google.inject.Scopes; -import com.google.inject.assistedinject.FactoryModuleBuilder; -import com.googlesource.gerrit.plugins.replication.AutoReloadSecureCredentialsFactoryDecorator; -import com.googlesource.gerrit.plugins.replication.CredentialsFactory; -import com.googlesource.gerrit.plugins.replication.ReplicationConfig; -import com.googlesource.gerrit.plugins.replication.ReplicationFileBasedConfig; +import com.google.inject.Inject; import com.googlesource.gerrit.plugins.replication.pull.fetch.BatchFetchClient; import com.googlesource.gerrit.plugins.replication.pull.fetch.CGitFetch; import com.googlesource.gerrit.plugins.replication.pull.fetch.Fetch; -import com.googlesource.gerrit.plugins.replication.pull.fetch.FetchClientImplementation; import com.googlesource.gerrit.plugins.replication.pull.fetch.FetchFactory; import com.googlesource.gerrit.plugins.replication.pull.fetch.RefUpdateState; -import java.net.URISyntaxException; import java.util.List; import org.eclipse.jgit.errors.TransportException; import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.transport.PushResult; import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.URIish; +import org.junit.Before; import org.junit.Test; @SkipProjectClone @@ -62,6 +63,16 @@ private static final String TEST_REPLICATION_SUFFIX = "suffix1"; private static final String TEST_TASK_ID = "taskid"; + @Inject private ProjectOperations projectOperations; + + @Before + public void allowRefDeletion() { + projectOperations + .allProjectsForUpdate() + .add(allow(Permission.DELETE).ref("refs/*").group(adminGroupUuid())) + .update(); + } + @Test public void shouldFetchRef() throws Exception { testRepo = cloneProject(createTestProject(project + TEST_REPLICATION_SUFFIX)); @@ -224,29 +235,55 @@ } } + @Test + public void shouldNotPruneRefsWhenMirrorIsUnset() throws Exception { + testRepo = cloneProject(createTestProject(project + TEST_REPLICATION_SUFFIX)); + String BRANCH_REF = Constants.R_HEADS + "anyBranch"; + String TAG_REF = Constants.R_TAGS + "anyTag"; + + PushOneCommit.Result branchPush = pushFactory.create(user.newIdent(), testRepo).to(BRANCH_REF); + branchPush.assertOkStatus(); + + PushResult tagPush = pushHead(testRepo, TAG_REF, false, false); + assertOkStatus(tagPush, TAG_REF); + + try (Repository localRepo = repoManager.openRepository(project)) { + fetchAllRefs(TEST_TASK_ID, testRepoPath, localRepo); + waitUntil( + () -> + checkedGetRef(localRepo, BRANCH_REF) != null + && checkedGetRef(localRepo, TAG_REF) != null); + assertThat(getRef(localRepo, BRANCH_REF)).isNotNull(); + assertThat(getRef(localRepo, TAG_REF)).isNotNull(); + + PushResult deleteBranchResult = deleteRef(testRepo, BRANCH_REF); + assertOkStatus(deleteBranchResult, BRANCH_REF); + + PushResult deleteTagResult = deleteRef(testRepo, TAG_REF); + assertOkStatus(deleteTagResult, TAG_REF); + + fetchAllRefs(TEST_TASK_ID, testRepoPath, localRepo); + waitUntil( + () -> + checkedGetRef(localRepo, BRANCH_REF) != null + && checkedGetRef(localRepo, TAG_REF) != null); + assertThat(getRef(localRepo, BRANCH_REF)).isNotNull(); + assertThat(getRef(localRepo, TAG_REF)).isNotNull(); + } + } + @SuppressWarnings("unused") - private static class TestModule extends FactoryModule { + private static class TestModule extends FetchModule<CGitFetch> { @Override - protected void configure() { + Class<CGitFetch> clientClass() { + return CGitFetch.class; + } + + @Override + Config cf() { Config cf = new Config(); cf.setInt("remote", "test_config", "timeout", 0); - try { - RemoteConfig remoteConfig = new RemoteConfig(cf, "test_config"); - SourceConfiguration sourceConfig = new SourceConfiguration(remoteConfig, cf); - bind(ReplicationConfig.class).to(ReplicationFileBasedConfig.class); - bind(CredentialsFactory.class) - .to(AutoReloadSecureCredentialsFactoryDecorator.class) - .in(Scopes.SINGLETON); - - bind(SourceConfiguration.class).toInstance(sourceConfig); - install( - new FactoryModuleBuilder() - .implement(Fetch.class, CGitFetch.class) - .implement(Fetch.class, FetchClientImplementation.class, CGitFetch.class) - .build(FetchFactory.class)); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } + return cf; } } }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/CGitFetchWithMirrorIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/CGitFetchWithMirrorIT.java new file mode 100644 index 0000000..8a3bae9 --- /dev/null +++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/CGitFetchWithMirrorIT.java
@@ -0,0 +1,108 @@ +// Copyright (C) 2023 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.googlesource.gerrit.plugins.replication.pull; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.gerrit.acceptance.GitUtil.deleteRef; +import static com.google.gerrit.acceptance.GitUtil.pushHead; +import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow; + +import com.google.gerrit.acceptance.PushOneCommit.Result; +import com.google.gerrit.acceptance.SkipProjectClone; +import com.google.gerrit.acceptance.TestPlugin; +import com.google.gerrit.acceptance.UseLocalDisk; +import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; +import com.google.gerrit.entities.Permission; +import com.google.inject.Inject; +import com.googlesource.gerrit.plugins.replication.pull.fetch.CGitFetch; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.transport.PushResult; +import org.junit.Before; +import org.junit.Test; + +@SkipProjectClone +@UseLocalDisk +@TestPlugin( + name = "pull-replication", + sysModule = "com.googlesource.gerrit.plugins.replication.pull.CGitFetchWithMirrorIT$TestModule") +public class CGitFetchWithMirrorIT extends FetchITBase { + private static final String TEST_REPLICATION_SUFFIX = "suffix1"; + private static final String TEST_TASK_ID = "taskid"; + + @Inject private ProjectOperations projectOperations; + + @Before + public void allowRefDeletion() { + projectOperations + .allProjectsForUpdate() + .add(allow(Permission.DELETE).ref("refs/*").group(adminGroupUuid())) + .update(); + } + + @Test + public void shouldPruneRefsWhenMirrorIsTrue() throws Exception { + testRepo = cloneProject(createTestProject(project + TEST_REPLICATION_SUFFIX)); + String BRANCH_REF = Constants.R_HEADS + "anyBranch"; + String TAG_REF = Constants.R_TAGS + "anyTag"; + + Result branchPush = pushFactory.create(user.newIdent(), testRepo).to(BRANCH_REF); + branchPush.assertOkStatus(); + + PushResult tagPush = pushHead(testRepo, TAG_REF, false, false); + assertOkStatus(tagPush, TAG_REF); + + try (Repository localRepo = repoManager.openRepository(project)) { + fetchAllRefs(TEST_TASK_ID, testRepoPath, localRepo); + waitUntil( + () -> + checkedGetRef(localRepo, BRANCH_REF) != null + && checkedGetRef(localRepo, TAG_REF) != null); + assertThat(getRef(localRepo, BRANCH_REF)).isNotNull(); + assertThat(getRef(localRepo, TAG_REF)).isNotNull(); + + PushResult deleteBranchResult = deleteRef(testRepo, BRANCH_REF); + assertOkStatus(deleteBranchResult, BRANCH_REF); + + PushResult deleteTagResult = deleteRef(testRepo, TAG_REF); + assertOkStatus(deleteTagResult, TAG_REF); + + fetchAllRefs(TEST_TASK_ID, testRepoPath, localRepo); + waitUntil( + () -> + checkedGetRef(localRepo, BRANCH_REF) == null + && checkedGetRef(localRepo, TAG_REF) == null); + assertThat(getRef(localRepo, BRANCH_REF)).isNull(); + assertThat(getRef(localRepo, TAG_REF)).isNull(); + } + } + + @SuppressWarnings("unused") + private static class TestModule extends FetchModule<CGitFetch> { + @Override + Class<CGitFetch> clientClass() { + return CGitFetch.class; + } + + @Override + Config cf() { + Config cf = new Config(); + cf.setInt("remote", "test_config", "timeout", 0); + cf.setBoolean("remote", "test_config", "mirror", true); + return cf; + } + } +}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FetchITBase.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FetchITBase.java index be9f902..3429983 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FetchITBase.java +++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FetchITBase.java
@@ -14,18 +14,39 @@ package com.googlesource.gerrit.plugins.replication.pull; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import com.google.common.collect.Lists; import com.google.common.flogger.FluentLogger; import com.google.gerrit.acceptance.LightweightPluginDaemonTest; import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; import com.google.gerrit.entities.Project; +import com.google.gerrit.extensions.config.FactoryModule; import com.google.gerrit.server.config.SitePaths; import com.google.inject.Inject; +import com.google.inject.Scopes; +import com.google.inject.assistedinject.FactoryModuleBuilder; +import com.googlesource.gerrit.plugins.replication.AutoReloadSecureCredentialsFactoryDecorator; +import com.googlesource.gerrit.plugins.replication.CredentialsFactory; +import com.googlesource.gerrit.plugins.replication.ReplicationConfig; +import com.googlesource.gerrit.plugins.replication.ReplicationFileBasedConfig; +import com.googlesource.gerrit.plugins.replication.pull.fetch.Fetch; +import com.googlesource.gerrit.plugins.replication.pull.fetch.FetchClientImplementation; import com.googlesource.gerrit.plugins.replication.pull.fetch.FetchFactory; +import java.io.IOException; +import java.net.URISyntaxException; import java.nio.file.Path; import java.time.Duration; import java.util.function.Supplier; +import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.transport.PushResult; +import org.eclipse.jgit.transport.RefSpec; +import org.eclipse.jgit.transport.RemoteConfig; +import org.eclipse.jgit.transport.RemoteRefUpdate; +import org.eclipse.jgit.transport.URIish; public abstract class FetchITBase extends LightweightPluginDaemonTest { private static final String TEST_REPLICATION_SUFFIX = "suffix1"; @@ -33,6 +54,7 @@ private static final int TEST_REPLICATION_DELAY = 60; private static final Duration TEST_TIMEOUT = Duration.ofSeconds(TEST_REPLICATION_DELAY * 2); + private static final RefSpec ALL_REFS = new RefSpec("+refs/*:refs/*"); @Inject private SitePaths sitePaths; @Inject private ProjectOperations projectOperations; @@ -66,7 +88,49 @@ } } + protected void fetchAllRefs(String taskId, Path remotePath, Repository localRepo) + throws URISyntaxException, IOException { + fetchFactory + .create(taskId, new URIish(remotePath.toString()), localRepo) + .fetch(Lists.newArrayList(ALL_REFS)); + } + + protected static void assertOkStatus(PushResult result, String ref) { + RemoteRefUpdate refUpdate = result.getRemoteUpdate(ref); + assertThat(refUpdate).isNotNull(); + assertWithMessage(refUpdate.getMessage()) + .that(refUpdate.getStatus()) + .isEqualTo(RemoteRefUpdate.Status.OK); + } + Project.NameKey createTestProject(String name) { return projectOperations.newProject().name(name).create(); } + + protected abstract static class FetchModule<T extends Fetch> extends FactoryModule { + abstract Config cf(); + + abstract Class<T> clientClass(); + + @Override + protected void configure() { + try { + RemoteConfig remoteConfig = new RemoteConfig(cf(), "test_config"); + SourceConfiguration sourceConfig = new SourceConfiguration(remoteConfig, cf()); + bind(ReplicationConfig.class).to(ReplicationFileBasedConfig.class); + bind(CredentialsFactory.class) + .to(AutoReloadSecureCredentialsFactoryDecorator.class) + .in(Scopes.SINGLETON); + + bind(SourceConfiguration.class).toInstance(sourceConfig); + install( + new FactoryModuleBuilder() + .implement(Fetch.class, clientClass()) + .implement(Fetch.class, FetchClientImplementation.class, clientClass()) + .build(FetchFactory.class)); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + } }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/JGitFetchIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/JGitFetchIT.java index 77cf80d..b900d8a 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/JGitFetchIT.java +++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/JGitFetchIT.java
@@ -15,7 +15,6 @@ package com.googlesource.gerrit.plugins.replication.pull; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; import static com.google.gerrit.acceptance.GitUtil.deleteRef; import static com.google.gerrit.acceptance.GitUtil.pushHead; import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow; @@ -27,31 +26,15 @@ import com.google.gerrit.acceptance.UseLocalDisk; import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; import com.google.gerrit.entities.Permission; -import com.google.gerrit.extensions.config.FactoryModule; import com.google.inject.Inject; -import com.google.inject.Scopes; -import com.google.inject.assistedinject.FactoryModuleBuilder; -import com.googlesource.gerrit.plugins.replication.AutoReloadSecureCredentialsFactoryDecorator; -import com.googlesource.gerrit.plugins.replication.CredentialsFactory; -import com.googlesource.gerrit.plugins.replication.ReplicationConfig; -import com.googlesource.gerrit.plugins.replication.ReplicationFileBasedConfig; import com.googlesource.gerrit.plugins.replication.pull.fetch.Fetch; -import com.googlesource.gerrit.plugins.replication.pull.fetch.FetchClientImplementation; -import com.googlesource.gerrit.plugins.replication.pull.fetch.FetchFactory; import com.googlesource.gerrit.plugins.replication.pull.fetch.JGitFetch; import com.googlesource.gerrit.plugins.replication.pull.fetch.PermanentTransportException; -import com.googlesource.gerrit.plugins.replication.pull.fetch.RefUpdateState; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.List; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.transport.PushResult; import org.eclipse.jgit.transport.RefSpec; -import org.eclipse.jgit.transport.RemoteConfig; -import org.eclipse.jgit.transport.RemoteRefUpdate; import org.eclipse.jgit.transport.URIish; import org.junit.Before; import org.junit.Test; @@ -64,7 +47,6 @@ public class JGitFetchIT extends FetchITBase { private static final String TEST_REPLICATION_SUFFIX = "suffix1"; private static final String TEST_TASK_ID = "taskid"; - private static final RefSpec ALL_REFS = new RefSpec("+refs/*:refs/*"); @Inject private ProjectOperations projectOperations; @@ -89,12 +71,10 @@ } @Test - public void shouldPruneRefsWhenMirrorIsTrue() throws Exception { + public void shouldPruneRefsWhenMirrorIsUnset() throws Exception { testRepo = cloneProject(createTestProject(project + TEST_REPLICATION_SUFFIX)); - String branchName = "anyBranch"; - String branchRef = Constants.R_HEADS + branchName; - String tagName = "anyTag"; - String tagRef = Constants.R_TAGS + tagName; + String branchRef = Constants.R_HEADS + "anyBranch"; + String tagRef = Constants.R_TAGS + "anyTag"; PushOneCommit.Result branchPush = pushFactory.create(user.newIdent(), testRepo).to(branchRef); branchPush.assertOkStatus(); @@ -103,13 +83,8 @@ assertOkStatus(tagPush, tagRef); try (Repository localRepo = repoManager.openRepository(project)) { - List<RefUpdateState> fetchCreated = fetchAllRefs(localRepo); - assertThat(fetchCreated.toString()) - .contains(new RefUpdateState(branchRef, RefUpdate.Result.NEW).toString()); + fetchAllRefs(TEST_TASK_ID, testRepoPath, localRepo); assertThat(getRef(localRepo, branchRef)).isNotNull(); - - assertThat(fetchCreated.toString()) - .contains(new RefUpdateState(tagRef, RefUpdate.Result.NEW).toString()); assertThat(getRef(localRepo, tagRef)).isNotNull(); PushResult deleteBranchResult = deleteRef(testRepo, branchRef); @@ -118,55 +93,24 @@ PushResult deleteTagResult = deleteRef(testRepo, tagRef); assertOkStatus(deleteTagResult, tagRef); - List<RefUpdateState> fetchDeleted = fetchAllRefs(localRepo); - assertThat(fetchDeleted.toString()) - .contains(new RefUpdateState(branchRef, RefUpdate.Result.FORCED).toString()); - assertThat(getRef(localRepo, branchRef)).isNull(); - - assertThat(fetchDeleted.toString()) - .contains(new RefUpdateState(tagRef, RefUpdate.Result.FORCED).toString()); - assertThat(getRef(localRepo, tagRef)).isNull(); + fetchAllRefs(TEST_TASK_ID, testRepoPath, localRepo); + assertThat(getRef(localRepo, branchRef)).isNotNull(); + assertThat(getRef(localRepo, tagRef)).isNotNull(); } } - private List<RefUpdateState> fetchAllRefs(Repository localRepo) - throws URISyntaxException, IOException { - Fetch fetch = fetchFactory.create(TEST_TASK_ID, new URIish(testRepoPath.toString()), localRepo); - return fetch.fetch(Lists.newArrayList(ALL_REFS)); - } - - private static void assertOkStatus(PushResult result, String ref) { - RemoteRefUpdate refUpdate = result.getRemoteUpdate(ref); - assertThat(refUpdate).isNotNull(); - assertWithMessage(refUpdate.getMessage()) - .that(refUpdate.getStatus()) - .isEqualTo(RemoteRefUpdate.Status.OK); - } - @SuppressWarnings("unused") - private static class TestModule extends FactoryModule { + private static class TestModule extends FetchModule<JGitFetch> { @Override - protected void configure() { + Class<JGitFetch> clientClass() { + return JGitFetch.class; + } + + @Override + Config cf() { Config cf = new Config(); cf.setInt("remote", "test_config", "timeout", 0); - cf.setBoolean("remote", "test_config", "mirror", true); - try { - RemoteConfig remoteConfig = new RemoteConfig(cf, "test_config"); - SourceConfiguration sourceConfig = new SourceConfiguration(remoteConfig, cf); - bind(ReplicationConfig.class).to(ReplicationFileBasedConfig.class); - bind(CredentialsFactory.class) - .to(AutoReloadSecureCredentialsFactoryDecorator.class) - .in(Scopes.SINGLETON); - - bind(SourceConfiguration.class).toInstance(sourceConfig); - install( - new FactoryModuleBuilder() - .implement(Fetch.class, JGitFetch.class) - .implement(Fetch.class, FetchClientImplementation.class, JGitFetch.class) - .build(FetchFactory.class)); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } + return cf; } } }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/JGitFetchWithMirrorIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/JGitFetchWithMirrorIT.java new file mode 100644 index 0000000..2df700f --- /dev/null +++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/JGitFetchWithMirrorIT.java
@@ -0,0 +1,100 @@ +// Copyright (C) 2023 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.googlesource.gerrit.plugins.replication.pull; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.gerrit.acceptance.GitUtil.deleteRef; +import static com.google.gerrit.acceptance.GitUtil.pushHead; +import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow; + +import com.google.gerrit.acceptance.PushOneCommit; +import com.google.gerrit.acceptance.SkipProjectClone; +import com.google.gerrit.acceptance.TestPlugin; +import com.google.gerrit.acceptance.UseLocalDisk; +import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; +import com.google.gerrit.entities.Permission; +import com.google.inject.Inject; +import com.googlesource.gerrit.plugins.replication.pull.fetch.JGitFetch; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.transport.PushResult; +import org.junit.Before; +import org.junit.Test; + +@SkipProjectClone +@UseLocalDisk +@TestPlugin( + name = "pull-replication", + sysModule = "com.googlesource.gerrit.plugins.replication.pull.JGitFetchWithMirrorIT$TestModule") +public class JGitFetchWithMirrorIT extends FetchITBase { + private static final String TEST_REPLICATION_SUFFIX = "suffix1"; + private static final String TEST_TASK_ID = "taskid"; + + @Inject private ProjectOperations projectOperations; + + @Before + public void allowRefDeletion() { + projectOperations + .allProjectsForUpdate() + .add(allow(Permission.DELETE).ref("refs/*").group(adminGroupUuid())) + .update(); + } + + @Test + public void shouldPruneRefsWhenMirrorIsTrue() throws Exception { + testRepo = cloneProject(createTestProject(project + TEST_REPLICATION_SUFFIX)); + String branchRef = Constants.R_HEADS + "anyBranch"; + String tagRef = Constants.R_TAGS + "anyTag"; + + PushOneCommit.Result branchPush = pushFactory.create(user.newIdent(), testRepo).to(branchRef); + branchPush.assertOkStatus(); + + PushResult tagPush = pushHead(testRepo, tagRef, false, false); + assertOkStatus(tagPush, tagRef); + + try (Repository localRepo = repoManager.openRepository(project)) { + fetchAllRefs(TEST_TASK_ID, testRepoPath, localRepo); + assertThat(getRef(localRepo, branchRef)).isNotNull(); + assertThat(getRef(localRepo, tagRef)).isNotNull(); + + PushResult deleteBranchResult = deleteRef(testRepo, branchRef); + assertOkStatus(deleteBranchResult, branchRef); + + PushResult deleteTagResult = deleteRef(testRepo, tagRef); + assertOkStatus(deleteTagResult, tagRef); + + fetchAllRefs(TEST_TASK_ID, testRepoPath, localRepo); + assertThat(getRef(localRepo, branchRef)).isNull(); + assertThat(getRef(localRepo, tagRef)).isNull(); + } + } + + @SuppressWarnings("unused") + private static class TestModule extends FetchModule<JGitFetch> { + @Override + Class<JGitFetch> clientClass() { + return JGitFetch.class; + } + + @Override + Config cf() { + Config cf = new Config(); + cf.setInt("remote", "test_config", "timeout", 0); + cf.setBoolean("remote", "test_config", "mirror", true); + return cf; + } + } +}