Bind GitRepositoryManager and associated factories
Intercept ref-updates at GitRepositoryManager level, wrapping the
repository, ref-database, ref-update and batch ref-update.
The InSyncChangeValidator is not useful anymore because it was covering
a very limited set of use-cases.
NOTE: The integration test does not cover yet the GitRepositoryManager
binding for the refs validation: this is due to the lack of support
of libModules inside the current acceptance test framework in Gerrit.
Change-Id: I4ecdfb1d4a779ab54a15831a692e4b2b697a3021
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/Module.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/Module.java
index d9d062f..4d713ea 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/Module.java
@@ -14,6 +14,7 @@
package com.googlesource.gerrit.plugins.multisite;
+import com.google.common.annotations.VisibleForTesting;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.server.config.SitePaths;
import com.google.gson.Gson;
@@ -43,11 +44,26 @@
public class Module extends LifecycleModule {
private static final Logger log = LoggerFactory.getLogger(Module.class);
- private final Configuration config;
- private final NoteDbStatus noteDb;
+ private Configuration config;
+ private NoteDbStatus noteDb;
+ private final boolean disableGitRepositoryValidation;
@Inject
public Module(Configuration config, NoteDbStatus noteDb) {
+ this(config, noteDb, false);
+ }
+
+ // TODO: It is not possible to properly test the libModules in Gerrit.
+ // Disable the Git repository validation during integration test and then build the necessary
+ // support
+ // in Gerrit for it.
+ @VisibleForTesting
+ public Module(Configuration config, NoteDbStatus noteDb, boolean disableGitRepositoryValidation) {
+ init(config, noteDb);
+ this.disableGitRepositoryValidation = disableGitRepositoryValidation;
+ }
+
+ private void init(Configuration config, NoteDbStatus noteDb) {
this.config = config;
this.noteDb = noteDb;
}
@@ -83,8 +99,7 @@
install(new BrokerForwarderModule(config.kafkaPublisher()));
}
- install(new ValidationModule(config));
-
+ install(new ValidationModule(config, disableGitRepositoryValidation));
bind(Gson.class).toProvider(GsonProvider.class).in(Singleton.class);
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/InSyncChangeValidator.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/InSyncChangeValidator.java
deleted file mode 100644
index 09a1b56..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/InSyncChangeValidator.java
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright (C) 2019 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.
-// Copyright (C) 2018 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.multisite.validation;
-
-import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.server.events.RefReceivedEvent;
-import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.git.validators.RefOperationValidationListener;
-import com.google.gerrit.server.git.validators.ValidationMessage;
-import com.google.gerrit.server.validators.ValidationException;
-import com.google.inject.Inject;
-import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedRefDatabase;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.Repository;
-
-/**
- * Validates if a change can be applied without bringing the system into a split brain situation by
- * verifying that the local status is aligned with the central status as retrieved by the
- * SharedRefDatabase. It also updates the DB to set the new current status for a ref as a
- * consequence of ref updates, creation and deletions. The operation is done for mutable updates
- * only. Operation on immutable ones are always considered valid.
- */
-public class InSyncChangeValidator implements RefOperationValidationListener {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
-
- private final SharedRefDatabase dfsRefDatabase;
- private final GitRepositoryManager repoManager;
-
- @Inject
- public InSyncChangeValidator(SharedRefDatabase dfsRefDatabase, GitRepositoryManager repoManager) {
- this.dfsRefDatabase = dfsRefDatabase;
- this.repoManager = repoManager;
- }
-
- @Override
- public List<ValidationMessage> onRefOperation(RefReceivedEvent refEvent)
- throws ValidationException {
- logger.atFine().log("Validating operation %s", refEvent);
-
- if (isImmutableRef(refEvent.getRefName())) {
- return Collections.emptyList();
- }
-
- try (Repository repo = repoManager.openRepository(refEvent.getProjectNameKey())) {
-
- switch (refEvent.command.getType()) {
- case CREATE:
- return onCreateRef(refEvent);
-
- case UPDATE:
- case UPDATE_NONFASTFORWARD:
- return onUpdateRef(repo, refEvent);
-
- case DELETE:
- return onDeleteRef(repo, refEvent);
-
- default:
- throw new IllegalArgumentException(
- String.format(
- "Unsupported command type '%s', in event %s",
- refEvent.command.getType().name(), refEvent));
- }
- } catch (IOException e) {
- throw new ValidationException(
- "Unable to access repository " + refEvent.getProjectNameKey(), e);
- }
- }
-
- private boolean isImmutableRef(String refName) {
- return refName.startsWith("refs/changes") && !refName.endsWith("/meta");
- }
-
- private List<ValidationMessage> onDeleteRef(Repository repo, RefReceivedEvent refEvent)
- throws ValidationException {
- try {
- Ref localRef = repo.findRef(refEvent.getRefName());
- if (localRef == null) {
- logger.atWarning().log(
- "Local status inconsistent with shared ref database for ref %s. "
- + "Trying to delete it but it is not in the local DB",
- refEvent.getRefName());
-
- throw new ValidationException(
- String.format(
- "Unable to delete ref '%s', cannot find it in the local ref database",
- refEvent.getRefName()));
- }
-
- if (!dfsRefDatabase.compareAndRemove(refEvent.getProjectNameKey().get(), localRef)) {
- throw new ValidationException(
- String.format(
- "Unable to delete ref '%s', the local ObjectId '%s' is not equal to the one "
- + "in the shared ref database",
- refEvent.getRefName(), localRef.getObjectId().getName()));
- }
- } catch (IOException ioe) {
- logger.atSevere().withCause(ioe).log(
- "Local status inconsistent with shared ref database for ref %s. "
- + "Trying to delete it but it is not in the DB",
- refEvent.getRefName());
-
- throw new ValidationException(
- String.format(
- "Unable to delete ref '%s', cannot find it in the shared ref database",
- refEvent.getRefName()),
- ioe);
- }
- return Collections.emptyList();
- }
-
- private List<ValidationMessage> onUpdateRef(Repository repo, RefReceivedEvent refEvent)
- throws ValidationException {
- try {
- Ref localRef = repo.findRef(refEvent.getRefName());
- if (localRef == null) {
- logger.atWarning().log(
- "Local status inconsistent with shared ref database for ref %s. "
- + "Trying to update it but it is not in the local DB",
- refEvent.getRefName());
-
- throw new ValidationException(
- String.format(
- "Unable to update ref '%s', cannot find it in the local ref database",
- refEvent.getRefName()));
- }
-
- Ref newRef = dfsRefDatabase.newRef(refEvent.getRefName(), refEvent.command.getNewId());
- if (!dfsRefDatabase.compareAndPut(refEvent.getProjectNameKey().get(), localRef, newRef)) {
- throw new ValidationException(
- String.format(
- "Unable to update ref '%s', the local objectId '%s' is not equal to the one "
- + "in the shared ref database",
- refEvent.getRefName(), localRef.getObjectId().getName()));
- }
- } catch (IOException ioe) {
- logger.atSevere().withCause(ioe).log(
- "Local status inconsistent with shared ref database for ref %s. "
- + "Trying to update it cannot extract the existing one on DB",
- refEvent.getRefName());
-
- throw new ValidationException(
- String.format(
- "Unable to update ref '%s', cannot open the local ref on the local DB",
- refEvent.getRefName()),
- ioe);
- }
-
- return Collections.emptyList();
- }
-
- private List<ValidationMessage> onCreateRef(RefReceivedEvent refEvent)
- throws ValidationException {
- try {
- Ref newRef = dfsRefDatabase.newRef(refEvent.getRefName(), refEvent.command.getNewId());
- dfsRefDatabase.compareAndCreate(refEvent.getProjectNameKey().get(), newRef);
- } catch (IllegalArgumentException | IOException alreadyInDB) {
- logger.atSevere().withCause(alreadyInDB).log(
- "Local status inconsistent with shared ref database for ref %s. "
- + "Trying to delete it but it is not in the DB",
- refEvent.getRefName());
-
- throw new ValidationException(
- String.format(
- "Unable to update ref '%s', cannot find it in the shared ref database",
- refEvent.getRefName()),
- alreadyInDB);
- }
- return Collections.emptyList();
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationModule.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationModule.java
index b3f99a6..284ea2c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationModule.java
@@ -14,23 +14,29 @@
package com.googlesource.gerrit.plugins.multisite.validation;
-import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.gerrit.server.git.validators.RefOperationValidationListener;
-import com.google.inject.AbstractModule;
+import com.google.gerrit.extensions.config.FactoryModule;
+import com.google.gerrit.server.git.GitRepositoryManager;
import com.googlesource.gerrit.plugins.multisite.Configuration;
import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.zookeeper.ZkValidationModule;
-public class ValidationModule extends AbstractModule {
+public class ValidationModule extends FactoryModule {
+ private final Configuration cfg;
+ private final boolean disableGitRepositoryValidation;
- private Configuration cfg;
-
- public ValidationModule(Configuration cfg) {
+ public ValidationModule(Configuration cfg, boolean disableGitRepositoryValidation) {
this.cfg = cfg;
+ this.disableGitRepositoryValidation = disableGitRepositoryValidation;
}
@Override
protected void configure() {
- DynamicSet.bind(binder(), RefOperationValidationListener.class).to(InSyncChangeValidator.class);
+ factory(MultiSiteRepository.Factory.class);
+ factory(MultiSiteRefDatabase.Factory.class);
+ factory(MultiSiteRefUpdate.Factory.class);
+
+ if (!disableGitRepositoryValidation) {
+ bind(GitRepositoryManager.class).to(MultiSiteGitRepositoryManager.class);
+ }
install(new ZkValidationModule(cfg));
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/EventConsumerIT.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/EventConsumerIT.java
index 1a1a3a0..45f02dc 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/EventConsumerIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/EventConsumerIT.java
@@ -17,10 +17,11 @@
import static com.google.common.truth.Truth.assertThat;
import static java.util.stream.Collectors.toSet;
-import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.GerritConfig;
import com.google.gerrit.acceptance.LogThreshold;
import com.google.gerrit.acceptance.NoHttpd;
-import com.google.gerrit.acceptance.TestPlugin;
+import com.google.gerrit.acceptance.UseLocalDisk;
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.extensions.registration.DynamicSet;
@@ -37,9 +38,9 @@
import com.google.inject.TypeLiteral;
import com.googlesource.gerrit.plugins.multisite.Configuration;
import com.googlesource.gerrit.plugins.multisite.Module;
+import com.googlesource.gerrit.plugins.multisite.NoteDbStatus;
import com.googlesource.gerrit.plugins.multisite.broker.GsonProvider;
import com.googlesource.gerrit.plugins.multisite.forwarder.events.ChangeIndexEvent;
-import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
@@ -54,17 +55,16 @@
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS;
-import org.junit.Before;
import org.junit.Test;
import org.testcontainers.containers.KafkaContainer;
@NoHttpd
@LogThreshold(level = "INFO")
-@TestPlugin(
- name = "multi-site",
- sysModule =
- "com.googlesource.gerrit.plugins.multisite.kafka.consumer.EventConsumerIT$KafkaTestContainerModule")
-public class EventConsumerIT extends LightweightPluginDaemonTest {
+@UseLocalDisk
+public class EventConsumerIT extends AbstractDaemonTest {
+ public static final String GERRIT_CONFIG_KEY = "gerrit.installModule";
+ public static final String GERRIT_CONFIG_VALUE =
+ "com.googlesource.gerrit.plugins.multisite.kafka.consumer.EventConsumerIT$KafkaTestContainerModule";
private static final int QUEUE_POLL_TIMEOUT_MSECS = 10000;
static {
@@ -91,14 +91,15 @@
}
}
- private final File multiSiteConfigFile;
+ private final FileBasedConfig config;
private final Module multiSiteModule;
@Inject
- public KafkaTestContainerModule(SitePaths sitePaths, Module multiSiteModule) {
- this.multiSiteConfigFile =
- sitePaths.etc_dir.resolve(Configuration.MULTI_SITE_CONFIG).toFile();
- this.multiSiteModule = multiSiteModule;
+ public KafkaTestContainerModule(SitePaths sitePaths, NoteDbStatus noteDb) {
+ this.config =
+ new FileBasedConfig(
+ sitePaths.etc_dir.resolve(Configuration.MULTI_SITE_CONFIG).toFile(), FS.DETECTED);
+ this.multiSiteModule = new Module(new Configuration(config), noteDb, true);
}
@Override
@@ -119,7 +120,6 @@
KafkaContainer kafkaContainer = new KafkaContainer();
kafkaContainer.start();
- FileBasedConfig config = new FileBasedConfig(multiSiteConfigFile, FS.DETECTED);
config.setString("kafka", null, "bootstrapServers", kafkaContainer.getBootstrapServers());
config.setBoolean("kafka", "publisher", "enabled", true);
config.setBoolean("kafka", "subscriber", "enabled", true);
@@ -130,17 +130,8 @@
}
}
- @Override
- @Before
- public void setUpTestPlugin() throws Exception {
- super.setUpTestPlugin();
-
- if (!notesMigration.commitChangeWrites()) {
- throw new IllegalStateException("NoteDb is mandatory for running the multi-site plugin");
- }
- }
-
@Test
+ @GerritConfig(name = GERRIT_CONFIG_KEY, value = GERRIT_CONFIG_VALUE)
public void createChangeShouldPropagateChangeIndexAndRefUpdateStreamEvent() throws Exception {
LinkedBlockingQueue<SourceAwareEventWrapper> droppedEventsQueue = captureDroppedEvents();
drainQueue(droppedEventsQueue);
@@ -188,6 +179,7 @@
}
@Test
+ @GerritConfig(name = GERRIT_CONFIG_KEY, value = GERRIT_CONFIG_VALUE)
public void reviewChangeShouldPropagateChangeIndexAndCommentAdded() throws Exception {
LinkedBlockingQueue<SourceAwareEventWrapper> droppedEventsQueue = captureDroppedEvents();
ChangeData change = createChange().getChange();
@@ -235,8 +227,8 @@
TypeLiteral<DynamicSet<DroppedEventListener>> type =
new TypeLiteral<DynamicSet<DroppedEventListener>>() {};
- plugin
- .getSysInjector()
+ server
+ .getTestInjector()
.getInstance(Key.get(type))
.add(
"multi-site",
@@ -258,7 +250,7 @@
private List<Event> drainQueue(LinkedBlockingQueue<SourceAwareEventWrapper> queue)
throws InterruptedException {
- GsonProvider gsonProvider = plugin.getSysInjector().getInstance(Key.get(GsonProvider.class));
+ GsonProvider gsonProvider = server.getTestInjector().getInstance(Key.get(GsonProvider.class));
SourceAwareEventWrapper event;
List<Event> eventsList = new ArrayList<>();
while ((event = queue.poll(QUEUE_POLL_TIMEOUT_MSECS, TimeUnit.MILLISECONDS)) != null) {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/InSyncChangeValidatorTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/InSyncChangeValidatorTest.java
deleted file mode 100644
index 6668529..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/InSyncChangeValidatorTest.java
+++ /dev/null
@@ -1,331 +0,0 @@
-// Copyright (C) 2019 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.multisite.validation;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.hamcrest.CoreMatchers.nullValue;
-import static org.hamcrest.CoreMatchers.sameInstance;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.argThat;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.lenient;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-
-import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.events.RefReceivedEvent;
-import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.git.validators.ValidationMessage;
-import com.google.gerrit.server.validators.ValidationException;
-import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedRefDatabase;
-import java.io.IOException;
-import java.util.List;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.RefDatabase;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.transport.ReceiveCommand;
-import org.eclipse.jgit.transport.ReceiveCommand.Type;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-@RunWith(MockitoJUnitRunner.class)
-public class InSyncChangeValidatorTest {
- static final String PROJECT_NAME = "AProject";
- static final Project.NameKey PROJECT_NAMEKEY = new Project.NameKey(PROJECT_NAME);
- static final String REF_NAME = "refs/heads/master";
- static final String REF_PATCHSET_NAME = "refs/changes/45/1245/1";
- static final String REF_PATCHSET_META_NAME = "refs/changes/45/1245/1/meta";
- static final ObjectId REF_OBJID = ObjectId.fromString("f2ffe80abb77223f3f8921f3f068b0e32d40f798");
- static final ObjectId REF_OBJID_OLD =
- ObjectId.fromString("a9a7a6fd1e9ad39a13fef5e897dc6d932a3282e1");
- static final ReceiveCommand RECEIVE_COMMAND_CREATE_REF =
- new ReceiveCommand(ObjectId.zeroId(), REF_OBJID, REF_NAME, Type.CREATE);
- static final ReceiveCommand RECEIVE_COMMAND_UPDATE_REF =
- new ReceiveCommand(REF_OBJID_OLD, REF_OBJID, REF_NAME, Type.UPDATE);
- static final ReceiveCommand RECEIVE_COMMAND_DELETE_REF =
- new ReceiveCommand(REF_OBJID_OLD, ObjectId.zeroId(), REF_NAME, Type.DELETE);
- static final ReceiveCommand RECEIVE_COMMAND_CREATE_PATCHSET_REF =
- new ReceiveCommand(ObjectId.zeroId(), REF_OBJID, REF_PATCHSET_NAME, Type.CREATE);
- static final ReceiveCommand RECEIVE_COMMAND_CREATE_PATCHSET_META_REF =
- new ReceiveCommand(ObjectId.zeroId(), REF_OBJID, REF_PATCHSET_META_NAME, Type.CREATE);
-
- @Rule public ExpectedException expectedException = ExpectedException.none();
-
- @Mock SharedRefDatabase dfsRefDatabase;
-
- @Mock Repository repo;
-
- @Mock RefDatabase localRefDatabase;
-
- @Mock GitRepositoryManager repoManager;
-
- private InSyncChangeValidator validator;
-
- static class TestRef implements Ref {
- private final String name;
- private final ObjectId objectId;
-
- public TestRef(String name, ObjectId objectId) {
- super();
- this.name = name;
- this.objectId = objectId;
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public boolean isSymbolic() {
- return false;
- }
-
- @Override
- public Ref getLeaf() {
- return null;
- }
-
- @Override
- public Ref getTarget() {
- return null;
- }
-
- @Override
- public ObjectId getObjectId() {
- return objectId;
- }
-
- @Override
- public ObjectId getPeeledObjectId() {
- return null;
- }
-
- @Override
- public boolean isPeeled() {
- return false;
- }
-
- @Override
- public Storage getStorage() {
- return Storage.LOOSE;
- }
- }
-
- static class RefMatcher implements ArgumentMatcher<Ref> {
- private final String name;
- private final ObjectId objectId;
-
- public RefMatcher(String name, ObjectId objectId) {
- super();
- this.name = name;
- this.objectId = objectId;
- }
-
- @Override
- public boolean matches(Ref that) {
- if (that == null) {
- return false;
- }
-
- return name.equals(that.getName()) && objectId.equals(that.getObjectId());
- }
- }
-
- public static Ref eqRef(String name, ObjectId objectId) {
- return argThat(new RefMatcher(name, objectId));
- }
-
- Ref testRef = new TestRef(REF_NAME, REF_OBJID);
- RefReceivedEvent testRefReceivedEvent =
- new RefReceivedEvent() {
-
- @Override
- public String getRefName() {
- return command.getRefName();
- }
-
- @Override
- public com.google.gerrit.reviewdb.client.Project.NameKey getProjectNameKey() {
- return PROJECT_NAMEKEY;
- }
- };
-
- @Before
- public void setUp() throws IOException {
- doReturn(testRef).when(dfsRefDatabase).newRef(REF_NAME, REF_OBJID);
- doReturn(repo).when(repoManager).openRepository(PROJECT_NAMEKEY);
- doReturn(localRefDatabase).when(repo).getRefDatabase();
- lenient()
- .doThrow(new NullPointerException("oldRef is null"))
- .when(dfsRefDatabase)
- .compareAndPut(any(), eq(null), any());
- lenient()
- .doThrow(new NullPointerException("newRef is null"))
- .when(dfsRefDatabase)
- .compareAndPut(any(), any(), eq(null));
- lenient()
- .doThrow(new NullPointerException("project name is null"))
- .when(dfsRefDatabase)
- .compareAndPut(eq(null), any(), any());
-
- validator = new InSyncChangeValidator(dfsRefDatabase, repoManager);
- repoManager.createRepository(PROJECT_NAMEKEY);
- }
-
- @Test
- public void shouldNotVerifyStatusOfImmutablePatchSetRefs() throws Exception {
- testRefReceivedEvent.command = RECEIVE_COMMAND_CREATE_PATCHSET_REF;
- final List<ValidationMessage> validationMessages =
- validator.onRefOperation(testRefReceivedEvent);
-
- assertThat(validationMessages).isEmpty();
-
- verifyZeroInteractions(dfsRefDatabase);
- }
-
- @Test
- public void shouldVerifyStatusOfPatchSetMetaRefs() throws Exception {
- testRefReceivedEvent.command = RECEIVE_COMMAND_CREATE_PATCHSET_META_REF;
-
- Ref testRefMeta = new TestRef(REF_PATCHSET_META_NAME, REF_OBJID);
- doReturn(testRefMeta).when(dfsRefDatabase).newRef(REF_PATCHSET_META_NAME, REF_OBJID);
-
- validator.onRefOperation(testRefReceivedEvent);
-
- verify(dfsRefDatabase)
- .compareAndCreate(eq(PROJECT_NAME), eqRef(REF_PATCHSET_META_NAME, REF_OBJID));
- }
-
- @Test
- public void shouldInsertNewRefInDfsDatabaseWhenHandlingRefCreationEvents() throws Exception {
- testRefReceivedEvent.command = RECEIVE_COMMAND_CREATE_REF;
-
- final List<ValidationMessage> validationMessages =
- validator.onRefOperation(testRefReceivedEvent);
-
- assertThat(validationMessages).isEmpty();
- verify(dfsRefDatabase).compareAndCreate(eq(PROJECT_NAME), eqRef(REF_NAME, REF_OBJID));
- }
-
- @Test
- public void shouldFailRefCreationIfInsertANewRefInDfsDatabaseFails() throws Exception {
- testRefReceivedEvent.command = RECEIVE_COMMAND_CREATE_REF;
-
- IllegalArgumentException alreadyInDb = new IllegalArgumentException("obj is already in db");
-
- doThrow(alreadyInDb)
- .when(dfsRefDatabase)
- .compareAndCreate(eq(PROJECT_NAME), eqRef(REF_NAME, REF_OBJID));
-
- expectedException.expect(ValidationException.class);
- expectedException.expectCause(sameInstance(alreadyInDb));
-
- validator.onRefOperation(testRefReceivedEvent);
- }
-
- @Test
- public void shouldUpdateRefInDfsDatabaseWhenHandlingRefUpdateEvents() throws Exception {
- testRefReceivedEvent.command = RECEIVE_COMMAND_UPDATE_REF;
- doReturn(new TestRef(REF_NAME, REF_OBJID_OLD)).when(localRefDatabase).getRef(REF_NAME);
- doReturn(true)
- .when(dfsRefDatabase)
- .compareAndPut(
- eq(PROJECT_NAME), eqRef(REF_NAME, REF_OBJID_OLD), eqRef(REF_NAME, REF_OBJID));
-
- final List<ValidationMessage> validationMessages =
- validator.onRefOperation(testRefReceivedEvent);
-
- assertThat(validationMessages).isEmpty();
- verify(dfsRefDatabase)
- .compareAndPut(
- eq(PROJECT_NAME), eqRef(REF_NAME, REF_OBJID_OLD), eqRef(REF_NAME, REF_OBJID));
- }
-
- @Test
- public void shouldFailRefUpdateIfRefUpdateInDfsRefDatabaseReturnsFalse() throws Exception {
- testRefReceivedEvent.command = RECEIVE_COMMAND_UPDATE_REF;
- doReturn(new TestRef(REF_NAME, REF_OBJID_OLD)).when(localRefDatabase).getRef(REF_NAME);
- doReturn(false)
- .when(dfsRefDatabase)
- .compareAndPut(
- eq(PROJECT_NAME), eqRef(REF_NAME, REF_OBJID_OLD), eqRef(REF_NAME, REF_OBJID));
- expectedException.expect(ValidationException.class);
- expectedException.expectCause(nullValue(Exception.class));
-
- validator.onRefOperation(testRefReceivedEvent);
- }
-
- @Test
- public void shouldFailRefUpdateIfRefIsNotInDfsRefDatabase() throws Exception {
- testRefReceivedEvent.command = RECEIVE_COMMAND_UPDATE_REF;
- doReturn(null).when(localRefDatabase).getRef(REF_NAME);
-
- expectedException.expect(ValidationException.class);
- expectedException.expectCause(nullValue(Exception.class));
-
- validator.onRefOperation(testRefReceivedEvent);
- }
-
- @Test
- public void shouldDeleteRefInDfsDatabaseWhenHandlingRefDeleteEvents() throws Exception {
- testRefReceivedEvent.command = RECEIVE_COMMAND_DELETE_REF;
- doReturn(new TestRef(REF_NAME, REF_OBJID_OLD)).when(localRefDatabase).getRef(REF_NAME);
- doReturn(true)
- .when(dfsRefDatabase)
- .compareAndRemove(eq(PROJECT_NAME), eqRef(REF_NAME, REF_OBJID_OLD));
-
- final List<ValidationMessage> validationMessages =
- validator.onRefOperation(testRefReceivedEvent);
-
- assertThat(validationMessages).isEmpty();
-
- verify(dfsRefDatabase).compareAndRemove(eq(PROJECT_NAME), eqRef(REF_NAME, REF_OBJID_OLD));
- }
-
- @Test
- public void shouldFailRefDeletionIfRefDeletionInDfsRefDatabaseReturnsFalse() throws Exception {
- testRefReceivedEvent.command = RECEIVE_COMMAND_DELETE_REF;
- doReturn(new TestRef(REF_NAME, REF_OBJID_OLD)).when(localRefDatabase).getRef(REF_NAME);
- doReturn(false)
- .when(dfsRefDatabase)
- .compareAndRemove(eq(PROJECT_NAME), eqRef(REF_NAME, REF_OBJID_OLD));
-
- expectedException.expect(ValidationException.class);
- expectedException.expectCause(nullValue(Exception.class));
-
- validator.onRefOperation(testRefReceivedEvent);
- }
-
- @Test
- public void shouldFailRefDeletionIfRefIsNotInDfsDatabase() throws Exception {
- testRefReceivedEvent.command = RECEIVE_COMMAND_DELETE_REF;
- doReturn(null).when(localRefDatabase).getRef(REF_NAME);
-
- expectedException.expect(ValidationException.class);
- expectedException.expectCause(nullValue(Exception.class));
-
- validator.onRefOperation(testRefReceivedEvent);
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationIT.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationIT.java
deleted file mode 100644
index c65002a..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationIT.java
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright (C) 2019 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.multisite.validation;
-
-import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
-import com.google.gerrit.acceptance.LogThreshold;
-import com.google.gerrit.acceptance.NoHttpd;
-import com.google.gerrit.acceptance.PushOneCommit;
-import com.google.gerrit.acceptance.TestPlugin;
-import com.google.gerrit.extensions.events.LifecycleListener;
-import com.google.gerrit.lifecycle.LifecycleModule;
-import com.google.inject.Inject;
-import com.googlesource.gerrit.plugins.multisite.Configuration;
-import com.googlesource.gerrit.plugins.multisite.Module;
-import com.googlesource.gerrit.plugins.multisite.NoteDbStatus;
-import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.zookeeper.ZookeeperTestContainerSupport;
-import org.junit.Before;
-import org.junit.Test;
-
-@NoHttpd
-@LogThreshold(level = "INFO")
-@TestPlugin(
- name = "multi-site",
- sysModule =
- "com.googlesource.gerrit.plugins.multisite.validation.ValidationIT$ZookeeperTestModule")
-public class ValidationIT extends LightweightPluginDaemonTest {
-
- static {
- System.setProperty("gerrit.notedb", "ON");
- }
-
- public static class ZookeeperTestModule extends LifecycleModule {
-
- public class ZookeeperStopAtShutdown implements LifecycleListener {
- private final ZookeeperTestContainerSupport zookeeperContainer;
-
- public ZookeeperStopAtShutdown(ZookeeperTestContainerSupport zk) {
- this.zookeeperContainer = zk;
- }
-
- @Override
- public void stop() {
- zookeeperContainer.cleanup();
- }
-
- @Override
- public void start() {
- // Do nothing
- }
- }
-
- private final NoteDbStatus noteDb;
-
- @Inject
- public ZookeeperTestModule(NoteDbStatus noteDb) {
- this.noteDb = noteDb;
- }
-
- @Override
- protected void configure() {
- ZookeeperTestContainerSupport zookeeperContainer = new ZookeeperTestContainerSupport(true);
- Configuration multiSiteConfig = zookeeperContainer.getConfig();
- bind(Configuration.class).toInstance(multiSiteConfig);
- install(new Module(multiSiteConfig, noteDb));
-
- listener().toInstance(new ZookeeperStopAtShutdown(zookeeperContainer));
- }
- }
-
- @Override
- @Before
- public void setUpTestPlugin() throws Exception {
- super.setUpTestPlugin();
-
- if (!notesMigration.commitChangeWrites()) {
- throw new IllegalStateException("NoteDb is mandatory for running the multi-site plugin");
- }
- }
-
- @Test
- public void inSyncChangeValidatorShouldAcceptNewChange() throws Exception {
- final PushOneCommit.Result change =
- createCommitAndPush(testRepo, "refs/heads/master", "msg", "file", "content");
-
- change.assertOkStatus();
- }
-}