Merge branch 'stable-3.7' into stable-3.8
* stable-3.7:
Use PullReplicationFilter in Gerrit primary setup
Ignore invalid createChange replication test on Gerrit replica
Allow replication of hidden projects
Fix ApplyObjectIT flaky test
Change-Id: Ic1b3cd66d6087d05f2e6712c36a9f49c9cd82048
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java
index d1c5ca1..03345e2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java
@@ -15,6 +15,7 @@
package com.googlesource.gerrit.plugins.replication.pull;
import static com.googlesource.gerrit.plugins.replication.StartReplicationCapability.START_REPLICATION;
+import static com.googlesource.gerrit.plugins.replication.pull.api.FetchApiCapability.CALL_FETCH_ACTION;
import com.google.common.eventbus.EventBus;
import com.google.gerrit.extensions.annotations.Exports;
@@ -42,8 +43,8 @@
import com.googlesource.gerrit.plugins.replication.ReplicationConfig;
import com.googlesource.gerrit.plugins.replication.ReplicationFileBasedConfig;
import com.googlesource.gerrit.plugins.replication.StartReplicationCapability;
+import com.googlesource.gerrit.plugins.replication.pull.api.FetchApiCapability;
import com.googlesource.gerrit.plugins.replication.pull.api.FetchJob;
-import com.googlesource.gerrit.plugins.replication.pull.api.PullReplicationApiModule;
import com.googlesource.gerrit.plugins.replication.pull.auth.PullReplicationGroupModule;
import com.googlesource.gerrit.plugins.replication.pull.client.FetchApiClient;
import com.googlesource.gerrit.plugins.replication.pull.client.FetchRestApiClient;
@@ -75,13 +76,16 @@
@Override
protected void configure() {
+ bind(CapabilityDefinition.class)
+ .annotatedWith(Exports.named(CALL_FETCH_ACTION))
+ .to(FetchApiCapability.class);
+
install(new PullReplicationGroupModule());
bind(BearerTokenProvider.class).in(Scopes.SINGLETON);
bind(RevisionReader.class).in(Scopes.SINGLETON);
bind(ApplyObject.class);
install(new FactoryModuleBuilder().build(FetchJob.Factory.class));
install(new ApplyObjectCacheModule());
- install(new PullReplicationApiModule());
install(new FetchRefReplicatedEventModule());
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/Source.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/Source.java
index 0ebbf91..f75ea7b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/Source.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/Source.java
@@ -318,13 +318,6 @@
ref);
throw new NoSuchProjectException(project);
}
- if (!projectState.get().statePermitsRead()) {
- repLog.warn(
- "NOT scheduling replication {}:{} because project is not readable",
- project,
- ref);
- return false;
- }
if (!shouldReplicate(projectState.get(), userProvider.get())) {
return false;
}
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 72f0266..d535ac9 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
@@ -26,6 +26,7 @@
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.server.project.ProjectResource;
import com.google.inject.Inject;
+import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.replication.pull.api.data.RevisionInput;
import com.googlesource.gerrit.plugins.replication.pull.api.exception.MissingParentObjectException;
import com.googlesource.gerrit.plugins.replication.pull.api.exception.RefUpdateException;
@@ -33,6 +34,7 @@
import java.util.Objects;
import javax.servlet.http.HttpServletResponse;
+@Singleton
public class ApplyObjectAction implements RestModifyView<ProjectResource, RevisionInput> {
private final ApplyObjectCommand applyObjectCommand;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchAction.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchAction.java
index fdb4f8f..9817f2c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchAction.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchAction.java
@@ -30,6 +30,7 @@
import com.google.gerrit.server.ioutil.HexFormat;
import com.google.gerrit.server.project.ProjectResource;
import com.google.inject.Inject;
+import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.replication.pull.api.FetchAction.Input;
import com.googlesource.gerrit.plugins.replication.pull.api.FetchJob.Factory;
import com.googlesource.gerrit.plugins.replication.pull.api.exception.RemoteConfigurationMissingException;
@@ -37,6 +38,7 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
+@Singleton
public class FetchAction implements RestModifyView<ProjectResource, Input> {
private final FetchCommand command;
private final WorkQueue workQueue;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchApiCapability.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchApiCapability.java
index 73a4ac5..27afcfd 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchApiCapability.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchApiCapability.java
@@ -17,7 +17,7 @@
import com.google.gerrit.extensions.config.CapabilityDefinition;
public class FetchApiCapability extends CapabilityDefinition {
- static final String CALL_FETCH_ACTION = "callFetchAction";
+ public static final String CALL_FETCH_ACTION = "callFetchAction";
@Override
public String getDescription() {
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 77d0e0b..7ca8805 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
@@ -26,8 +26,10 @@
import com.google.gerrit.server.permissions.RefPermission;
import com.google.inject.Inject;
import com.google.inject.Provider;
+import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.replication.pull.api.exception.UnauthorizedAuthException;
+@Singleton
public class FetchPreconditions {
private final String pluginName;
private final PermissionBackend permissionBackend;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/HttpModule.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/HttpModule.java
index 0f3e1e8..95082b8 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/HttpModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/HttpModule.java
@@ -16,7 +16,6 @@
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.httpd.AllRequestFilter;
-import com.google.gerrit.server.config.GerritIsReplica;
import com.google.inject.Inject;
import com.google.inject.Scopes;
import com.google.inject.name.Names;
@@ -24,12 +23,10 @@
import com.googlesource.gerrit.plugins.replication.pull.BearerTokenProvider;
public class HttpModule extends ServletModule {
- private boolean isReplica;
private final BearerTokenProvider bearerTokenProvider;
@Inject
- public HttpModule(@GerritIsReplica Boolean isReplica, BearerTokenProvider bearerTokenProvider) {
- this.isReplica = isReplica;
+ public HttpModule(BearerTokenProvider bearerTokenProvider) {
this.bearerTokenProvider = bearerTokenProvider;
}
@@ -49,12 +46,8 @@
.in(Scopes.SINGLETON);
});
- if (isReplica) {
- DynamicSet.bind(binder(), AllRequestFilter.class)
- .to(PullReplicationFilter.class)
- .in(Scopes.SINGLETON);
- } else {
- serveRegex("/init-project/.*$").with(ProjectInitializationAction.class);
- }
+ DynamicSet.bind(binder(), AllRequestFilter.class)
+ .to(PullReplicationFilter.class)
+ .in(Scopes.SINGLETON);
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectDeletionAction.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectDeletionAction.java
index 2e1c5d4..adb333c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectDeletionAction.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectDeletionAction.java
@@ -27,11 +27,13 @@
import com.google.gerrit.server.project.ProjectResource;
import com.google.inject.Inject;
import com.google.inject.Provider;
+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
class ProjectDeletionAction
implements RestModifyView<ProjectResource, ProjectDeletionAction.DeleteInput> {
private static final PluginPermission DELETE_PROJECT =
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationApiModule.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationApiModule.java
deleted file mode 100644
index d1d28a6..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationApiModule.java
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (C) 2020 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;
-
-import static com.google.gerrit.server.project.ProjectResource.PROJECT_KIND;
-import static com.googlesource.gerrit.plugins.replication.pull.api.FetchApiCapability.CALL_FETCH_ACTION;
-
-import com.google.gerrit.extensions.annotations.Exports;
-import com.google.gerrit.extensions.config.CapabilityDefinition;
-import com.google.gerrit.extensions.restapi.RestApiModule;
-import com.google.inject.Scopes;
-
-public class PullReplicationApiModule extends RestApiModule {
- @Override
- protected void configure() {
- bind(FetchAction.class).in(Scopes.SINGLETON);
- bind(ApplyObjectAction.class).in(Scopes.SINGLETON);
- bind(ProjectDeletionAction.class).in(Scopes.SINGLETON);
- bind(UpdateHeadAction.class).in(Scopes.SINGLETON);
- post(PROJECT_KIND, "fetch").to(FetchAction.class);
- post(PROJECT_KIND, "apply-object").to(ApplyObjectAction.class);
- post(PROJECT_KIND, "apply-objects").to(ApplyObjectsAction.class);
- delete(PROJECT_KIND, "delete-project").to(ProjectDeletionAction.class);
- put(PROJECT_KIND, "HEAD").to(UpdateHeadAction.class);
-
- bind(FetchPreconditions.class).in(Scopes.SINGLETON);
- bind(CapabilityDefinition.class)
- .annotatedWith(Exports.named(CALL_FETCH_ACTION))
- .to(FetchApiCapability.class);
- }
-}
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 2df6b0c..40e39ad 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
@@ -26,6 +26,7 @@
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.api.projects.HeadInput;
import com.google.gerrit.extensions.restapi.AuthException;
@@ -35,19 +36,22 @@
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.httpd.AllRequestFilter;
import com.google.gerrit.httpd.restapi.RestApiServlet;
import com.google.gerrit.json.OutputFormat;
+import com.google.gerrit.server.AnonymousUser;
+import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectResource;
-import com.google.gerrit.server.restapi.project.ProjectsCollection;
+import com.google.gerrit.server.project.ProjectState;
import com.google.gson.Gson;
import com.google.gson.JsonParseException;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.MalformedJsonException;
import com.google.inject.Inject;
+import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import com.googlesource.gerrit.plugins.replication.pull.api.FetchAction.Input;
import com.googlesource.gerrit.plugins.replication.pull.api.data.RevisionInput;
@@ -83,9 +87,10 @@
private ProjectInitializationAction projectInitializationAction;
private UpdateHeadAction updateHEADAction;
private ProjectDeletionAction projectDeletionAction;
- private ProjectsCollection projectsCollection;
+ private ProjectCache projectCache;
private Gson gson;
private String pluginName;
+ private final Provider<CurrentUser> currentUserProvider;
@Inject
public PullReplicationFilter(
@@ -95,17 +100,19 @@
ProjectInitializationAction projectInitializationAction,
UpdateHeadAction updateHEADAction,
ProjectDeletionAction projectDeletionAction,
- ProjectsCollection projectsCollection,
- @PluginName String pluginName) {
+ ProjectCache projectCache,
+ @PluginName String pluginName,
+ Provider<CurrentUser> currentUserProvider) {
this.fetchAction = fetchAction;
this.applyObjectAction = applyObjectAction;
this.applyObjectsAction = applyObjectsAction;
this.projectInitializationAction = projectInitializationAction;
this.updateHEADAction = updateHEADAction;
this.projectDeletionAction = projectDeletionAction;
- this.projectsCollection = projectsCollection;
+ this.projectCache = projectCache;
this.pluginName = pluginName;
this.gson = OutputFormat.JSON.newGsonBuilder().create();
+ this.currentUserProvider = currentUserProvider;
}
@Override
@@ -120,19 +127,25 @@
HttpServletRequest httpRequest = (HttpServletRequest) request;
try {
if (isFetchAction(httpRequest)) {
+ failIfcurrentUserIsAnonymous();
writeResponse(httpResponse, doFetch(httpRequest));
} else if (isApplyObjectAction(httpRequest)) {
+ failIfcurrentUserIsAnonymous();
writeResponse(httpResponse, doApplyObject(httpRequest));
} else if (isApplyObjectsAction(httpRequest)) {
+ failIfcurrentUserIsAnonymous();
writeResponse(httpResponse, doApplyObjects(httpRequest));
} else if (isInitProjectAction(httpRequest)) {
+ failIfcurrentUserIsAnonymous();
if (!checkAcceptHeader(httpRequest, httpResponse)) {
return;
}
doInitProject(httpRequest, httpResponse);
} else if (isUpdateHEADAction(httpRequest)) {
+ failIfcurrentUserIsAnonymous();
writeResponse(httpResponse, doUpdateHEAD(httpRequest));
} else if (isDeleteProjectAction(httpRequest)) {
+ failIfcurrentUserIsAnonymous();
writeResponse(httpResponse, doDeleteProject(httpRequest));
} else {
chain.doFilter(request, response);
@@ -173,6 +186,13 @@
}
}
+ private void failIfcurrentUserIsAnonymous() throws UnauthorizedAuthException {
+ CurrentUser currentUser = currentUserProvider.get();
+ if (currentUser instanceof AnonymousUser) {
+ throw new UnauthorizedAuthException();
+ }
+ }
+
private void doInitProject(HttpServletRequest httpRequest, HttpServletResponse httpResponse)
throws RestApiException, IOException, PermissionBackendException {
@@ -191,9 +211,8 @@
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<String>) applyObjectAction.apply(projectResource, input);
+ return (Response<String>) applyObjectAction.apply(parseProjectResource(id), input);
}
@SuppressWarnings("unchecked")
@@ -201,26 +220,24 @@
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<String>) applyObjectsAction.apply(projectResource, input);
+ return (Response<String>) applyObjectsAction.apply(parseProjectResource(id), input);
}
@SuppressWarnings("unchecked")
private Response<String> doUpdateHEAD(HttpServletRequest httpRequest) throws Exception {
HeadInput input = readJson(httpRequest, TypeLiteral.get(HeadInput.class));
IdString id = getProjectName(httpRequest).get();
- ProjectResource projectResource = projectsCollection.parse(TopLevelResource.INSTANCE, id);
- return (Response<String>) updateHEADAction.apply(projectResource, input);
+ return (Response<String>) updateHEADAction.apply(parseProjectResource(id), input);
}
@SuppressWarnings("unchecked")
private Response<String> doDeleteProject(HttpServletRequest httpRequest) throws Exception {
IdString id = getProjectName(httpRequest).get();
- ProjectResource projectResource = projectsCollection.parse(TopLevelResource.INSTANCE, id);
return (Response<String>)
- projectDeletionAction.apply(projectResource, new ProjectDeletionAction.DeleteInput());
+ projectDeletionAction.apply(
+ parseProjectResource(id), new ProjectDeletionAction.DeleteInput());
}
@SuppressWarnings("unchecked")
@@ -228,9 +245,16 @@
throws IOException, RestApiException, PermissionBackendException {
Input input = readJson(httpRequest, TypeLiteral.get(Input.class));
IdString id = getProjectName(httpRequest).get();
- ProjectResource projectResource = projectsCollection.parse(TopLevelResource.INSTANCE, id);
- return (Response<Map<String, Object>>) fetchAction.apply(projectResource, input);
+ return (Response<Map<String, Object>>) fetchAction.apply(parseProjectResource(id), input);
+ }
+
+ private ProjectResource parseProjectResource(IdString id) throws ResourceNotFoundException {
+ Optional<ProjectState> project = projectCache.get(Project.nameKey(id.get()));
+ if (project.isEmpty()) {
+ throw new ResourceNotFoundException(id);
+ }
+ return new ProjectResource(project.get(), currentUserProvider.get());
}
private <T> void writeResponse(HttpServletResponse httpResponse, Response<T> response)
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index b85aeb6..65b03b8 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -80,6 +80,21 @@
Default is 1024.
+cache.projects.refreshAfterWrite
+: The Gerrit configuration of the `projects` cache, as [documented](/Documentation/config-gerrit.html#cache.name.refreshAfterWrite)
+
+ Needs to be set to a relatively low value (e.g. 1 min) for allowing the
+ project settings cache to be kept relatively up-to-date (e.g. within 1 mins)
+ with the incoming replication tasks updating it.
+
+cache.project_list.refreshAfterWrite
+: The Gerrit configuration of the `project_list` cache, as [documented](/Documentation/config-gerrit.html#cache.name.refreshAfterWrite)
+
+ Needs to be set to a relatively low value (e.g. 5 min) for allowing the
+ creation, removal and hiding of projects performed by incoming
+ replication tasks to be reflected relavitely soon (e.g. within 5 mins)
+ in the list of projects.
+
File `@PLUGIN@.config`
-------------------------
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationFanoutConfigIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationFanoutConfigIT.java
index b9ea0c8..4ede1ae 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationFanoutConfigIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationFanoutConfigIT.java
@@ -50,7 +50,8 @@
@UseLocalDisk
@TestPlugin(
name = "pull-replication",
- sysModule = "com.googlesource.gerrit.plugins.replication.pull.PullReplicationModule")
+ sysModule = "com.googlesource.gerrit.plugins.replication.pull.PullReplicationModule",
+ httpModule = "com.googlesource.gerrit.plugins.replication.pull.api.HttpModule")
public class PullReplicationFanoutConfigIT extends LightweightPluginDaemonTest {
private static final Optional<String> ALL_PROJECTS = Optional.empty();
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationIT.java
index d1aaf7c..5d4aeb4 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationIT.java
@@ -48,6 +48,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;
@SkipProjectClone
@@ -351,7 +352,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/ProjectDeletionActionIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectDeletionActionIT.java
index 87a8048..7c7846c 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectDeletionActionIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectDeletionActionIT.java
@@ -92,10 +92,11 @@
@Test
@GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
@GerritConfig(name = "container.replica", value = "true")
- public void shouldReturnForbiddenForUserWithoutPermissionsOnReplica() throws Exception {
+ public void shouldReturnUnauthorizedForUserWithoutPermissionsOnReplica() throws Exception {
httpClientFactory
.create(source)
- .execute(createDeleteRequest(), assertHttpResponseCode(HttpServletResponse.SC_FORBIDDEN));
+ .execute(
+ createDeleteRequest(), assertHttpResponseCode(HttpServletResponse.SC_UNAUTHORIZED));
}
@Test
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectInitializationActionIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectInitializationActionIT.java
index c543969..0f13881 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectInitializationActionIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectInitializationActionIT.java
@@ -184,12 +184,13 @@
@Test
@GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
@GerritConfig(name = "container.replica", value = "true")
- public void shouldReturnForbiddenForUserWithoutPermissionsWhenNodeIsAReplica() throws Exception {
+ public void shouldReturnUnauthorizedForUserWithoutPermissionsWhenNodeIsAReplica()
+ throws Exception {
httpClientFactory
.create(source)
.execute(
createPutRequestWithHeaders(),
- assertHttpResponseCode(HttpServletResponse.SC_FORBIDDEN));
+ assertHttpResponseCode(HttpServletResponse.SC_UNAUTHORIZED));
}
@Test
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 9e5ca8d..5ede668 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
@@ -5,17 +5,25 @@
import static javax.servlet.http.HttpServletResponse.SC_CONFLICT;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.internal.verification.VerificationModeFactory.atLeastOnce;
import static org.mockito.internal.verification.VerificationModeFactory.times;
import com.google.common.net.MediaType;
+import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.restapi.*;
+import com.google.gerrit.server.AnonymousUser;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectResource;
-import com.google.gerrit.server.restapi.project.ProjectsCollection;
+import com.google.gerrit.server.project.ProjectState;
+import com.google.inject.util.Providers;
import java.io.*;
import java.nio.charset.StandardCharsets;
+import java.util.Optional;
import javax.servlet.FilterChain;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
@@ -37,10 +45,12 @@
@Mock private ProjectInitializationAction projectInitializationAction;
@Mock private UpdateHeadAction updateHEADAction;
@Mock private ProjectDeletionAction projectDeletionAction;
- @Mock private ProjectsCollection projectsCollection;
- @Mock private ProjectResource projectResource;
+ @Mock private ProjectCache projectCache;
+ @Mock private ProjectState projectState;
@Mock private ServletOutputStream outputStream;
@Mock private PrintWriter printWriter;
+ @Mock private IdentifiedUser identifiedUserMock;
+ @Mock private AnonymousUser anonymousUserMock;
private final String PLUGIN_NAME = "pull-replication";
private final String PROJECT_NAME = "some-project";
private final String PROJECT_NAME_GIT = "some-project.git";
@@ -60,6 +70,10 @@
private final Response OK_RESPONSE = Response.ok();
private PullReplicationFilter createPullReplicationFilter() {
+ return createPullReplicationFilter(identifiedUserMock);
+ }
+
+ private PullReplicationFilter createPullReplicationFilter(CurrentUser currentUser) {
return new PullReplicationFilter(
fetchAction,
applyObjectAction,
@@ -67,8 +81,9 @@
projectInitializationAction,
updateHEADAction,
projectDeletionAction,
- projectsCollection,
- PLUGIN_NAME);
+ projectCache,
+ PLUGIN_NAME,
+ Providers.of(currentUser));
}
private void defineBehaviours(byte[] payload, String uri) throws Exception {
@@ -76,15 +91,14 @@
InputStream is = new ByteArrayInputStream(payload);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
when(request.getReader()).thenReturn(bufferedReader);
- when(projectsCollection.parse(TopLevelResource.INSTANCE, IdString.fromDecoded(PROJECT_NAME)))
- .thenReturn(projectResource);
+ when(projectCache.get(Project.nameKey(PROJECT_NAME))).thenReturn(Optional.of(projectState));
when(response.getWriter()).thenReturn(printWriter);
}
private void verifyBehaviours() throws Exception {
verify(request, atLeastOnce()).getRequestURI();
verify(request).getReader();
- verify(projectsCollection).parse(TopLevelResource.INSTANCE, IdString.fromDecoded(PROJECT_NAME));
+ verify(projectCache).get(Project.nameKey(PROJECT_NAME));
verify(response).getWriter();
verify(response).setContentType("application/json");
verify(response).setStatus(HttpServletResponse.SC_OK);
@@ -107,7 +121,7 @@
pullReplicationFilter.doFilter(request, response, filterChain);
verifyBehaviours();
- verify(fetchAction).apply(eq(projectResource), any());
+ verify(fetchAction).apply(any(ProjectResource.class), any());
}
@Test
@@ -130,7 +144,7 @@
pullReplicationFilter.doFilter(request, response, filterChain);
verifyBehaviours();
- verify(applyObjectAction).apply(eq(projectResource), any());
+ verify(applyObjectAction).apply(any(ProjectResource.class), any());
}
@Test
@@ -152,7 +166,7 @@
pullReplicationFilter.doFilter(request, response, filterChain);
verifyBehaviours();
- verify(applyObjectsAction).apply(eq(projectResource), any());
+ verify(applyObjectsAction).apply(any(ProjectResource.class), any());
}
@Test
@@ -183,15 +197,14 @@
pullReplicationFilter.doFilter(request, response, filterChain);
verifyBehaviours();
- verify(updateHEADAction).apply(eq(projectResource), any());
+ verify(updateHEADAction).apply(any(ProjectResource.class), any());
}
@Test
public void shouldFilterProjectDeletionAction() throws Exception {
when(request.getRequestURI()).thenReturn(DELETE_PROJECT_URI);
when(request.getMethod()).thenReturn("DELETE");
- when(projectsCollection.parse(TopLevelResource.INSTANCE, IdString.fromDecoded(PROJECT_NAME)))
- .thenReturn(projectResource);
+ when(projectCache.get(Project.nameKey(PROJECT_NAME))).thenReturn(Optional.of(projectState));
when(projectDeletionAction.apply(any(), any())).thenReturn(OK_RESPONSE);
when(response.getWriter()).thenReturn(printWriter);
@@ -199,8 +212,8 @@
pullReplicationFilter.doFilter(request, response, filterChain);
verify(request, times(7)).getRequestURI();
- verify(projectsCollection).parse(TopLevelResource.INSTANCE, IdString.fromDecoded(PROJECT_NAME));
- verify(projectDeletionAction).apply(eq(projectResource), any());
+ verify(projectCache).get(Project.nameKey(PROJECT_NAME));
+ verify(projectDeletionAction).apply(any(ProjectResource.class), any());
verify(response).getWriter();
verify(response).setContentType("application/json");
verify(response).setStatus(OK_RESPONSE.statusCode());
@@ -215,6 +228,17 @@
}
@Test
+ public void shouldGoNextInChainWhenAnonymousRequestUriDoesNotMatch() throws Exception {
+ when(request.getRequestURI()).thenReturn("any-url");
+ lenient().when(response.getOutputStream()).thenReturn(outputStream);
+
+ final PullReplicationFilter pullReplicationFilter =
+ createPullReplicationFilter(anonymousUserMock);
+ pullReplicationFilter.doFilter(request, response, filterChain);
+ verify(filterChain).doFilter(request, response);
+ }
+
+ @Test
public void shouldBe404WhenJsonIsMalformed() throws Exception {
byte[] payloadMalformedJson = "some-json-malformed".getBytes(StandardCharsets.UTF_8);
InputStream is = new ByteArrayInputStream(payloadMalformedJson);
@@ -246,8 +270,7 @@
public void shouldBe500WhenResourceNotFound() throws Exception {
when(request.getRequestURI()).thenReturn(DELETE_PROJECT_URI);
when(request.getMethod()).thenReturn("DELETE");
- when(projectsCollection.parse(TopLevelResource.INSTANCE, IdString.fromDecoded(PROJECT_NAME)))
- .thenReturn(projectResource);
+ when(projectCache.get(Project.nameKey(PROJECT_NAME))).thenReturn(Optional.of(projectState));
when(projectDeletionAction.apply(any(), any()))
.thenThrow(new ResourceNotFoundException("resource not found"));
when(response.getOutputStream()).thenReturn(outputStream);
@@ -280,6 +303,19 @@
}
@Test
+ public void shouldBe401WhenUserIsAnonymous() throws Exception {
+ byte[] payloadFetchAction = "{}".getBytes(StandardCharsets.UTF_8);
+
+ defineBehaviours(payloadFetchAction, FETCH_URI);
+ when(response.getOutputStream()).thenReturn(outputStream);
+
+ PullReplicationFilter pullReplicationFilter = createPullReplicationFilter(anonymousUserMock);
+ pullReplicationFilter.doFilter(request, response, filterChain);
+
+ verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+
+ @Test
public void shouldBe422WhenEntityCannotBeProcessed() throws Exception {
byte[] payloadFetchAction =
("{"
@@ -304,8 +340,7 @@
public void shouldBe409WhenThereIsResourceConflict() throws Exception {
when(request.getRequestURI()).thenReturn(DELETE_PROJECT_URI);
when(request.getMethod()).thenReturn("DELETE");
- when(projectsCollection.parse(TopLevelResource.INSTANCE, IdString.fromDecoded(PROJECT_NAME)))
- .thenReturn(projectResource);
+ when(projectCache.get(Project.nameKey(PROJECT_NAME))).thenReturn(Optional.of(projectState));
when(projectDeletionAction.apply(any(), any()))
.thenThrow(new ResourceConflictException("Resource conflict"));
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/fetch/ApplyObjectIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/fetch/ApplyObjectIT.java
index 161830b..c75d32a 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/fetch/ApplyObjectIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/fetch/ApplyObjectIT.java
@@ -77,12 +77,15 @@
Result pushResult = createChange();
String refName = RefNames.changeMetaRef(pushResult.getChange().getId());
- Optional<RevisionData> revisionData =
- reader.read(
- Project.nameKey(testRepoProjectName), pushResult.getCommit().toObjectId(), refName, 0);
-
RefSpec refSpec = new RefSpec(refName);
- objectUnderTest.apply(project, refSpec, toArray(revisionData));
+ Optional<RevisionData> revisionData;
+ NameKey testRepoKey = Project.nameKey(testRepoProjectName);
+
+ try (Repository repo = repoManager.openRepository(testRepoKey)) {
+ revisionData = reader.read(testRepoKey, repo.exactRef(refName).getObjectId(), refName, 0);
+ objectUnderTest.apply(project, refSpec, toArray(revisionData));
+ }
+
try (Repository repo = repoManager.openRepository(project);
TestRepository<Repository> testRepo = new TestRepository<>(repo); ) {
Optional<RevisionData> newRevisionData =