Merge branch 'stable-3.0'
* stable-3.0:
Adapt to JGit 5.3.x for Gerrit v3.0
Add project custom enforcement policy
Clean up projects from the SharedRef Db
Adapt the local env. setup to work with stable-3.0
Change-Id: I9a42af314c6137f9432dd2edbe457fbc5911a582
diff --git a/setup_local_env/configs/gerrit.config b/setup_local_env/configs/gerrit.config
index 348b90e..f0f56dc 100644
--- a/setup_local_env/configs/gerrit.config
+++ b/setup_local_env/configs/gerrit.config
@@ -3,6 +3,7 @@
serverId = 69ec38f0-350e-4d9c-96d4-bc956f2faaac
canonicalWebUrl = $GERRIT_CANONICAL_WEB_URL
installModule = com.googlesource.gerrit.plugins.multisite.Module # multi-site needs to be a gerrit lib
+ installDbModule = com.googlesource.gerrit.plugins.multisite.GitModule
[database]
type = h2
database = $LOCATION_TEST_SITE/db/ReviewDB
diff --git a/setup_local_env/setup.sh b/setup_local_env/setup.sh
index 5f4d076..94fc972 100755
--- a/setup_local_env/setup.sh
+++ b/setup_local_env/setup.sh
@@ -317,11 +317,11 @@
cp -f $MULTISITE_LIB_LOCATION $DEPLOYMENT_LOCATION/multi-site.jar >/dev/null 2>&1 || { echo >&2 "$MULTISITE_LIB_LOCATION: Not able to copy the file. Aborting"; exit 1; }
fi
if [ $DOWNLOAD_WEBSESSION_FLATFILE = "true" ];then
- echo "Downloading websession-flatfile plugin stable 2.16"
- wget https://gerrit-ci.gerritforge.com/view/Plugins-stable-2.16/job/plugin-websession-flatfile-bazel-master-stable-2.16/lastSuccessfulBuild/artifact/bazel-genfiles/plugins/websession-flatfile/websession-flatfile.jar \
+ echo "Downloading websession-flatfile plugin stable 3.0"
+ wget https://gerrit-ci.gerritforge.com/view/Plugins-stable-3.0/job/plugin-websession-flatfile-bazel-master-stable-3.0/lastSuccessfulBuild/artifact/bazel-genfiles/plugins/websession-flatfile/websession-flatfile.jar \
-O $DEPLOYMENT_LOCATION/websession-flatfile.jar || { echo >&2 "Cannot download websession-flatfile plugin: Check internet connection. Abort\
ing"; exit 1; }
- wget https://gerrit-ci.gerritforge.com/view/Plugins-stable-2.16/job/plugin-healthcheck-bazel-stable-2.16/lastSuccessfulBuild/artifact/bazel-genfiles/plugins/healthcheck/healthcheck.jar \
+ wget https://gerrit-ci.gerritforge.com/view/Plugins-stable-3.0/job/plugin-healthcheck-bazel-stable-3.0/lastSuccessfulBuild/artifact/bazel-genfiles/plugins/healthcheck/healthcheck.jar \
-O $DEPLOYMENT_LOCATION/healthcheck.jar || { echo >&2 "Cannot download healthcheck plugin: Check internet connection. Abort\
ing"; exit 1; }
else
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/Configuration.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/Configuration.java
index 3756097..72fec47 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/Configuration.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/Configuration.java
@@ -22,12 +22,16 @@
import com.google.common.base.CaseFormat;
import com.google.common.base.Strings;
import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.MultimapBuilder;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.spi.Message;
import com.googlesource.gerrit.plugins.multisite.forwarder.events.EventFamily;
+import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedRefEnforcement.EnforcePolicy;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
@@ -517,6 +521,8 @@
public static final String KEY_MIGRATE = "migrate";
public final String TRANSACTION_LOCK_TIMEOUT_KEY = "transactionLockTimeoutMs";
+ public static final String SUBSECTION_ENFORCEMENT_RULES = "enforcementRules";
+
private final String connectionString;
private final String root;
private final int sessionTimeoutMs;
@@ -529,6 +535,8 @@
private final int casMaxRetries;
private final boolean enabled;
+ private final Multimap<EnforcePolicy, String> enforcementRules;
+
private final Long transactionLockTimeOut;
private CuratorFramework build;
@@ -600,7 +608,14 @@
checkArgument(StringUtils.isNotEmpty(connectionString), "zookeeper.%s contains no servers");
- enabled = Configuration.getBoolean(cfg, SECTION, SUBSECTION, ENABLE_KEY, true);
+ enabled = Configuration.getBoolean(cfg, SECTION, null, ENABLE_KEY, true);
+
+ enforcementRules = MultimapBuilder.hashKeys().arrayListValues().build();
+ for (EnforcePolicy policy : EnforcePolicy.values()) {
+ enforcementRules.putAll(
+ policy,
+ Configuration.getList(cfg, SECTION, SUBSECTION_ENFORCEMENT_RULES, policy.name()));
+ }
}
public CuratorFramework buildCurator() {
@@ -632,6 +647,15 @@
public boolean isEnabled() {
return enabled;
}
+
+ public Multimap<EnforcePolicy, String> getEnforcementRules() {
+ return enforcementRules;
+ }
+ }
+
+ static List<String> getList(
+ Supplier<Config> cfg, String section, String subsection, String name) {
+ return ImmutableList.copyOf(cfg.get().getStringList(section, subsection, name));
}
static boolean getBoolean(
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRefDatabase.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRefDatabase.java
index 630b091..e1d1c65 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRefDatabase.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRefDatabase.java
@@ -99,11 +99,6 @@
}
@Override
- public Ref getRef(String name) throws IOException {
- return refDatabase.getRef(name);
- }
-
- @Override
public String toString() {
return refDatabase.toString();
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectDeletedSharedDbCleanup.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectDeletedSharedDbCleanup.java
new file mode 100644
index 0000000..7f58d39
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectDeletedSharedDbCleanup.java
@@ -0,0 +1,53 @@
+// 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.common.flogger.FluentLogger;
+import com.google.gerrit.extensions.events.ProjectDeletedListener;
+import com.google.inject.Inject;
+import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedRefDatabase;
+import java.io.IOException;
+
+public class ProjectDeletedSharedDbCleanup implements ProjectDeletedListener {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ private final SharedRefDatabase sharedDb;
+
+ private final ValidationMetrics validationMetrics;
+
+ @Inject
+ public ProjectDeletedSharedDbCleanup(
+ SharedRefDatabase sharedDb, ValidationMetrics validationMetrics) {
+ this.sharedDb = sharedDb;
+ this.validationMetrics = validationMetrics;
+ }
+
+ @Override
+ public void onProjectDeleted(Event event) {
+ String projectName = event.getProjectName();
+ logger.atInfo().log(
+ "Deleting project '%s'. Will perform a cleanup in Shared-Ref database.", projectName);
+
+ try {
+ sharedDb.removeProject(projectName);
+ } catch (IOException e) {
+ validationMetrics.incrementSplitBrain();
+ logger.atSevere().withCause(e).log(
+ "Project '%s' deleted from GIT but it was not able to cleanup"
+ + " from Shared-Ref database",
+ projectName);
+ }
+ }
+}
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 e10af32..001fe1b 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
@@ -18,6 +18,7 @@
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Scopes;
import com.googlesource.gerrit.plugins.multisite.Configuration;
+import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.CustomSharedRefEnforcementByProject;
import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.DefaultSharedRefEnforcement;
import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedRefEnforcement;
import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.zookeeper.ZkValidationModule;
@@ -39,7 +40,14 @@
factory(BatchRefUpdateValidator.Factory.class);
bind(GitRepositoryManager.class).to(MultiSiteGitRepositoryManager.class);
- bind(SharedRefEnforcement.class).to(DefaultSharedRefEnforcement.class).in(Scopes.SINGLETON);
+ if (cfg.getZookeeperConfig().getEnforcementRules().isEmpty()) {
+ bind(SharedRefEnforcement.class).to(DefaultSharedRefEnforcement.class).in(Scopes.SINGLETON);
+ } else {
+ bind(SharedRefEnforcement.class)
+ .to(CustomSharedRefEnforcementByProject.class)
+ .in(Scopes.SINGLETON);
+ }
+
install(new ZkValidationModule(cfg));
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/CustomSharedRefEnforcementByProject.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/CustomSharedRefEnforcementByProject.java
new file mode 100644
index 0000000..7a806a8
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/CustomSharedRefEnforcementByProject.java
@@ -0,0 +1,103 @@
+// 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.dfsrefdb;
+
+import static com.google.common.base.Suppliers.memoize;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Splitter;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Inject;
+import com.googlesource.gerrit.plugins.multisite.Configuration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+public class CustomSharedRefEnforcementByProject implements SharedRefEnforcement {
+ private static final String ALL = ".*";
+
+ private final Supplier<Map<String, Map<String, EnforcePolicy>>> predefEnforcements;
+
+ @Inject
+ public CustomSharedRefEnforcementByProject(Configuration config) {
+ this.predefEnforcements = memoize(() -> parseDryRunEnforcementsToMap(config));
+ }
+
+ private static Map<String, Map<String, EnforcePolicy>> parseDryRunEnforcementsToMap(
+ Configuration config) {
+ Map<String, Map<String, EnforcePolicy>> enforcementMap = new HashMap<>();
+
+ for (Map.Entry<EnforcePolicy, String> enforcementEntry :
+ config.getZookeeperConfig().getEnforcementRules().entries()) {
+ parseEnforcementEntry(enforcementMap, enforcementEntry);
+ }
+
+ return enforcementMap;
+ }
+
+ private static void parseEnforcementEntry(
+ Map<String, Map<String, EnforcePolicy>> enforcementMap,
+ Map.Entry<EnforcePolicy, String> enforcementEntry) {
+ Iterator<String> projectAndRef = Splitter.on(':').split(enforcementEntry.getValue()).iterator();
+ EnforcePolicy enforcementPolicy = enforcementEntry.getKey();
+
+ if (projectAndRef.hasNext()) {
+ String projectName = emptyToAll(projectAndRef.next());
+ String refName = emptyToAll(projectAndRef.hasNext() ? projectAndRef.next() : ALL);
+
+ Map<String, EnforcePolicy> existingOrDefaultRef =
+ enforcementMap.getOrDefault(projectName, new HashMap<>());
+
+ existingOrDefaultRef.put(refName, enforcementPolicy);
+
+ enforcementMap.put(projectName, existingOrDefaultRef);
+ }
+ }
+
+ private static String emptyToAll(String value) {
+ return value.trim().isEmpty() ? ALL : value;
+ }
+
+ @Override
+ public EnforcePolicy getPolicy(String projectName, String refName) {
+ if (isRefToBeIgnoredBySharedRefDb(refName)) {
+ return EnforcePolicy.IGNORED;
+ }
+
+ return getRefEnforcePolicy(projectName, refName);
+ }
+
+ private EnforcePolicy getRefEnforcePolicy(String projectName, String refName) {
+ Map<String, EnforcePolicy> orDefault =
+ predefEnforcements
+ .get()
+ .getOrDefault(
+ projectName, predefEnforcements.get().getOrDefault(ALL, ImmutableMap.of()));
+
+ return MoreObjects.firstNonNull(
+ orDefault.getOrDefault(refName, orDefault.get(ALL)), EnforcePolicy.REQUIRED);
+ }
+
+ @Override
+ public EnforcePolicy getPolicy(String projectName) {
+ Map<String, EnforcePolicy> policiesForProject =
+ predefEnforcements
+ .get()
+ .getOrDefault(
+ projectName, predefEnforcements.get().getOrDefault(ALL, ImmutableMap.of()));
+ return policiesForProject.getOrDefault(ALL, EnforcePolicy.REQUIRED);
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/SharedRefDatabase.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/SharedRefDatabase.java
index 790935b..cfbd783 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/SharedRefDatabase.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/SharedRefDatabase.java
@@ -156,4 +156,12 @@
* @return true if the ref exists on the project
*/
boolean exists(String project, String refName);
+
+ /**
+ * Clean project path from SharedRefDatabase
+ *
+ * @param project project name
+ * @throws IOException
+ */
+ void removeProject(String project) throws IOException;
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/ZkSharedRefDatabase.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/ZkSharedRefDatabase.java
index 321ad8a..afd3766 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/ZkSharedRefDatabase.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/ZkSharedRefDatabase.java
@@ -73,6 +73,15 @@
}
@Override
+ public void removeProject(String project) throws IOException {
+ try {
+ client.delete().deletingChildrenIfNeeded().forPath("/" + project);
+ } catch (Exception e) {
+ throw new IOException(String.format("Not able to delete project '%s'", project), e);
+ }
+ }
+
+ @Override
public boolean exists(String project, String refName) throws ZookeeperRuntimeException {
try {
return client.checkExists().forPath(pathFor(project, refName)) != null;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/ZkValidationModule.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/ZkValidationModule.java
index 927591e..3e8f75a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/ZkValidationModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/ZkValidationModule.java
@@ -14,8 +14,11 @@
package com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.zookeeper;
+import com.google.gerrit.extensions.events.ProjectDeletedListener;
+import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.inject.AbstractModule;
import com.googlesource.gerrit.plugins.multisite.Configuration;
+import com.googlesource.gerrit.plugins.multisite.validation.ProjectDeletedSharedDbCleanup;
import com.googlesource.gerrit.plugins.multisite.validation.ZkConnectionConfig;
import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedRefDatabase;
import org.apache.curator.framework.CuratorFramework;
@@ -38,5 +41,7 @@
new ZkConnectionConfig(
cfg.getZookeeperConfig().buildCasRetryPolicy(),
cfg.getZookeeperConfig().getZkInterProcessLockTimeOut()));
+
+ DynamicSet.bind(binder(), ProjectDeletedListener.class).to(ProjectDeletedSharedDbCleanup.class);
}
}
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index e3abe59..be32c27 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -187,6 +187,34 @@
: Enable the use of a shared ref-database
Defaults: true
+```ref-database.enforcementRules.<policy>```
+: Level of consistency enforcement across sites on a project:refs basis.
+ Supports multiple values for enforcing the policy on multiple projects or refs.
+ If the project or ref is omitted, apply the policy to all projects or all refs.
+
+ The <policy> can be one of the following values:
+
+ 1. REQUIRED - Throw an exception if a git ref-update is processed again
+ a local ref not yet in sync with the shared ref-database.
+ The user transaction is cancelled. The Gerrit GUI (or the Git client)
+ receives an HTTP 500 - Internal Server Error.
+
+ 2. DESIRED - Validate the git ref-update against the shared ref-database.
+ Any misaligned is logged in errors_log file but the user operation is allowed
+ to continue successfully.
+
+ 3. IGNORED - Ignore any validation against the shared ref-database.
+
+ *Example:*
+ ```
+ [ref-database "enforcementRules"]
+ DESIRED = AProject:/refs/heads/feature
+ ```
+
+ Relax the alignment with the shared ref-database for AProject on refs/heads/feature.
+
+ Defaults: No rules = All projects are REQUIRED to be consistent on all refs.
+
```ref-database.zookeeper.connectString```
: Connection string to Zookeeper
@@ -230,14 +258,14 @@
operations on Zookeeper
Defaults: 1000
-
+
```ref-database.zookeeper.casRetryPolicyMaxSleepTimeMs```
: Configuration for the maximum sleep timeout in milliseconds of the
BoundedExponentialBackoffRetry policy used for the Compare and Swap
operations on Zookeeper
Defaults: 3000
-
+
```ref-database.zookeeper.casRetryPolicyMaxRetries```
: Configuration for the maximum number of retries of the
BoundedExponentialBackoffRetry policy used for the Compare and Swap
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/CustomSharedRefEnforcementByProjectTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/CustomSharedRefEnforcementByProjectTest.java
new file mode 100644
index 0000000..e4d7861
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/CustomSharedRefEnforcementByProjectTest.java
@@ -0,0 +1,159 @@
+// 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.dfsrefdb.zookeeper;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedRefDatabase.newRef;
+
+import com.googlesource.gerrit.plugins.multisite.Configuration;
+import com.googlesource.gerrit.plugins.multisite.Configuration.ZookeeperConfig;
+import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.CustomSharedRefEnforcementByProject;
+import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedRefEnforcement;
+import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedRefEnforcement.EnforcePolicy;
+import java.util.Arrays;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Ref;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CustomSharedRefEnforcementByProjectTest implements RefFixture {
+
+ SharedRefEnforcement refEnforcement;
+
+ @Before
+ public void setUp() {
+ Config multiSiteConfig = new Config();
+ multiSiteConfig.setStringList(
+ ZookeeperConfig.SECTION,
+ ZookeeperConfig.SUBSECTION_ENFORCEMENT_RULES,
+ EnforcePolicy.DESIRED.name(),
+ Arrays.asList(
+ "ProjectOne",
+ "ProjectTwo:refs/heads/master/test",
+ "ProjectTwo:refs/heads/master/test2"));
+ multiSiteConfig.setString(
+ ZookeeperConfig.SECTION,
+ ZookeeperConfig.SUBSECTION_ENFORCEMENT_RULES,
+ EnforcePolicy.IGNORED.name(),
+ ":refs/heads/master/test");
+
+ refEnforcement = newCustomRefEnforcement(multiSiteConfig);
+ }
+
+ @Test
+ public void projectOneShouldReturnDesiredForAllRefs() {
+ Ref aRef = newRef("refs/heads/master/2", AN_OBJECT_ID_1);
+ assertThat(refEnforcement.getPolicy("ProjectOne", aRef.getName()))
+ .isEqualTo(EnforcePolicy.DESIRED);
+ }
+
+ @Test
+ public void projectOneEnforcementShouldAlwaysPrevail() {
+ Ref aRef = newRef("refs/heads/master/test", AN_OBJECT_ID_1);
+ assertThat(refEnforcement.getPolicy("ProjectOne", aRef.getName()))
+ .isEqualTo(EnforcePolicy.DESIRED);
+ }
+
+ @Test
+ public void aNonListedProjectShouldIgnoreRefForMasterTest() {
+ Ref aRef = newRef("refs/heads/master/test", AN_OBJECT_ID_1);
+ assertThat(refEnforcement.getPolicy("NonListedProject", aRef.getName()))
+ .isEqualTo(EnforcePolicy.IGNORED);
+ }
+
+ @Test
+ public void projectTwoSpecificRefShouldReturnDesiredPolicy() {
+ Ref refOne = newRef("refs/heads/master/test", AN_OBJECT_ID_1);
+ Ref refTwo = newRef("refs/heads/master/test2", AN_OBJECT_ID_1);
+
+ assertThat(refEnforcement.getPolicy("ProjectTwo", refOne.getName()))
+ .isEqualTo(EnforcePolicy.DESIRED);
+ assertThat(refEnforcement.getPolicy("ProjectTwo", refTwo.getName()))
+ .isEqualTo(EnforcePolicy.DESIRED);
+ }
+
+ @Test
+ public void aNonListedProjectShouldReturnRequired() {
+ Ref refOne = newRef("refs/heads/master/newChange", AN_OBJECT_ID_1);
+ assertThat(refEnforcement.getPolicy("NonListedProject", refOne.getName()))
+ .isEqualTo(EnforcePolicy.REQUIRED);
+ }
+
+ @Test
+ public void aNonListedRefInProjectShouldReturnRequired() {
+ Ref refOne = newRef("refs/heads/master/test3", AN_OBJECT_ID_1);
+ assertThat(refEnforcement.getPolicy("ProjectTwo", refOne.getName()))
+ .isEqualTo(EnforcePolicy.REQUIRED);
+ }
+
+ @Test
+ public void aNonListedProjectAndRefShouldReturnRequired() {
+ Ref refOne = newRef("refs/heads/master/test3", AN_OBJECT_ID_1);
+ assertThat(refEnforcement.getPolicy("NonListedProject", refOne.getName()))
+ .isEqualTo(EnforcePolicy.REQUIRED);
+ }
+
+ @Test
+ public void getProjectPolicyForProjectOneShouldRetrunDesired() {
+ assertThat(refEnforcement.getPolicy("ProjectOne")).isEqualTo(EnforcePolicy.DESIRED);
+ }
+
+ @Test
+ public void getProjectPolicyForProjectTwoShouldReturnRequired() {
+ assertThat(refEnforcement.getPolicy("ProjectTwo")).isEqualTo(EnforcePolicy.REQUIRED);
+ }
+
+ @Test
+ public void getProjectPolicyForNonListedProjectShouldReturnRequired() {
+ assertThat(refEnforcement.getPolicy("NonListedProject")).isEqualTo(EnforcePolicy.REQUIRED);
+ }
+
+ @Test
+ public void getProjectPolicyForNonListedProjectWhenSingleProject() {
+ SharedRefEnforcement customEnforcement =
+ newCustomRefEnforcementWithValue(EnforcePolicy.DESIRED, ":refs/heads/master");
+
+ assertThat(customEnforcement.getPolicy("NonListedProject")).isEqualTo(EnforcePolicy.REQUIRED);
+ }
+
+ @Test
+ public void getANonListedProjectWhenOnlyOneProjectIsListedShouldReturnRequired() {
+ SharedRefEnforcement customEnforcement =
+ newCustomRefEnforcementWithValue(EnforcePolicy.DESIRED, "AProject:");
+ assertThat(customEnforcement.getPolicy("NonListedProject", "refs/heads/master"))
+ .isEqualTo(EnforcePolicy.REQUIRED);
+ }
+
+ private SharedRefEnforcement newCustomRefEnforcementWithValue(
+ EnforcePolicy policy, String... projectAndRefs) {
+ Config multiSiteConfig = new Config();
+ multiSiteConfig.setStringList(
+ ZookeeperConfig.SECTION,
+ ZookeeperConfig.SUBSECTION_ENFORCEMENT_RULES,
+ policy.name(),
+ Arrays.asList(projectAndRefs));
+ return newCustomRefEnforcement(multiSiteConfig);
+ }
+
+ private SharedRefEnforcement newCustomRefEnforcement(Config multiSiteConfig) {
+ return new CustomSharedRefEnforcementByProject(
+ new Configuration(multiSiteConfig, new Config()));
+ }
+
+ @Override
+ public String testBranch() {
+ return "fooBranch";
+ }
+}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/ZkSharedRefDatabaseTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/ZkSharedRefDatabaseTest.java
index 9e85563..8819b8b 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/ZkSharedRefDatabaseTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/ZkSharedRefDatabaseTest.java
@@ -15,7 +15,12 @@
package com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.zookeeper;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
+import com.google.gerrit.extensions.api.changes.NotifyHandling;
+import com.google.gerrit.extensions.events.ProjectDeletedListener;
+import com.googlesource.gerrit.plugins.multisite.validation.ProjectDeletedSharedDbCleanup;
+import com.googlesource.gerrit.plugins.multisite.validation.ValidationMetrics;
import com.googlesource.gerrit.plugins.multisite.validation.ZkConnectionConfig;
import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.DefaultSharedRefEnforcement;
import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedRefDatabase;
@@ -36,6 +41,8 @@
ZkSharedRefDatabase zkSharedRefDatabase;
SharedRefEnforcement refEnforcement;
+ ValidationMetrics mockValidationMetrics;
+
@Before
public void setup() {
refEnforcement = new DefaultSharedRefEnforcement();
@@ -50,6 +57,8 @@
new ZkConnectionConfig(
new RetryNTimes(NUMBER_OF_RETRIES, SLEEP_BETWEEN_RETRIES_MS),
TRANSACTION_LOCK_TIMEOUT));
+
+ mockValidationMetrics = mock(ValidationMetrics.class);
}
@After
@@ -156,8 +165,62 @@
return SharedRefDatabase.newRef(aBranchRef(), objectId);
}
+ @Test
+ public void removeProjectShouldRemoveTheWholePathInZk() throws Exception {
+ String projectName = A_TEST_PROJECT_NAME;
+ Ref someRef = refOf(AN_OBJECT_ID_1);
+
+ zookeeperContainer.createRefInZk(projectName, someRef);
+
+ assertThat(zookeeperContainer.readRefValueFromZk(projectName, someRef))
+ .isEqualTo(AN_OBJECT_ID_1);
+
+ assertThat(getNumChildrenForPath("/")).isEqualTo(1);
+
+ zkSharedRefDatabase.removeProject(projectName);
+
+ assertThat(getNumChildrenForPath("/")).isEqualTo(0);
+ }
+
+ @Test
+ public void aDeleteProjectEventShouldCleanupProjectFromZk() throws Exception {
+ String projectName = A_TEST_PROJECT_NAME;
+ Ref someRef = refOf(AN_OBJECT_ID_1);
+ ProjectDeletedSharedDbCleanup projectDeletedSharedDbCleanup =
+ new ProjectDeletedSharedDbCleanup(zkSharedRefDatabase, mockValidationMetrics);
+
+ ProjectDeletedListener.Event event =
+ new ProjectDeletedListener.Event() {
+ @Override
+ public String getProjectName() {
+ return projectName;
+ }
+
+ @Override
+ public NotifyHandling getNotify() {
+ return NotifyHandling.NONE;
+ }
+ };
+
+ zookeeperContainer.createRefInZk(projectName, someRef);
+
+ assertThat(getNumChildrenForPath("/")).isEqualTo(1);
+
+ projectDeletedSharedDbCleanup.onProjectDeleted(event);
+
+ assertThat(getNumChildrenForPath("/")).isEqualTo(0);
+ }
+
@Override
public String testBranch() {
return "branch_" + nameRule.getMethodName();
}
+
+ private int getNumChildrenForPath(String path) throws Exception {
+ return zookeeperContainer
+ .getCurator()
+ .checkExists()
+ .forPath(String.format(path))
+ .getNumChildren();
+ }
}