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();
-  }
-}