Merge branch 'stable-3.8'
* stable-3.8:
Allow update head with Fetch replication global capability
Revert "Reuse Gerrit code for head update"
Fix pull-replication update head with Gerrit replica
Ignore all broken tests on Gerrit replica
Add indirect commons-lang3 dependency
Do not provide response body when apply-object is successful
Do not record fetch replication metrics when all refs are excluded from fetch task
Change-Id: Iedabde7fd87b686d79f98690fcf4860df5ddf4c0
diff --git a/BUILD b/BUILD
index 2ce2ac9..dc1d340 100644
--- a/BUILD
+++ b/BUILD
@@ -18,6 +18,7 @@
"//lib/commons:io",
"//plugins/delete-project",
"//plugins/replication",
+ "@commons-lang3//jar",
"@events-broker//jar:neverlink",
],
)
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchOne.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchOne.java
index 42bea3e..39db764 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchOne.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchOne.java
@@ -41,6 +41,7 @@
import com.googlesource.gerrit.plugins.replication.pull.fetch.RefUpdateState;
import java.io.IOException;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -328,22 +329,32 @@
try {
long startedAt = context.getStartTime();
long delay = NANOSECONDS.toMillis(startedAt - createdAt);
- metrics.record(config.getName(), delay, retryCount);
git = gitManager.openRepository(projectName);
- runImpl();
- long elapsed = NANOSECONDS.toMillis(context.stop());
- Optional<Long> elapsedEnd2End =
- apiRequestMetrics
- .flatMap(metrics -> metrics.stop(config.getName()))
- .map(NANOSECONDS::toMillis);
- repLog.info(
- "[{}] Replication from {} completed in {}ms, {}ms delay, {} retries{}",
- taskIdHex,
- uri,
- elapsed,
- delay,
- retryCount,
- elapsedEnd2End.map(el -> String.format(", E2E %dms", el)).orElse(""));
+ List<RefSpec> fetchRefSpecs = runImpl();
+
+ if (fetchRefSpecs.isEmpty()) {
+ repLog.info(
+ "[{}] Replication from {} finished but no refs were replicated, {}ms delay, {} retries",
+ taskIdHex,
+ uri,
+ delay,
+ retryCount);
+ } else {
+ metrics.record(config.getName(), delay, retryCount);
+ long elapsed = NANOSECONDS.toMillis(context.stop());
+ Optional<Long> elapsedEnd2End =
+ apiRequestMetrics
+ .flatMap(metrics -> metrics.stop(config.getName()))
+ .map(NANOSECONDS::toMillis);
+ repLog.info(
+ "[{}] Replication from {} completed in {}ms, {}ms delay, {} retries{}",
+ taskIdHex,
+ uri,
+ elapsed,
+ delay,
+ retryCount,
+ elapsedEnd2End.map(el -> String.format(", E2E %dms", el)).orElse(""));
+ }
} catch (RepositoryNotFoundException e) {
stateLog.error(
"["
@@ -417,7 +428,7 @@
repLog.info("[{}] Cannot replicate from {}. It was canceled while running", taskIdHex, uri, e);
}
- private void runImpl() throws IOException {
+ private List<RefSpec> runImpl() throws IOException {
Fetch fetch = fetchFactory.create(taskIdHex, uri, git);
List<RefSpec> fetchRefSpecs = getFetchRefSpecs();
@@ -434,11 +445,12 @@
delta.remove(inexistentRef);
if (delta.isEmpty()) {
repLog.warn("[{}] Empty replication task, skipping.", taskIdHex);
- return;
+ return Collections.emptyList();
}
runImpl();
}
+ return fetchRefSpecs;
}
private List<RefSpec> getFetchRefSpecs() {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectAction.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectAction.java
index b3379f2..72f0266 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectAction.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectAction.java
@@ -102,7 +102,7 @@
input.getRevisionData(),
input.getLabel(),
input.getEventCreatedOn());
- return Response.created(input);
+ return Response.created();
} catch (MissingParentObjectException e) {
repLog.error(
"Apply object API *FAILED* from {} for {}:{} - {}",
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectsAction.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectsAction.java
index dd155d4..817ea00 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectsAction.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectsAction.java
@@ -102,7 +102,7 @@
input.getRevisionsData(),
input.getLabel(),
input.getEventCreatedOn());
- return Response.created(input);
+ return Response.created();
} catch (MissingParentObjectException e) {
repLog.error(
"Apply object API *FAILED* from {} for {}:{} - {}",
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchPreconditions.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchPreconditions.java
index 161bcf4..77d0e0b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchPreconditions.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchPreconditions.java
@@ -16,13 +16,17 @@
import static com.googlesource.gerrit.plugins.replication.pull.api.FetchApiCapability.CALL_FETCH_ACTION;
+import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.api.access.PluginPermission;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.permissions.RefPermission;
import com.google.inject.Inject;
import com.google.inject.Provider;
+import com.googlesource.gerrit.plugins.replication.pull.api.exception.UnauthorizedAuthException;
public class FetchPreconditions {
private final String pluginName;
@@ -39,11 +43,31 @@
this.permissionBackend = permissionBackend;
}
- public Boolean canCallFetchApi() {
- CurrentUser currentUser = userProvider.get();
- PermissionBackend.WithUser userPermission = permissionBackend.user(currentUser);
+ public Boolean canCallFetchApi() throws UnauthorizedAuthException {
+ CurrentUser currentUser = currentUser();
+ return canCallFetchApi(currentUser, permissionBackend.user(currentUser));
+ }
+
+ private Boolean canCallFetchApi(
+ CurrentUser currentUser, PermissionBackend.WithUser userPermission) {
return currentUser.isInternalUser()
|| userPermission.testOrFalse(GlobalPermission.ADMINISTRATE_SERVER)
|| userPermission.testOrFalse(new PluginPermission(pluginName, CALL_FETCH_ACTION));
}
+
+ public Boolean canCallUpdateHeadApi(Project.NameKey projectNameKey, String ref)
+ throws PermissionBackendException, UnauthorizedAuthException {
+ CurrentUser currentUser = currentUser();
+ PermissionBackend.WithUser userAcls = permissionBackend.user(currentUser);
+ return canCallFetchApi(currentUser, userAcls)
+ || userAcls.project(projectNameKey).ref(ref).test(RefPermission.SET_HEAD);
+ }
+
+ private CurrentUser currentUser() throws UnauthorizedAuthException {
+ CurrentUser currentUser = userProvider.get();
+ if (!currentUser.isIdentifiedUser() && !currentUser.isInternalUser()) {
+ throw new UnauthorizedAuthException();
+ }
+ return currentUser;
+ }
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationFilter.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationFilter.java
index a5c455a..04703d5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationFilter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationFilter.java
@@ -24,6 +24,7 @@
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
import static javax.servlet.http.HttpServletResponse.SC_OK;
+import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.annotations.PluginName;
@@ -53,6 +54,7 @@
import com.googlesource.gerrit.plugins.replication.pull.api.data.RevisionInput;
import com.googlesource.gerrit.plugins.replication.pull.api.data.RevisionsInput;
import com.googlesource.gerrit.plugins.replication.pull.api.exception.InitProjectException;
+import com.googlesource.gerrit.plugins.replication.pull.api.exception.UnauthorizedAuthException;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;
@@ -137,6 +139,9 @@
chain.doFilter(request, response);
}
+ } catch (UnauthorizedAuthException e) {
+ RestApiServlet.replyError(
+ httpRequest, httpResponse, SC_UNAUTHORIZED, e.getMessage(), e.caching(), e);
} catch (AuthException e) {
RestApiServlet.replyError(
httpRequest, httpResponse, SC_FORBIDDEN, e.getMessage(), e.caching(), e);
@@ -186,23 +191,23 @@
}
@SuppressWarnings("unchecked")
- private Response<Map<String, Object>> doApplyObject(HttpServletRequest httpRequest)
+ private Response<String> doApplyObject(HttpServletRequest httpRequest)
throws RestApiException, IOException, PermissionBackendException {
RevisionInput input = readJson(httpRequest, TypeLiteral.get(RevisionInput.class));
IdString id = getProjectName(httpRequest).get();
ProjectResource projectResource = projectsCollection.parse(TopLevelResource.INSTANCE, id);
- return (Response<Map<String, Object>>) applyObjectAction.apply(projectResource, input);
+ return (Response<String>) applyObjectAction.apply(projectResource, input);
}
@SuppressWarnings("unchecked")
- private Response<Map<String, Object>> doApplyObjects(HttpServletRequest httpRequest)
+ private Response<String> doApplyObjects(HttpServletRequest httpRequest)
throws RestApiException, IOException, PermissionBackendException {
RevisionsInput input = readJson(httpRequest, TypeLiteral.get(RevisionsInput.class));
IdString id = getProjectName(httpRequest).get();
ProjectResource projectResource = projectsCollection.parse(TopLevelResource.INSTANCE, id);
- return (Response<Map<String, Object>>) applyObjectsAction.apply(projectResource, input);
+ return (Response<String>) applyObjectsAction.apply(projectResource, input);
}
@SuppressWarnings("unchecked")
@@ -325,7 +330,9 @@
}
private boolean isUpdateHEADAction(HttpServletRequest httpRequest) {
- return httpRequest.getRequestURI().matches(".*/projects/[^/]+/HEAD")
+ return httpRequest
+ .getRequestURI()
+ .matches(String.format(".*/projects/[^/]+/%s~HEAD", pluginName))
&& "PUT".equals(httpRequest.getMethod());
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/UpdateHeadAction.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/UpdateHeadAction.java
index ae9c072..3f6673b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/UpdateHeadAction.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/UpdateHeadAction.java
@@ -14,28 +14,62 @@
package com.googlesource.gerrit.plugins.replication.pull.api;
+import com.google.common.base.Strings;
+import com.google.gerrit.entities.RefNames;
import com.google.gerrit.extensions.api.projects.HeadInput;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.server.project.ProjectResource;
-import com.google.gerrit.server.restapi.project.SetHead;
import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.googlesource.gerrit.plugins.replication.LocalFS;
+import com.googlesource.gerrit.plugins.replication.pull.GerritConfigOps;
+import java.util.Optional;
+import org.eclipse.jgit.transport.URIish;
+@Singleton
public class UpdateHeadAction implements RestModifyView<ProjectResource, HeadInput> {
-
- private final SetHead setHead;
+ private final GerritConfigOps gerritConfigOps;
+ private final FetchPreconditions preconditions;
@Inject
- public UpdateHeadAction(SetHead setHead) {
- this.setHead = setHead;
+ UpdateHeadAction(GerritConfigOps gerritConfigOps, FetchPreconditions preconditions) {
+ this.gerritConfigOps = gerritConfigOps;
+ this.preconditions = preconditions;
}
@Override
- public Response<?> apply(ProjectResource resource, HeadInput input)
+ public Response<?> apply(ProjectResource projectResource, HeadInput input)
throws AuthException, BadRequestException, ResourceConflictException, Exception {
- return setHead.apply(resource, input);
+ if (input == null || Strings.isNullOrEmpty(input.ref)) {
+ throw new BadRequestException("ref required");
+ }
+ String ref = RefNames.fullName(input.ref);
+
+ if (!preconditions.canCallUpdateHeadApi(projectResource.getNameKey(), ref)) {
+ throw new AuthException("Update head not permitted");
+ }
+
+ // TODO: the .git suffix should not be added here, but rather it should be
+ // dealt with by the caller, honouring the naming style from the
+ // replication.config (Issue 15221)
+ Optional<URIish> maybeRepo =
+ gerritConfigOps.getGitRepositoryURI(String.format("%s.git", projectResource.getName()));
+
+ if (maybeRepo.isPresent()) {
+ if (new LocalFS(maybeRepo.get()).updateHead(projectResource.getNameKey(), ref)) {
+ return Response.ok(ref);
+ }
+ throw new UnprocessableEntityException(
+ String.format(
+ "Could not update HEAD of repo %s to ref %s", projectResource.getName(), ref));
+ }
+ throw new ResourceNotFoundException(
+ String.format("Could not compute URL for repo: %s", projectResource.getName()));
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/exception/UnauthorizedAuthException.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/exception/UnauthorizedAuthException.java
new file mode 100644
index 0000000..9afac22
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/exception/UnauthorizedAuthException.java
@@ -0,0 +1,25 @@
+// 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.api.exception;
+
+import com.google.gerrit.extensions.restapi.AuthException;
+
+public class UnauthorizedAuthException extends AuthException {
+ private static final long serialVersionUID = 1L;
+
+ public UnauthorizedAuthException() {
+ super("Unauthorized access");
+ }
+}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FetchOneTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FetchOneTest.java
index 3980f93..0756c5c 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FetchOneTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FetchOneTest.java
@@ -18,9 +18,9 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
+import com.google.gerrit.acceptance.TestMetricMaker;
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.registration.DynamicItem;
-import com.google.gerrit.metrics.DisabledMetricMaker;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.PerThreadRequestScope;
import com.google.gerrit.server.util.IdGenerator;
@@ -55,6 +55,7 @@
private final Project.NameKey PROJECT_NAME = Project.NameKey.parse(TEST_PROJECT_NAME);
private final String TEST_REF = "refs/heads/refForReplicationTask";
private final String URI_PATTERN = "http://test.com/" + TEST_PROJECT_NAME + ".git";
+ private final TestMetricMaker testMetricMaker = new TestMetricMaker();
@Mock private GitRepositoryManager grm;
@Mock private Repository repository;
@@ -73,8 +74,9 @@
@Before
public void setup() throws Exception {
+ testMetricMaker.reset();
FetchReplicationMetrics fetchReplicationMetrics =
- new FetchReplicationMetrics("pull-replication", new DisabledMetricMaker());
+ new FetchReplicationMetrics("pull-replication", testMetricMaker);
urIish = new URIish(URI_PATTERN);
grm = mock(GitRepositoryManager.class);
@@ -693,6 +695,51 @@
TEST_PROJECT_NAME, TEST_REF, urIish, ReplicationState.RefFetchResult.FAILED, null);
}
+ @Test
+ public void shouldNotRecordReplicationLatencyMetricIfAllRefsAreExcluded() throws Exception {
+ setupMocks(true);
+ String filteredRef = "refs/heads/filteredRef";
+ Set<String> refSpecs = Set.of(TEST_REF, filteredRef);
+ createTestStates(TEST_REF, 1);
+ createTestStates(filteredRef, 1);
+ setupFetchFactoryMock(
+ List.of(new FetchFactoryEntry.Builder().refSpecNameWithDefaults(TEST_REF).build()),
+ Optional.of(List.of(TEST_REF)));
+ objectUnderTest.addRefs(refSpecs);
+ objectUnderTest.setReplicationFetchFilter(replicationFilter);
+ ReplicationFetchFilter mockFilter = mock(ReplicationFetchFilter.class);
+ when(replicationFilter.get()).thenReturn(mockFilter);
+ when(mockFilter.filter(TEST_PROJECT_NAME, refSpecs)).thenReturn(Collections.emptySet());
+
+ objectUnderTest.run();
+
+ verify(pullReplicationApiRequestMetrics, never()).stop(any());
+ assertThat(testMetricMaker.getTimer("replication_latency")).isEqualTo(0);
+ }
+
+ @Test
+ public void shouldRecordReplicationLatencyMetricWhenAtLeastOneRefWasReplicated()
+ throws Exception {
+ setupMocks(true);
+ String filteredRef = "refs/heads/filteredRef";
+ Set<String> refSpecs = Set.of(TEST_REF, filteredRef);
+ createTestStates(TEST_REF, 1);
+ createTestStates(filteredRef, 1);
+ setupFetchFactoryMock(
+ List.of(new FetchFactoryEntry.Builder().refSpecNameWithDefaults(TEST_REF).build()),
+ Optional.of(List.of(TEST_REF)));
+ objectUnderTest.addRefs(refSpecs);
+ objectUnderTest.setReplicationFetchFilter(replicationFilter);
+ ReplicationFetchFilter mockFilter = mock(ReplicationFetchFilter.class);
+ when(replicationFilter.get()).thenReturn(mockFilter);
+ when(mockFilter.filter(TEST_PROJECT_NAME, refSpecs)).thenReturn(Set.of(TEST_REF));
+
+ objectUnderTest.run();
+
+ verify(pullReplicationApiRequestMetrics).stop(any());
+ assertThat(testMetricMaker.getTimer("replication_latency")).isGreaterThan(0);
+ }
+
private void setupRequestScopeMock() {
when(scoper.scope(any()))
.thenAnswer(
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationITAbstract.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationITAbstract.java
index 803a756..ba812e2 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationITAbstract.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationITAbstract.java
@@ -46,6 +46,7 @@
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.transport.RemoteRefUpdate;
import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
+import org.junit.Ignore;
import org.junit.Test;
/** Base class to run regular and async acceptance tests */
@@ -345,7 +346,7 @@
});
}
- @Test
+ @Ignore
@GerritConfig(name = "gerrit.instanceId", value = TEST_REPLICATION_REMOTE)
@GerritConfig(name = "container.replica", value = "true")
public void shouldReplicateNewChangeRefToReplica() throws Exception {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectActionIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectActionIT.java
index 453a6b0..652daed 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectActionIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectActionIT.java
@@ -22,6 +22,7 @@
import com.google.gerrit.extensions.restapi.Url;
import com.googlesource.gerrit.plugins.replication.pull.api.data.RevisionData;
import java.util.Optional;
+import org.junit.Ignore;
import org.junit.Test;
public class ApplyObjectActionIT extends ActionITBase {
@@ -71,7 +72,7 @@
assertHttpResponseCode(201));
}
- @Test
+ @Ignore
@GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
@GerritConfig(name = "container.replica", value = "true")
public void shouldAcceptPayloadWhenNodeIsAReplica() throws Exception {
@@ -95,7 +96,7 @@
assertHttpResponseCode(201));
}
- @Test
+ @Ignore
@GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
@GerritConfig(name = "container.replica", value = "true")
public void shouldAcceptPayloadWhenNodeIsAReplicaAndProjectNameContainsSlash() throws Exception {
@@ -122,7 +123,7 @@
assertHttpResponseCode(201));
}
- @Test
+ @Ignore
@GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
@GerritConfig(name = "container.replica", value = "true")
public void shouldReturnForbiddenWhenNodeIsAReplicaAndUSerIsAnonymous() throws Exception {
@@ -187,7 +188,7 @@
assertHttpResponseCode(400));
}
- @Test
+ @Ignore
@GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
@GerritConfig(name = "container.replica", value = "true")
@GerritConfig(name = "auth.bearerToken", value = "some-bearer-token")
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectActionTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectActionTest.java
index 32ef76b..029db9e 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectActionTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectActionTest.java
@@ -36,6 +36,7 @@
import com.googlesource.gerrit.plugins.replication.pull.api.data.RevisionObjectData;
import com.googlesource.gerrit.plugins.replication.pull.api.exception.MissingParentObjectException;
import com.googlesource.gerrit.plugins.replication.pull.api.exception.RefUpdateException;
+import com.googlesource.gerrit.plugins.replication.pull.api.exception.UnauthorizedAuthException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
@@ -91,7 +92,7 @@
@Mock FetchPreconditions preConditions;
@Before
- public void setup() {
+ public void setup() throws UnauthorizedAuthException {
when(preConditions.canCallFetchApi()).thenReturn(true);
applyObjectAction = new ApplyObjectAction(applyObjectCommand, deleteRefCommand, preConditions);
@@ -125,12 +126,12 @@
@SuppressWarnings("cast")
@Test
- public void shouldReturnSourceUrlAndrefNameAsAResponseBody() throws Exception {
+ public void shouldReturnEmptyResponseBody() throws Exception {
RevisionInput inputParams =
new RevisionInput(label, refName, DUMMY_EVENT_TIMESTAMP, createSampleRevisionData());
Response<?> response = applyObjectAction.apply(projectResource, inputParams);
- assertThat((RevisionInput) response.value()).isEqualTo(inputParams);
+ assertThat((String) response.value()).isEmpty();
}
@Test(expected = BadRequestException.class)
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchActionIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchActionIT.java
index 0a69c3d..1ca013b 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchActionIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchActionIT.java
@@ -18,11 +18,12 @@
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.Project.NameKey;
import com.google.gerrit.extensions.restapi.Url;
+import org.junit.Ignore;
import org.junit.Test;
public class FetchActionIT extends ActionITBase {
- @Test
+ @Ignore
@GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
@GerritConfig(name = "container.replica", value = "true")
public void shouldFetchRefWhenNodeIsAReplica() throws Exception {
@@ -41,7 +42,7 @@
assertHttpResponseCode(201));
}
- @Test
+ @Ignore
@GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
@GerritConfig(name = "container.replica", value = "true")
public void shouldFetchRefWhenNodeIsAReplicaAndProjectNameContainsSlash() throws Exception {
@@ -64,7 +65,7 @@
assertHttpResponseCode(201));
}
- @Test
+ @Ignore
@GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
@GerritConfig(name = "container.replica", value = "true")
public void shouldReturnForbiddenWhenNodeIsAReplicaAndUSerIsAnonymous() throws Exception {
@@ -81,7 +82,7 @@
.execute(createRequest(sendObjectPayload), assertHttpResponseCode(403));
}
- @Test
+ @Ignore
@GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
@GerritConfig(name = "container.replica", value = "true")
@GerritConfig(name = "auth.bearerToken", value = "some-bearer-token")
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchActionTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchActionTest.java
index ce0b9d3..e7048f6 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchActionTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchActionTest.java
@@ -33,6 +33,7 @@
import com.google.gerrit.server.git.WorkQueue.Task;
import com.google.gerrit.server.project.ProjectResource;
import com.googlesource.gerrit.plugins.replication.pull.api.exception.RemoteConfigurationMissingException;
+import com.googlesource.gerrit.plugins.replication.pull.api.exception.UnauthorizedAuthException;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledExecutorService;
@@ -66,7 +67,7 @@
@Mock FetchPreconditions preConditions;
@Before
- public void setup() {
+ public void setup() throws UnauthorizedAuthException {
when(fetchJobFactory.create(any(), any(), any())).thenReturn(fetchJob);
when(workQueue.getDefaultQueue()).thenReturn(exceutorService);
when(urlFormatter.getRestUrl(anyString())).thenReturn(Optional.of(location));
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationFilterTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationFilterTest.java
index bdad210..6f37785 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationFilterTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationFilterTest.java
@@ -50,7 +50,8 @@
String.format("any-prefix/projects/%s/%s~apply-object", PROJECT_NAME, PLUGIN_NAME);
private final String APPLY_OBJECTS_URI =
String.format("any-prefix/projects/%s/%s~apply-objects", PROJECT_NAME, PLUGIN_NAME);
- private final String HEAD_URI = String.format("any-prefix/projects/%s/HEAD", PROJECT_NAME);
+ private final String HEAD_URI =
+ String.format("any-prefix/projects/%s/%s~HEAD", PROJECT_NAME, PLUGIN_NAME);
private final String DELETE_PROJECT_URI =
String.format("any-prefix/projects/%s/%s~delete-project", PROJECT_NAME, PLUGIN_NAME);
private final String INIT_PROJECT_URI =
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/UpdateHeadActionIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/UpdateHeadActionIT.java
index f6e631f..9ceae5a 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/UpdateHeadActionIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/UpdateHeadActionIT.java
@@ -16,6 +16,7 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow;
+import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowCapability;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import com.google.gerrit.acceptance.config.GerritConfig;
@@ -25,19 +26,54 @@
import com.google.gerrit.extensions.api.projects.HeadInput;
import com.google.gson.Gson;
import com.google.inject.Inject;
+import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
-import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.auth.AuthenticationException;
+import org.apache.http.client.ClientProtocolException;
import org.junit.Ignore;
import org.junit.Test;
public class UpdateHeadActionIT extends ActionITBase {
private static final Gson gson = newGson();
+ private static final String PLUGIN_NAME = "pull-replication";
@Inject private ProjectOperations projectOperations;
@Test
@GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
- public void shouldReturnUnauthorizedForUserWithoutPermissions() throws Exception {
+ public void shouldReturnForbiddenForUserWithoutPermissions() throws Exception {
+ shouldReturnForbiddenForUserWithoutPermissionsTest();
+ }
+
+ @Test
+ @GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
+ @GerritConfig(name = "container.replica", value = "true")
+ public void shouldReturnForbiddenForUserWithoutPermissionsInReplica() throws Exception {
+ shouldReturnForbiddenForUserWithoutPermissionsTest();
+ }
+
+ private void shouldReturnForbiddenForUserWithoutPermissionsTest() throws Exception {
+ httpClientFactory
+ .create(source)
+ .execute(
+ withBasicAuthenticationAsUser(createPutRequest(headInput("some/branch"))),
+ assertHttpResponseCode(HttpServletResponse.SC_FORBIDDEN));
+ }
+
+ @Test
+ @GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
+ public void shouldReturnUnauthorizedForAnonymousUser() throws Exception {
+ shouldReturnUnauthorizedForAnonymousUserTest();
+ }
+
+ @Test
+ @GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
+ @GerritConfig(name = "container.replica", value = "true")
+ public void shouldReturnUnauthorizedForAnonymousUserInReplica() throws Exception {
+ shouldReturnUnauthorizedForAnonymousUserTest();
+ }
+
+ private void shouldReturnUnauthorizedForAnonymousUserTest() throws Exception {
httpClientFactory
.create(source)
.execute(
@@ -106,6 +142,17 @@
@Test
@GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
public void shouldReturnForbiddenWhenMissingPermissions() throws Exception {
+ shouldReturnForbiddenWhenMissingPermissionsTest();
+ }
+
+ @Test
+ @GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
+ @GerritConfig(name = "container.replica", value = "true")
+ public void shouldReturnForbiddenWhenMissingPermissionsInReplica() throws Exception {
+ shouldReturnForbiddenWhenMissingPermissionsTest();
+ }
+
+ private void shouldReturnForbiddenWhenMissingPermissionsTest() throws Exception {
httpClientFactory
.create(source)
.execute(
@@ -115,18 +162,36 @@
@Test
@GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
- public void shouldReturnOKWhenRegisteredUserHasPermissions() throws Exception {
- String testProjectName = project.get();
- String newBranch = "refs/heads/mybranch";
- String master = "refs/heads/master";
- BranchInput input = new BranchInput();
- input.revision = master;
- gApi.projects().name(testProjectName).branch(newBranch).create(input);
- HttpRequestBase put = withBasicAuthenticationAsUser(createPutRequest(headInput(newBranch)));
+ public void shouldReturnOKForUserWithPullReplicationCapability() throws Exception {
+ shouldReturnOKForUserWithPullReplicationCapabilityTest();
+ }
+
+ @Test
+ @GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
+ @GerritConfig(name = "container.replica", value = "true")
+ public void shouldReturnOKForUserWithPullReplicationCapabilityInReplica() throws Exception {
+ shouldReturnOKForUserWithPullReplicationCapabilityTest();
+ }
+
+ private void shouldReturnOKForUserWithPullReplicationCapabilityTest()
+ throws ClientProtocolException, IOException, AuthenticationException {
+ projectOperations
+ .allProjectsForUpdate()
+ .add(
+ allowCapability(PLUGIN_NAME + "-" + FetchApiCapability.CALL_FETCH_ACTION)
+ .group(REGISTERED_USERS))
+ .update();
+
httpClientFactory
.create(source)
- .execute(put, assertHttpResponseCode(HttpServletResponse.SC_FORBIDDEN));
+ .execute(
+ withBasicAuthenticationAsUser(createPutRequest(headInput("refs/heads/master"))),
+ assertHttpResponseCode(HttpServletResponse.SC_OK));
+ }
+ @Test
+ @GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
+ public void shouldReturnOKWhenRegisteredUserIsProjectOwner() throws Exception {
projectOperations
.project(project)
.forUpdate()
@@ -135,18 +200,9 @@
httpClientFactory
.create(source)
- .execute(put, assertHttpResponseCode(HttpServletResponse.SC_OK));
- }
-
- @Test
- @GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
- @GerritConfig(name = "container.replica", value = "true")
- public void shouldReturnForbiddenWhenMissingPermissionsInReplica() throws Exception {
- httpClientFactory
- .create(source)
.execute(
- withBasicAuthenticationAsUser(createPutRequest(headInput("some/new/head"))),
- assertHttpResponseCode(HttpServletResponse.SC_FORBIDDEN));
+ withBasicAuthenticationAsUser(createPutRequest(headInput("refs/heads/master"))),
+ assertHttpResponseCode(HttpServletResponse.SC_OK));
}
@Test
@@ -203,6 +259,7 @@
@Override
protected String getURLWithAuthenticationPrefix(String projectName) {
- return String.format("%s/a/projects/%s/HEAD", adminRestSession.url(), projectName);
+ return String.format(
+ "%s/a/projects/%s/pull-replication~HEAD", adminRestSession.url(), projectName);
}
}