Merge branch 'stable-3.2' into stable-3.3 * stable-3.2: Remove unmaintained attempt to Dockerize the whole multi-site setup Change-Id: I0eec9896cddcaccbc37f630d7baad07840ae0ddc
diff --git a/README.md b/README.md index 0bf8486..34f7709 100644 --- a/README.md +++ b/README.md
@@ -14,12 +14,10 @@ **NOTE**: The multi-site plugin will not start if Gerrit is not yet migrated to NoteDb. -Currently, the only mode supported is one primary read/write master -and multiple read-only masters but eventually the plan is to support multiple -read/write masters. The read/write master is handling any traffic while the -read-only masters are serving the Gerrit GUI assets, the HTTP GET REST API and -git fetch requests (git-upload-pack). The read-only masters are kept synchronized -with the read/write master in order to be always ready to become a read/write master. +Supports multiple read/write masters across multiple sites across different +geographic locations. The Gerrit nodes are kept synchronized +between each other using the replication plugin and a global ref-database in +order to detect and prevent split-brains. For more details on the overall multi-site design and roadmap, please refer to the [multi-site plugin DESIGN.md document](DESIGN.md)
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl index fee8aca..223778e 100644 --- a/external_plugin_deps.bzl +++ b/external_plugin_deps.bzl
@@ -3,12 +3,12 @@ def external_plugin_deps(): maven_jar( name = "global-refdb", - artifact = "com.gerritforge:global-refdb:3.1.2", - sha1 = "6ddee3de0f3fe9254453118ae1eca481ec03e957", + artifact = "com.gerritforge:global-refdb:3.3.1", + sha1 = "5df9dddad2fc67c922406f41549186b210cd957e", ) maven_jar( name = "events-broker", - artifact = "com.gerritforge:events-broker:3.2.0-rc4", - sha1 = "53e3f862ac2c2196dba716756ac9586f4b63af47", + artifact = "com.gerritforge:events-broker:3.3.2", + sha1 = "d8bcb77047cc12dd7c623b5b4de70a25499d3d6c", )
diff --git a/setup_local_env/README.md b/setup_local_env/README.md index 5b99996..fca46d8 100644 --- a/setup_local_env/README.md +++ b/setup_local_env/README.md
@@ -4,7 +4,8 @@ The environment is composed by: - 2 gerrit instances deployed by default in /tmp -- 1 kafka node and 1 zookeeper node +- 1 zookeeper node +- 1 Broker node (kafka, kinesis or gcloud-pubsub) - 1 HA-PROXY ## Requirements @@ -14,15 +15,36 @@ - wget - envsubst - haproxy +- aws-cli (only when broker_type is "kinesis") ## Examples -Simplest setup with all default values and cleanup previous deployment +Simplest setup with all default values and cleanup previous deployment. This +will deploy kafka broker ```bash sh setup_local_env/setup.sh --release-war-file /path/to/gerrit.war --multisite-lib-file /path/to/multi-site.jar ``` +Deploy Kinesis broker + +```bash +sh setup_local_env/setup.sh \ + --release-war-file /path/to/gerrit.war \ + --multisite-lib-file /path/to/multi-site.jar \ + --broker-type kinesis +``` + +Deploy GCloud PubSub broker + +```bash +sh setup_local_env/setup.sh \ + --release-war-file /path/to/gerrit.war \ + --multisite-lib-file /path/to/multi-site.jar \ + --broker-type gcloud-pubsub +``` + + Cleanup the previous deployments ```bash @@ -59,6 +81,8 @@ [--just-cleanup-env] Cleans up previous deployment; default false [--enabled-https] Enabled https; default true + +[--broker_type] events broker type; 'kafka', 'kinesis' or 'gcloud-pubsub'. Default 'kafka' ``` ## Limitations
diff --git a/setup_local_env/configs/gerrit.config b/setup_local_env/configs/gerrit.config index 884b5be..c4df06a 100644 --- a/setup_local_env/configs/gerrit.config +++ b/setup_local_env/configs/gerrit.config
@@ -18,6 +18,7 @@ [container] javaOptions = "-Dflogger.backend_factory=com.google.common.flogger.backend.log4j.Log4jBackendFactory#getInstance" javaOptions = "-Dflogger.logging_context=com.google.gerrit.server.logging.LoggingContext#getInstance" + javaOptions = "-DPUBSUB_EMULATOR_HOST=localhost:$BROKER_PORT" javaOptions = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$REMOTE_DEBUG_PORT" [index] type = LUCENE @@ -41,13 +42,25 @@ directory = $FAKE_NFS [plugin "events-kafka"] sendAsync = true - bootstrapServers = localhost:$KAFKA_PORT - groupId = $KAFKA_GROUP_ID + bootstrapServers = localhost:$BROKER_PORT + groupId = $GROUP_ID numberOfSubscribers = 6 securityProtocol = PLAINTEXT pollingIntervalMs = 1000 enableAutoCommit = true autoCommitIntervalMs = 1000 autoOffsetReset = latest +[plugin "events-aws-kinesis"] + numberOfSubscribers = 6 + pollingIntervalMs = 1000 + region = us-east-1 + endpoint = http://localhost:$BROKER_PORT + applicationName = $GROUP_ID + initialPosition = trim_horizon +[plugin "events-gcloud-pubsub"] + numberOfSubscribers = 6 + gcloudProject="test-project" + subscriptionId=$GROUP_ID + privateKeyLocation="not used in local mode" [plugin "metrics-reporter-prometheus"] prometheusBearerToken = token
diff --git a/setup_local_env/docker-compose.yaml b/setup_local_env/docker-compose-core.yaml similarity index 61% rename from setup_local_env/docker-compose.yaml rename to setup_local_env/docker-compose-core.yaml index c386d46..dab168d 100644 --- a/setup_local_env/docker-compose.yaml +++ b/setup_local_env/docker-compose-core.yaml
@@ -5,15 +5,8 @@ ports: - "2181:2181" container_name: zk_test_node - kafka: - image: wurstmeister/kafka:2.12-2.1.0 - ports: - - "9092:9092" - container_name: kafka_test_node - environment: - KAFKA_ADVERTISED_HOST_NAME: 127.0.0.1 - KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 prometheus: + container_name: prometheus_test_node image: prom/prometheus:v2.16.0 user: root volumes:
diff --git a/setup_local_env/docker-compose-gcloud-pubsub.yaml b/setup_local_env/docker-compose-gcloud-pubsub.yaml new file mode 100644 index 0000000..983e784 --- /dev/null +++ b/setup_local_env/docker-compose-gcloud-pubsub.yaml
@@ -0,0 +1,13 @@ +version: '3' +services: + pubsub: + image: gcr.io/google.com/cloudsdktool/cloud-sdk:316.0.0-emulators + ports: + - "8085:8085" + container_name: gcloud-pubsub_test_node + entrypoint: gcloud beta emulators pubsub start --project test-project --host-port 0.0.0.0:8085 + networks: + - setup_local_env_default +networks: + setup_local_env_default: + external: true
diff --git a/setup_local_env/docker-compose-kafka.yaml b/setup_local_env/docker-compose-kafka.yaml new file mode 100644 index 0000000..8a31502 --- /dev/null +++ b/setup_local_env/docker-compose-kafka.yaml
@@ -0,0 +1,15 @@ +version: '3' +services: + kafka: + image: wurstmeister/kafka:2.12-2.1.0 + ports: + - "9092:9092" + container_name: kafka_test_node + environment: + KAFKA_ADVERTISED_HOST_NAME: 127.0.0.1 + KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 + networks: + - setup_local_env_default +networks: + setup_local_env_default: + external: true
diff --git a/setup_local_env/docker-compose-kinesis.yaml b/setup_local_env/docker-compose-kinesis.yaml new file mode 100644 index 0000000..15c609e --- /dev/null +++ b/setup_local_env/docker-compose-kinesis.yaml
@@ -0,0 +1,17 @@ +version: '3' +services: + kinesis: + image: localstack/localstack:0.12.8 + ports: + - "4566:4566" + - "4751:4751" + container_name: kinesis_test_node + environment: + SERVICES: dynamodb,cloudwatch,kinesis + AWS_REGION: us-east-1 + USE_SSL: "true" + networks: + - setup_local_env_default +networks: + setup_local_env_default: + external: true \ No newline at end of file
diff --git a/setup_local_env/haproxy-config/haproxy.cfg b/setup_local_env/haproxy-config/haproxy.cfg index 94b22d8..de4f709 100644 --- a/setup_local_env/haproxy-config/haproxy.cfg +++ b/setup_local_env/haproxy-config/haproxy.cfg
@@ -65,4 +65,5 @@ timeout connect 10s timeout server 5m server ssh_node1 $HA_GERRIT_SITE1_HOSTNAME:$HA_GERRIT_SITE1_SSHD_PORT check inter 10s check port $HA_GERRIT_SITE1_HTTPD_PORT inter 10s - server ssh_node2 $HA_GERRIT_SITE2_HOSTNAME:$HA_GERRIT_SITE2_SSHD_PORT check inter 10s check port $HA_GERRIT_SITE2_HTTPD_PORT inter 10s backup \ No newline at end of file + server ssh_node2 $HA_GERRIT_SITE2_HOSTNAME:$HA_GERRIT_SITE2_SSHD_PORT check inter 10s check port $HA_GERRIT_SITE2_HTTPD_PORT inter 10s backup +
diff --git a/setup_local_env/setup.sh b/setup_local_env/setup.sh index f3f3ae6..4266ce2 100755 --- a/setup_local_env/setup.sh +++ b/setup_local_env/setup.sh
@@ -16,10 +16,11 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -GERRIT_BRANCH=stable-3.2 +GERRIT_BRANCH=stable-3.3 GERRIT_CI=https://gerrit-ci.gerritforge.com/view/Plugins-$GERRIT_BRANCH/job LAST_BUILD=lastSuccessfulBuild/artifact/bazel-bin/plugins EVENTS_BROKER_VER=`grep 'com.gerritforge:events-broker' $(dirname $0)/../external_plugin_deps.bzl | cut -d '"' -f 2 | cut -d ':' -f 3` +GLOBAL_REFDB_VER=`grep 'com.gerritforge:global-refdb' $(dirname $0)/../external_plugin_deps.bzl | cut -d '"' -f 2 | cut -d ':' -f 3` function check_application_requirements { type haproxy >/dev/null 2>&1 || { echo >&2 "Require haproxy but it's not installed. Aborting."; exit 1; } @@ -29,6 +30,9 @@ type wget >/dev/null 2>&1 || { echo >&2 "Require wget but it's not installed. Aborting."; exit 1; } type envsubst >/dev/null 2>&1 || { echo >&2 "Require envsubst but it's not installed. Aborting."; exit 1; } type openssl >/dev/null 2>&1 || { echo >&2 "Require openssl but it's not installed. Aborting."; exit 1; } + if [ "$BROKER_TYPE" = "kinesis" ]; then + type aws >/dev/null 2>&1 || { echo >&2 "Require aws-cli but it's not installed. Aborting."; exit 1; } + fi } function get_replication_url { @@ -66,7 +70,7 @@ export GERRIT_HOSTNAME=$7 export REPLICATION_HOSTNAME=$8 export REMOTE_DEBUG_PORT=$9 - export KAFKA_GROUP_ID=${10} + export GROUP_ID=${10} export REPLICATION_URL=$(get_replication_url $REPLICATION_LOCATION_TEST_SITE $REPLICATION_HOSTNAME) echo "Replacing variables for file $file and copying to $CONFIG_TEST_SITE/$file_name" @@ -98,10 +102,17 @@ haproxy -f $HA_PROXY_CONFIG_DIR/haproxy.cfg & } -function deploy_config_files { - # KAFKA configuration - export KAFKA_PORT=9092 +function export_broker_port { + if [ "$BROKER_TYPE" = "kinesis" ]; then + export BROKER_PORT=4566 + elif [ "$BROKER_TYPE" = "kafka" ]; then + export BROKER_PORT=9092 + elif [ "$BROKER_TYPE" = "gcloud-pubsub" ]; then + export BROKER_PORT=8085 + fi +} +function deploy_config_files { # ZK configuration export ZK_PORT=2181 @@ -111,21 +122,21 @@ GERRIT_SITE1_SSHD_PORT=$3 CONFIG_TEST_SITE_1=$LOCATION_TEST_SITE_1/etc GERRIT_SITE1_REMOTE_DEBUG_PORT="5005" - GERRIT_SITE1_KAFKA_GROUP_ID="instance-1" + GERRIT_SITE1_GROUP_ID="instance-1" # SITE 2 GERRIT_SITE2_HOSTNAME=$4 GERRIT_SITE2_HTTPD_PORT=$5 GERRIT_SITE2_SSHD_PORT=$6 CONFIG_TEST_SITE_2=$LOCATION_TEST_SITE_2/etc GERRIT_SITE2_REMOTE_DEBUG_PORT="5006" - GERRIT_SITE2_KAFKA_GROUP_ID="instance-2" + GERRIT_SITE2_GROUP_ID="instance-2" # Set config SITE1 - copy_config_files $CONFIG_TEST_SITE_1 $GERRIT_SITE1_HTTPD_PORT $LOCATION_TEST_SITE_1 $GERRIT_SITE1_SSHD_PORT $GERRIT_SITE2_HTTPD_PORT $LOCATION_TEST_SITE_2 $GERRIT_SITE1_HOSTNAME $GERRIT_SITE2_HOSTNAME $GERRIT_SITE1_REMOTE_DEBUG_PORT $GERRIT_SITE1_KAFKA_GROUP_ID + copy_config_files $CONFIG_TEST_SITE_1 $GERRIT_SITE1_HTTPD_PORT $LOCATION_TEST_SITE_1 $GERRIT_SITE1_SSHD_PORT $GERRIT_SITE2_HTTPD_PORT $LOCATION_TEST_SITE_2 $GERRIT_SITE1_HOSTNAME $GERRIT_SITE2_HOSTNAME $GERRIT_SITE1_REMOTE_DEBUG_PORT $GERRIT_SITE1_GROUP_ID # Set config SITE2 - copy_config_files $CONFIG_TEST_SITE_2 $GERRIT_SITE2_HTTPD_PORT $LOCATION_TEST_SITE_2 $GERRIT_SITE2_SSHD_PORT $GERRIT_SITE1_HTTPD_PORT $LOCATION_TEST_SITE_1 $GERRIT_SITE1_HOSTNAME $GERRIT_SITE2_HOSTNAME $GERRIT_SITE2_REMOTE_DEBUG_PORT $GERRIT_SITE2_KAFKA_GROUP_ID + copy_config_files $CONFIG_TEST_SITE_2 $GERRIT_SITE2_HTTPD_PORT $LOCATION_TEST_SITE_2 $GERRIT_SITE2_SSHD_PORT $GERRIT_SITE1_HTTPD_PORT $LOCATION_TEST_SITE_1 $GERRIT_SITE1_HOSTNAME $GERRIT_SITE2_HOSTNAME $GERRIT_SITE2_REMOTE_DEBUG_PORT $GERRIT_SITE2_GROUP_ID } function is_docker_desktop { @@ -141,13 +152,33 @@ fi } +function create_kinesis_streams { + for stream in "gerrit_batch_index" "gerrit_cache_eviction" "gerrit_index" "gerrit_list_project" "gerrit_stream" "gerrit_web_session" "gerrit" + do + create_kinesis_stream $stream + done +} + +function create_kinesis_stream { + local stream=$1 + + export AWS_PAGER='' + echo "[KINESIS] Create stream $stream" + until aws --endpoint-url=http://localhost:$BROKER_PORT kinesis create-stream --shard-count 1 --stream-name "$stream" + do + echo "[KINESIS stream $stream] Creation failed. Retrying in 5 seconds..." + sleep 5s + done +} function cleanup_environment { echo "Killing existing HA-PROXY setup" kill $(ps -ax | grep haproxy | grep "gerrit_setup/ha-proxy-config" | awk '{print $1}') 2> /dev/null - echo "Stopping docker containers" - docker-compose -f $SCRIPT_DIR/docker-compose.yaml down 2> /dev/null + echo "Stopping $BROKER_TYPE docker container" + docker-compose -f "${SCRIPT_DIR}/docker-compose-${BROKER_TYPE}.yaml" down 2> /dev/null + echo "Stopping core docker containers" + docker-compose -f "${SCRIPT_DIR}/docker-compose-core.yaml" down 2> /dev/null echo "Stopping GERRIT instances" $1/bin/gerrit.sh stop 2> /dev/null @@ -157,8 +188,32 @@ rm -rf $3 2> /dev/null } -function check_if_kafka_is_running { - echo $(docker inspect kafka_test_node 2> /dev/null | grep '"Running": true' | wc -l) +function check_if_container_is_running { + local container=$1; + echo $(docker inspect "$container" 2> /dev/null | grep '"Running": true' | wc -l) +} + +function ensure_docker_compose_is_up_and_running { + local log_label=$1 + local container_name=$2 + local docker_compose_file=$3 + + local is_container_running=$(check_if_container_is_running "$container_name") + if [ "$is_container_running" -lt 1 ];then + echo "[$log_label] Starting docker containers" + docker-compose -f "${SCRIPT_DIR}/${docker_compose_file}" up -d + + echo "[$log_label] Waiting for docker containers to start..." + while [[ $(check_if_container_is_running "$container_name") -lt 1 ]];do sleep 10s; done + else + echo "[$log_label] Containers already running, nothing to do" + fi +} + +function prepare_broker_data { + if [ "$BROKER_TYPE" = "kinesis" ]; then + create_kinesis_streams + fi } while [ $# -ne 0 ] @@ -193,6 +248,8 @@ echo echo "[--enabled-https] Enabled https; default true" echo + echo "[--broker-type] events broker type; 'kafka', 'kinesis' or 'gcloud-pubsub'. Default 'kafka'" + echo exit 0 ;; "--new-deployment") @@ -280,6 +337,15 @@ shift shift ;; + "--broker-type" ) + BROKER_TYPE=$2 + shift + shift + if [ ! "$BROKER_TYPE" = "kafka" ] && [ ! "$BROKER_TYPE" = "kinesis" ] && [ ! "$BROKER_TYPE" = "gcloud-pubsub" ]; then + echo >&2 "broker type: '$BROKER_TYPE' not valid. Please supply 'kafka','kinesis' or 'gcloud-pubsub'. Aborting" + exit 1 + fi + ;; * ) echo "Unknown option argument: $1" shift @@ -308,6 +374,7 @@ export REPLICATION_DELAY_SEC=${REPLICATION_DELAY_SEC:-"5"} export SSH_ADVERTISED_PORT=${SSH_ADVERTISED_PORT:-"29418"} HTTPS_ENABLED=${HTTPS_ENABLED:-"false"} +BROKER_TYPE=${BROKER_TYPE:-"kafka"} export COMMON_LOCATION=$DEPLOYMENT_LOCATION/gerrit_setup LOCATION_TEST_SITE_1=$COMMON_LOCATION/instance-1 @@ -356,15 +423,37 @@ -O $DEPLOYMENT_LOCATION/zookeeper-refdb.jar || { echo >&2 "Cannot download zookeeper plugin: Check internet connection. Abort\ ing"; exit 1; } +echo "Downloading global-refdb library $GERRIT_BRANCH" + wget https://repo1.maven.org/maven2/com/gerritforge/global-refdb/$GLOBAL_REFDB_VER/global-refdb-$GLOBAL_REFDB_VER.jar \ + -O $DEPLOYMENT_LOCATION/global-refdb.jar || { echo >&2 "Cannot download global-refdb library: Check internet connection. Abort\ +ing"; exit 1; } + echo "Downloading events-broker library $GERRIT_BRANCH" wget https://repo1.maven.org/maven2/com/gerritforge/events-broker/$EVENTS_BROKER_VER/events-broker-$EVENTS_BROKER_VER.jar \ -O $DEPLOYMENT_LOCATION/events-broker.jar || { echo >&2 "Cannot download events-broker library: Check internet connection. Abort\ ing"; exit 1; } +if [ "$BROKER_TYPE" = "kafka" ]; then echo "Downloading events-kafka plugin $GERRIT_BRANCH" wget $GERRIT_CI/plugin-events-kafka-bazel-$GERRIT_BRANCH/$LAST_BUILD/events-kafka/events-kafka.jar \ -O $DEPLOYMENT_LOCATION/events-kafka.jar || { echo >&2 "Cannot download events-kafka plugin: Check internet connection. Abort\ ing"; exit 1; } +fi + +if [ "$BROKER_TYPE" = "kinesis" ]; then +echo "Downloading events-aws-kinesis plugin $GERRIT_BRANCH" + wget $GERRIT_CI/plugin-events-aws-kinesis-bazel-$GERRIT_BRANCH/$LAST_BUILD/events-aws-kinesis/events-aws-kinesis.jar \ + -O $DEPLOYMENT_LOCATION/events-aws-kinesis.jar || { echo >&2 "Cannot download events-aws-kinesis plugin: Check internet connection. Abort\ +ing"; exit 1; } +fi + + +if [ "$BROKER_TYPE" = "gcloud-pubsub" ]; then +echo "Downloading events-gcloud-pubsub plugin $GERRIT_BRANCH" + wget $GERRIT_CI/plugin-events-gcloud-pubsub-bazel-$GERRIT_BRANCH/$LAST_BUILD/events-gcloud-pubsub/events-gcloud-pubsub.jar \ + -O $DEPLOYMENT_LOCATION/events-gcloud-pubsub.jar || { echo >&2 "Cannot download events-gcloud-pubsub plugin: Check internet connection. Abort\ +ing"; exit 1; } +fi echo "Downloading metrics-reporter-prometheus plugin $GERRIT_BRANCH" wget $GERRIT_CI/plugin-metrics-reporter-prometheus-bazel-master-$GERRIT_BRANCH/$LAST_BUILD/metrics-reporter-prometheus/metrics-reporter-prometheus.jar \ @@ -410,11 +499,20 @@ echo "Copy zookeeper plugin" cp -f $DEPLOYMENT_LOCATION/zookeeper-refdb.jar $LOCATION_TEST_SITE_1/plugins/zookeeper-refdb.jar + echo "Copy global refdb library" + cp -f $DEPLOYMENT_LOCATION/global-refdb.jar $LOCATION_TEST_SITE_1/lib/global-refdb.jar + echo "Copy events broker library" cp -f $DEPLOYMENT_LOCATION/events-broker.jar $LOCATION_TEST_SITE_1/lib/events-broker.jar - echo "Copy events kafka plugin" - cp -f $DEPLOYMENT_LOCATION/events-kafka.jar $LOCATION_TEST_SITE_1/plugins/events-kafka.jar + echo "Copy $BROKER_TYPE events plugin" + if [ $BROKER_TYPE = "kinesis" ]; then + cp -f $DEPLOYMENT_LOCATION/events-aws-kinesis.jar $LOCATION_TEST_SITE_1/plugins/events-aws-kinesis.jar + elif [ $BROKER_TYPE = "gcloud-pubsub" ]; then + cp -f $DEPLOYMENT_LOCATION/events-gcloud-pubsub.jar $LOCATION_TEST_SITE_1/plugins/events-gcloud-pubsub.jar + else + cp -f $DEPLOYMENT_LOCATION/events-kafka.jar $LOCATION_TEST_SITE_1/plugins/events-kafka.jar + fi echo "Copy metrics-reporter-prometheus plugin" cp -f $DEPLOYMENT_LOCATION/metrics-reporter-prometheus.jar $LOCATION_TEST_SITE_1/plugins/metrics-reporter-prometheus.jar @@ -446,14 +544,10 @@ cat $SCRIPT_DIR/configs/prometheus.yml | envsubst > $COMMON_LOCATION/prometheus.yml -IS_KAFKA_RUNNING=$(check_if_kafka_is_running) -if [ $IS_KAFKA_RUNNING -lt 1 ];then - - echo "Starting zk and kafka" - docker-compose -f $SCRIPT_DIR/docker-compose.yaml up -d - echo "Waiting for kafka to start..." - while [[ $(check_if_kafka_is_running) -lt 1 ]];do sleep 10s; done -fi +export_broker_port +ensure_docker_compose_is_up_and_running "core" "prometheus_test_node" "docker-compose-core.yaml" +ensure_docker_compose_is_up_and_running "$BROKER_TYPE" "${BROKER_TYPE}_test_node" "docker-compose-$BROKER_TYPE.yaml" +prepare_broker_data echo "Re-deploying configuration files" deploy_config_files $GERRIT_1_HOSTNAME $GERRIT_1_HTTPD_PORT $GERRIT_1_SSHD_PORT $GERRIT_2_HOSTNAME $GERRIT_2_HTTPD_PORT $GERRIT_2_SSHD_PORT
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 f509cd4..81e1c12 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/Configuration.java +++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/Configuration.java
@@ -17,17 +17,16 @@ import static com.google.common.base.Suppliers.memoize; import static com.google.common.base.Suppliers.ofInstance; +import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbConfiguration; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.MoreObjects; +import com.google.common.base.Strings; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; -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.validation.dfsrefdb.SharedRefEnforcement.EnforcePolicy; import java.io.IOException; import java.util.Arrays; import java.util.Collection; @@ -62,7 +61,7 @@ private final Supplier<Event> event; private final Supplier<Index> index; private final Supplier<Projects> projects; - private final Supplier<SharedRefDatabase> sharedRefDb; + private final Supplier<SharedRefDbConfiguration> sharedRefDb; private final Supplier<Collection<Message>> replicationConfigValidation; private final Supplier<Broker> broker; private final Config multiSiteConfig; @@ -81,7 +80,11 @@ event = memoize(() -> new Event(lazyMultiSiteCfg)); index = memoize(() -> new Index(lazyMultiSiteCfg)); projects = memoize(() -> new Projects(lazyMultiSiteCfg)); - sharedRefDb = memoize(() -> new SharedRefDatabase(lazyMultiSiteCfg)); + sharedRefDb = + memoize( + () -> + new SharedRefDbConfiguration( + enableSharedRefDbByDefault(lazyMultiSiteCfg.get()), PLUGIN_NAME)); broker = memoize(() -> new Broker(lazyMultiSiteCfg)); } @@ -89,7 +92,7 @@ return multiSiteConfig; } - public SharedRefDatabase getSharedRefDb() { + public SharedRefDbConfiguration getSharedRefDbConfiguration() { return sharedRefDb.get(); } @@ -121,6 +124,21 @@ return new FileBasedConfig(sitePaths.etc_dir.resolve(configFileName).toFile(), FS.DETECTED); } + private Config enableSharedRefDbByDefault(Config cfg) { + if (Strings.isNullOrEmpty( + cfg.getString( + SharedRefDbConfiguration.SharedRefDatabase.SECTION, + null, + SharedRefDbConfiguration.SharedRefDatabase.ENABLE_KEY))) { + cfg.setBoolean( + SharedRefDbConfiguration.SharedRefDatabase.SECTION, + null, + SharedRefDbConfiguration.SharedRefDatabase.ENABLE_KEY, + true); + } + return cfg; + } + private Supplier<Config> lazyLoad(Config config) { if (config instanceof FileBasedConfig) { return memoize( @@ -172,38 +190,6 @@ } } - public static class SharedRefDatabase { - public static final String SECTION = "ref-database"; - public static final String ENABLE_KEY = "enabled"; - public static final String SUBSECTION_ENFORCEMENT_RULES = "enforcementRules"; - - private final boolean enabled; - private final Multimap<EnforcePolicy, String> enforcementRules; - - private SharedRefDatabase(Supplier<Config> cfg) { - enabled = getBoolean(cfg, SECTION, null, ENABLE_KEY, true); - - enforcementRules = MultimapBuilder.hashKeys().arrayListValues().build(); - for (EnforcePolicy policy : EnforcePolicy.values()) { - enforcementRules.putAll( - policy, getList(cfg, SECTION, SUBSECTION_ENFORCEMENT_RULES, policy.name())); - } - } - - public boolean isEnabled() { - return enabled; - } - - public Multimap<EnforcePolicy, String> getEnforcementRules() { - return enforcementRules; - } - - private List<String> getList( - Supplier<Config> cfg, String section, String subsection, String name) { - return ImmutableList.copyOf(cfg.get().getStringList(section, subsection, name)); - } - } - public static class Projects { public static final String SECTION = "projects"; public static final String PATTERN_KEY = "pattern";
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/GitModule.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/GitModule.java index 4f7205d..87e9d22 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/GitModule.java +++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/GitModule.java
@@ -28,7 +28,7 @@ @Override protected void configure() { - if (config.getSharedRefDb().isEnabled()) { + if (config.getSharedRefDbConfiguration().getSharedRefDb().isEnabled()) { install(new ValidationModule(config)); } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/LockWrapper.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/LockWrapper.java deleted file mode 100644 index 0e018d3..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/LockWrapper.java +++ /dev/null
@@ -1,50 +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; - -import com.google.inject.Inject; -import com.google.inject.assistedinject.Assisted; - -public class LockWrapper implements AutoCloseable { - public interface Factory { - LockWrapper create( - @Assisted("project") String project, - @Assisted("refName") String refName, - @Assisted("lock") AutoCloseable lock); - } - - private final String project; - private final String refName; - private final AutoCloseable lock; - private final SharedRefLogger sharedRefLogger; - - @Inject - public LockWrapper( - SharedRefLogger sharedRefLogger, - @Assisted("project") String project, - @Assisted("refName") String refName, - @Assisted("lock") AutoCloseable lock) { - this.lock = lock; - this.sharedRefLogger = sharedRefLogger; - this.project = project; - this.refName = refName; - } - - @Override - public void close() throws Exception { - lock.close(); - sharedRefLogger.logLockRelease(project, refName); - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/Log4jSharedRefLogger.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/Log4jSharedRefLogger.java deleted file mode 100644 index 003ce5b..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/Log4jSharedRefLogger.java +++ /dev/null
@@ -1,141 +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; - -import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; -import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.flogger.FluentLogger; -import com.google.gerrit.entities.Project; -import com.google.gerrit.extensions.common.GitPerson; -import com.google.gerrit.json.OutputFormat; -import com.google.gerrit.server.CommonConverters; -import com.google.gerrit.server.git.GitRepositoryManager; -import com.google.gerrit.server.util.SystemLog; -import com.google.gson.Gson; -import com.google.inject.Inject; -import com.google.inject.Singleton; -import java.io.IOException; -import org.apache.log4j.PatternLayout; -import org.eclipse.jgit.errors.IncorrectObjectTypeException; -import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.revwalk.RevWalk; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Singleton -public class Log4jSharedRefLogger extends LibModuleLogFile implements SharedRefLogger { - private static final String LOG_NAME = "sharedref_log"; - private Logger sharedRefDBLog; - private final GitRepositoryManager gitRepositoryManager; - private static final Gson gson = OutputFormat.JSON_COMPACT.newGson(); - - private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - - @Inject - public Log4jSharedRefLogger(SystemLog systemLog, GitRepositoryManager gitRepositoryManager) { - super(systemLog, LOG_NAME, new PatternLayout("[%d{ISO8601}] [%t] %-5p : %m%n")); - this.gitRepositoryManager = gitRepositoryManager; - sharedRefDBLog = LoggerFactory.getLogger(LOG_NAME); - } - - @Override - public void logRefUpdate(String project, Ref currRef, ObjectId newRefValue) { - if (!ObjectId.zeroId().equals(newRefValue)) { - try (Repository repository = gitRepositoryManager.openRepository(Project.nameKey(project)); - RevWalk walk = new RevWalk(repository)) { - GitPerson committer = null; - String commitMessage = null; - if (newRefValue != null) { - int objectType = walk.parseAny(newRefValue).getType(); - switch (objectType) { - case OBJ_COMMIT: - RevCommit commit = walk.parseCommit(newRefValue); - committer = CommonConverters.toGitPerson(commit.getCommitterIdent()); - commitMessage = commit.getShortMessage(); - break; - case OBJ_BLOB: - break; - default: - throw new IncorrectObjectTypeException(newRefValue, Constants.typeString(objectType)); - } - } - sharedRefDBLog.info( - gson.toJson( - new SharedRefLogEntry.UpdateRef( - project, - currRef.getName(), - currRef.getObjectId().getName(), - newRefValue == null ? ObjectId.zeroId().name() : newRefValue.getName(), - committer, - commitMessage))); - } catch (IOException e) { - logger.atSevere().withCause(e).log( - "Cannot log sharedRefDB interaction for ref %s on project %s", - currRef.getName(), project); - } - } else { - sharedRefDBLog.info( - gson.toJson( - new SharedRefLogEntry.DeleteRef( - project, currRef.getName(), currRef.getObjectId().getName()))); - } - } - - @Override - public <T> void logRefUpdate(String project, String refName, T currRef, T newRefValue) { - if (newRefValue != null) { - sharedRefDBLog.info( - gson.toJson( - new SharedRefLogEntry.UpdateRef( - project, refName, safeToString(currRef), safeToString(newRefValue), null, null))); - } else { - sharedRefDBLog.info( - gson.toJson(new SharedRefLogEntry.DeleteRef(project, refName, safeToString(currRef)))); - } - } - - @Override - public void logProjectDelete(String project) { - sharedRefDBLog.info(gson.toJson(new SharedRefLogEntry.DeleteProject(project))); - } - - @Override - public void logLockAcquisition(String project, String refName) { - sharedRefDBLog.info(gson.toJson(new SharedRefLogEntry.LockAcquire(project, refName))); - } - - @Override - public void logLockRelease(String project, String refName) { - sharedRefDBLog.info(gson.toJson(new SharedRefLogEntry.LockRelease(project, refName))); - } - - @VisibleForTesting - public void setLogger(Logger logger) { - this.sharedRefDBLog = logger; - } - - private <T> String safeToString(T currRef) { - if (currRef == null) { - return "<null>"; - } - return currRef.toString(); - } -}
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 708e707..f44f4f7 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/Module.java +++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/Module.java
@@ -14,14 +14,12 @@ package com.googlesource.gerrit.plugins.multisite; -import com.gerritforge.gerrit.globalrefdb.GlobalRefDatabase; -import com.google.gerrit.extensions.registration.DynamicItem; +import com.gerritforge.gerrit.globalrefdb.validation.LibModule; import com.google.gerrit.lifecycle.LifecycleModule; import com.google.gerrit.server.config.SitePaths; import com.google.inject.CreationException; import com.google.inject.Inject; import com.google.inject.Provides; -import com.google.inject.Scopes; import com.google.inject.Singleton; import com.google.inject.spi.Message; import com.googlesource.gerrit.plugins.multisite.cache.CacheModule; @@ -29,7 +27,6 @@ import com.googlesource.gerrit.plugins.multisite.forwarder.ForwarderModule; import com.googlesource.gerrit.plugins.multisite.forwarder.router.RouterModule; import com.googlesource.gerrit.plugins.multisite.index.IndexModule; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.NoopSharedRefDatabase; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; @@ -58,11 +55,7 @@ throw new CreationException(validationErrors); } - DynamicItem.itemOf(binder(), GlobalRefDatabase.class); - DynamicItem.bind(binder(), GlobalRefDatabase.class) - .to(NoopSharedRefDatabase.class) - .in(Scopes.SINGLETON); - log.info("Shared ref-db engine: none"); + install(new LibModule()); listener().to(Log4jMessageLogger.class); bind(MessageLogger.class).to(Log4jMessageLogger.class);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/PluginModule.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/PluginModule.java index 2eaa5d9..81a0d8d 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/PluginModule.java +++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/PluginModule.java
@@ -14,6 +14,7 @@ package com.googlesource.gerrit.plugins.multisite; +import com.gerritforge.gerrit.globalrefdb.validation.ProjectDeletedSharedDbCleanup; import com.google.gerrit.extensions.events.ProjectDeletedListener; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.lifecycle.LifecycleModule; @@ -23,7 +24,6 @@ import com.googlesource.gerrit.plugins.multisite.consumer.MultiSiteConsumerRunner; import com.googlesource.gerrit.plugins.multisite.consumer.SubscriberModule; import com.googlesource.gerrit.plugins.multisite.forwarder.broker.BrokerForwarderModule; -import com.googlesource.gerrit.plugins.multisite.validation.ProjectDeletedSharedDbCleanup; public class PluginModule extends LifecycleModule { private Configuration config; @@ -41,7 +41,7 @@ install(new BrokerForwarderModule()); listener().to(MultiSiteConsumerRunner.class); - if (config.getSharedRefDb().isEnabled()) { + if (config.getSharedRefDbConfiguration().getSharedRefDb().isEnabled()) { listener().to(PluginStartup.class); DynamicSet.bind(binder(), ProjectDeletedListener.class) .to(ProjectDeletedSharedDbCleanup.class);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/PluginStartup.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/PluginStartup.java index 33b54d2..db7064c 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/PluginStartup.java +++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/PluginStartup.java
@@ -14,6 +14,7 @@ package com.googlesource.gerrit.plugins.multisite; +import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDatabaseWrapper; import com.google.gerrit.extensions.events.LifecycleListener; import com.google.inject.Inject; import com.google.inject.Injector;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/ProjectsFilter.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/ProjectsFilter.java deleted file mode 100644 index d6fac47..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/ProjectsFilter.java +++ /dev/null
@@ -1,109 +0,0 @@ -// Copyright (C) 2020 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package com.googlesource.gerrit.plugins.multisite; - -import com.google.common.base.Strings; -import com.google.common.collect.Sets; -import com.google.gerrit.common.data.AccessSection; -import com.google.gerrit.entities.Project; -import com.google.gerrit.entities.Project.NameKey; -import com.google.gerrit.server.events.Event; -import com.google.gerrit.server.events.ProjectEvent; -import com.google.inject.Inject; -import com.google.inject.Singleton; -import java.util.List; -import java.util.Set; - -@Singleton -public class ProjectsFilter { - public enum PatternType { - REGEX, - WILDCARD, - EXACT_MATCH; - - public static PatternType getPatternType(String pattern) { - if (pattern.startsWith(AccessSection.REGEX_PREFIX)) { - return REGEX; - } else if (pattern.endsWith("*")) { - return WILDCARD; - } else { - return EXACT_MATCH; - } - } - } - - private Set<NameKey> globalProjects = Sets.newConcurrentHashSet(); - private Set<NameKey> localProjects = Sets.newConcurrentHashSet(); - private final List<String> projectPatterns; - - @Inject - public ProjectsFilter(Configuration cfg) { - projectPatterns = cfg.projects().getPatterns(); - } - - public boolean matches(Event event) { - if (event == null) { - throw new IllegalArgumentException("Event object cannot be null"); - } - if (event instanceof ProjectEvent) { - return matches(((ProjectEvent) event).getProjectNameKey()); - } - return false; - } - - public boolean matches(String projectName) { - return matches(NameKey.parse(projectName)); - } - - public boolean matches(Project.NameKey name) { - if (name == null || Strings.isNullOrEmpty(name.get())) { - throw new IllegalArgumentException( - String.format("Project name cannot be null or empty, but was %s", name)); - } - if (projectPatterns.isEmpty() || globalProjects.contains(name)) { - return true; - } - - if (localProjects.contains(name)) { - return false; - } - - String projectName = name.get(); - - for (String pattern : projectPatterns) { - if (matchesPattern(projectName, pattern)) { - globalProjects.add(name); - return true; - } - } - localProjects.add(name); - return false; - } - - private boolean matchesPattern(String projectName, String pattern) { - boolean match = false; - switch (PatternType.getPatternType(pattern)) { - case REGEX: - match = projectName.matches(pattern); - break; - case WILDCARD: - match = projectName.startsWith(pattern.substring(0, pattern.length() - 1)); - break; - case EXACT_MATCH: - match = projectName.equals(pattern); - } - return match; - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/SharedRefDatabaseWrapper.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/SharedRefDatabaseWrapper.java deleted file mode 100644 index ddf9d84..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/SharedRefDatabaseWrapper.java +++ /dev/null
@@ -1,102 +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; - -import com.gerritforge.gerrit.globalrefdb.GlobalRefDatabase; -import com.gerritforge.gerrit.globalrefdb.GlobalRefDbLockException; -import com.gerritforge.gerrit.globalrefdb.GlobalRefDbSystemError; -import com.google.common.annotations.VisibleForTesting; -import com.google.gerrit.entities.Project; -import com.google.gerrit.extensions.registration.DynamicItem; -import com.google.inject.Inject; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.NoopSharedRefDatabase; -import java.util.Optional; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.Ref; - -public class SharedRefDatabaseWrapper implements GlobalRefDatabase { - private static final GlobalRefDatabase NOOP_REFDB = new NoopSharedRefDatabase(); - - @Inject(optional = true) - private DynamicItem<GlobalRefDatabase> sharedRefDbDynamicItem; - - private final SharedRefLogger sharedRefLogger; - - @Inject - public SharedRefDatabaseWrapper(SharedRefLogger sharedRefLogger) { - this.sharedRefLogger = sharedRefLogger; - } - - @VisibleForTesting - public SharedRefDatabaseWrapper( - DynamicItem<GlobalRefDatabase> sharedRefDbDynamicItem, SharedRefLogger sharedRefLogger) { - this.sharedRefLogger = sharedRefLogger; - this.sharedRefDbDynamicItem = sharedRefDbDynamicItem; - } - - @Override - public boolean isUpToDate(Project.NameKey project, Ref ref) throws GlobalRefDbLockException { - return sharedRefDb().isUpToDate(project, ref); - } - - @Override - public boolean compareAndPut(Project.NameKey project, Ref currRef, ObjectId newRefValue) - throws GlobalRefDbSystemError { - boolean succeeded = sharedRefDb().compareAndPut(project, currRef, newRefValue); - if (succeeded) { - sharedRefLogger.logRefUpdate(project.get(), currRef, newRefValue); - } - return succeeded; - } - - @Override - public <T> boolean compareAndPut(Project.NameKey project, String refName, T currValue, T newValue) - throws GlobalRefDbSystemError { - boolean succeeded = sharedRefDb().compareAndPut(project, refName, currValue, newValue); - if (succeeded) { - sharedRefLogger.logRefUpdate(project.get(), refName, currValue, newValue); - } - return succeeded; - } - - @Override - public AutoCloseable lockRef(Project.NameKey project, String refName) - throws GlobalRefDbLockException { - AutoCloseable locker = sharedRefDb().lockRef(project, refName); - sharedRefLogger.logLockAcquisition(project.get(), refName); - return locker; - } - - @Override - public boolean exists(Project.NameKey project, String refName) { - return sharedRefDb().exists(project, refName); - } - - @Override - public void remove(Project.NameKey project) throws GlobalRefDbSystemError { - sharedRefDb().remove(project); - sharedRefLogger.logProjectDelete(project.get()); - } - - @Override - public <T> Optional<T> get(Project.NameKey nameKey, String s, Class<T> clazz) - throws GlobalRefDbSystemError { - return sharedRefDb().get(nameKey, s, clazz); - } - - private GlobalRefDatabase sharedRefDb() { - return Optional.ofNullable(sharedRefDbDynamicItem).map(di -> di.get()).orElse(NOOP_REFDB); - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/SharedRefLogEntry.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/SharedRefLogEntry.java deleted file mode 100644 index d9e762f..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/SharedRefLogEntry.java +++ /dev/null
@@ -1,100 +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; - -import com.google.gerrit.common.Nullable; -import com.google.gerrit.extensions.common.GitPerson; - -public class SharedRefLogEntry { - - public enum Type { - UPDATE_REF, - DELETE_REF, - DELETE_PROJECT, - LOCK_ACQUIRE, - LOCK_RELEASE - } - - public String projectName; - public Type type; - - public static class UpdateRef extends SharedRefLogEntry { - - public String refName; - public String oldId; - public String newId; - public GitPerson committer; - public String comment; - - UpdateRef( - String projectName, - String refName, - String oldId, - String newId, - @Nullable GitPerson committer, - @Nullable String comment) { - this.type = Type.UPDATE_REF; - this.projectName = projectName; - this.refName = refName; - this.oldId = oldId; - this.newId = newId; - this.committer = committer; - this.comment = comment; - } - } - - public static class DeleteProject extends SharedRefLogEntry { - - DeleteProject(String projectName) { - this.type = Type.DELETE_PROJECT; - this.projectName = projectName; - } - } - - public static class DeleteRef extends SharedRefLogEntry { - - public String refName; - public String oldId; - - DeleteRef(String projectName, String refName, String oldId) { - this.type = Type.DELETE_REF; - this.projectName = projectName; - this.refName = refName; - this.oldId = oldId; - } - } - - public static class LockAcquire extends SharedRefLogEntry { - - public String refName; - - LockAcquire(String projectName, String refName) { - this.type = Type.LOCK_ACQUIRE; - this.projectName = projectName; - this.refName = refName; - } - } - - public static class LockRelease extends SharedRefLogEntry { - - public String refName; - - LockRelease(String projectName, String refName) { - this.type = Type.LOCK_RELEASE; - this.projectName = projectName; - this.refName = refName; - } - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/SharedRefLogger.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/SharedRefLogger.java deleted file mode 100644 index 3853af6..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/SharedRefLogger.java +++ /dev/null
@@ -1,31 +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; - -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.Ref; - -public interface SharedRefLogger { - - void logRefUpdate(String project, Ref currRef, ObjectId newRefValue); - - <T> void logRefUpdate(String project, String refName, T currRef, T newRefValue); - - void logProjectDelete(String project); - - void logLockAcquisition(String project, String refName); - - void logLockRelease(String project, String refName); -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/cache/ProjectListUpdateHandler.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/cache/ProjectListUpdateHandler.java index 2e2f9de..fdc6fc3 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/cache/ProjectListUpdateHandler.java +++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/cache/ProjectListUpdateHandler.java
@@ -14,13 +14,13 @@ package com.googlesource.gerrit.plugins.multisite.cache; +import com.gerritforge.gerrit.globalrefdb.validation.ProjectsFilter; import com.google.gerrit.extensions.events.NewProjectCreatedListener; import com.google.gerrit.extensions.events.ProjectDeletedListener; import com.google.gerrit.extensions.events.ProjectEvent; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.inject.Inject; import com.google.inject.Singleton; -import com.googlesource.gerrit.plugins.multisite.ProjectsFilter; import com.googlesource.gerrit.plugins.multisite.forwarder.Context; import com.googlesource.gerrit.plugins.multisite.forwarder.ForwarderTask; import com.googlesource.gerrit.plugins.multisite.forwarder.ProjectListUpdateForwarder;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/consumer/AbstractSubcriber.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/consumer/AbstractSubcriber.java index 1f8766a..b37f434 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/consumer/AbstractSubcriber.java +++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/consumer/AbstractSubcriber.java
@@ -15,6 +15,7 @@ package com.googlesource.gerrit.plugins.multisite.consumer; import com.gerritforge.gerrit.eventbroker.EventMessage; +import com.google.common.base.Strings; import com.google.common.flogger.FluentLogger; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.server.permissions.PermissionBackendException; @@ -34,7 +35,7 @@ private final ForwardedEventRouter eventRouter; private final DynamicSet<DroppedEventListener> droppedEventListeners; - private final UUID instanceId; + private final String instanceId; private final MessageLogger msgLog; private SubscriberMetrics subscriberMetrics; private final Configuration cfg; @@ -49,7 +50,7 @@ Configuration cfg) { this.eventRouter = eventRouter; this.droppedEventListeners = droppedEventListeners; - this.instanceId = instanceId; + this.instanceId = instanceId.toString(); this.msgLog = msgLog; this.subscriberMetrics = subscriberMetrics; this.cfg = cfg; @@ -63,11 +64,18 @@ } private void processRecord(EventMessage event) { + String sourceInstanceId = event.getHeader().sourceInstanceId; - if (event.getHeader().sourceInstanceId.equals(instanceId)) { - logger.atFiner().log( - "Dropping event %s produced by our instanceId %s", - event.toString(), instanceId.toString()); + if (Strings.isNullOrEmpty(sourceInstanceId) || instanceId.equals(sourceInstanceId)) { + if (Strings.isNullOrEmpty(sourceInstanceId)) { + logger.atWarning().log( + String.format( + "Dropping event %s because sourceInstanceId cannot be null", event.toString())); + } else { + logger.atFiner().log( + String.format( + "Dropping event %s produced by our instanceId %s", event.toString(), instanceId)); + } droppedEventListeners.forEach(l -> l.onEventDropped(event)); } else { try {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/event/EventHandler.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/event/EventHandler.java index a1b7a53..b2efb80 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/event/EventHandler.java +++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/event/EventHandler.java
@@ -14,12 +14,12 @@ package com.googlesource.gerrit.plugins.multisite.event; +import com.gerritforge.gerrit.globalrefdb.validation.ProjectsFilter; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.server.events.Event; import com.google.gerrit.server.events.EventListener; import com.google.gerrit.server.events.ProjectEvent; import com.google.inject.Inject; -import com.googlesource.gerrit.plugins.multisite.ProjectsFilter; import com.googlesource.gerrit.plugins.multisite.forwarder.Context; import com.googlesource.gerrit.plugins.multisite.forwarder.StreamEventForwarder; import java.util.concurrent.Executor;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/GsonParser.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/CacheKeyJsonParser.java similarity index 90% rename from src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/GsonParser.java rename to src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/CacheKeyJsonParser.java index 0bbdada..80b2445 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/GsonParser.java +++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/CacheKeyJsonParser.java
@@ -17,17 +17,18 @@ import com.google.common.base.MoreObjects; import com.google.gerrit.entities.Account; import com.google.gerrit.entities.AccountGroup; +import com.google.gerrit.entities.Project; import com.google.gerrit.server.events.EventGson; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.inject.Inject; import com.googlesource.gerrit.plugins.multisite.cache.Constants; -public final class GsonParser { +public final class CacheKeyJsonParser { private final Gson gson; @Inject - public GsonParser(@EventGson Gson gson) { + public CacheKeyJsonParser(@EventGson Gson gson) { this.gson = gson; } @@ -46,6 +47,9 @@ case Constants.GROUPS_MEMBERS: key = AccountGroup.uuid(jsonElement(json).getAsJsonObject().get("uuid").getAsString()); break; + case Constants.PROJECTS: + key = Project.nameKey(jsonElement(json).getAsString()); + break; case Constants.PROJECT_LIST: key = gson.fromJson(nullToEmpty(json).toString(), Object.class); break;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/router/CacheEvictionEventRouter.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/router/CacheEvictionEventRouter.java index 0fb0c0a..a77e168 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/router/CacheEvictionEventRouter.java +++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/router/CacheEvictionEventRouter.java
@@ -16,18 +16,18 @@ import com.google.inject.Inject; import com.googlesource.gerrit.plugins.multisite.forwarder.CacheEntry; +import com.googlesource.gerrit.plugins.multisite.forwarder.CacheKeyJsonParser; import com.googlesource.gerrit.plugins.multisite.forwarder.CacheNotFoundException; import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedCacheEvictionHandler; -import com.googlesource.gerrit.plugins.multisite.forwarder.GsonParser; import com.googlesource.gerrit.plugins.multisite.forwarder.events.CacheEvictionEvent; public class CacheEvictionEventRouter implements ForwardedEventRouter<CacheEvictionEvent> { private final ForwardedCacheEvictionHandler cacheEvictionHanlder; - private final GsonParser gsonParser; + private final CacheKeyJsonParser gsonParser; @Inject public CacheEvictionEventRouter( - ForwardedCacheEvictionHandler cacheEvictionHanlder, GsonParser gsonParser) { + ForwardedCacheEvictionHandler cacheEvictionHanlder, CacheKeyJsonParser gsonParser) { this.cacheEvictionHanlder = cacheEvictionHanlder; this.gsonParser = gsonParser; }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/index/ChangeCheckerImpl.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/index/ChangeCheckerImpl.java index 02972b0..08b26f7 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/index/ChangeCheckerImpl.java +++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/index/ChangeCheckerImpl.java
@@ -15,7 +15,7 @@ package com.googlesource.gerrit.plugins.multisite.index; import com.google.gerrit.entities.Change; -import com.google.gerrit.entities.Comment; +import com.google.gerrit.entities.HumanComment; import com.google.gerrit.exceptions.StorageException; import com.google.gerrit.server.CommentsUtil; import com.google.gerrit.server.change.ChangeFinder; @@ -148,7 +148,7 @@ Change change = notes.getChange(); Timestamp changeTs = change.getLastUpdatedOn(); try { - for (Comment comment : commentsUtil.draftByChange(changeNotes.get())) { + for (HumanComment comment : commentsUtil.draftByChange(changeNotes.get())) { Timestamp commentTs = comment.writtenOn; changeTs = commentTs.after(changeTs) ? commentTs : changeTs; }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/index/IndexEventHandler.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/index/IndexEventHandler.java index 5effd0e..eef3e4b 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/index/IndexEventHandler.java +++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/index/IndexEventHandler.java
@@ -14,6 +14,7 @@ package com.googlesource.gerrit.plugins.multisite.index; +import com.gerritforge.gerrit.globalrefdb.validation.ProjectsFilter; import com.google.common.base.Objects; import com.google.gerrit.extensions.events.AccountIndexedListener; import com.google.gerrit.extensions.events.ChangeIndexedListener; @@ -21,7 +22,6 @@ import com.google.gerrit.extensions.events.ProjectIndexedListener; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.inject.Inject; -import com.googlesource.gerrit.plugins.multisite.ProjectsFilter; import com.googlesource.gerrit.plugins.multisite.forwarder.Context; import com.googlesource.gerrit.plugins.multisite.forwarder.ForwarderTask; import com.googlesource.gerrit.plugins.multisite.forwarder.IndexEventForwarder;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/BatchRefUpdateValidator.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/BatchRefUpdateValidator.java deleted file mode 100644 index 0afe308..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/BatchRefUpdateValidator.java +++ /dev/null
@@ -1,213 +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.common.flogger.FluentLogger; -import com.google.inject.Inject; -import com.google.inject.assistedinject.Assisted; -import com.googlesource.gerrit.plugins.multisite.LockWrapper; -import com.googlesource.gerrit.plugins.multisite.ProjectsFilter; -import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.OutOfSyncException; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedRefEnforcement; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedRefEnforcement.EnforcePolicy; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.eclipse.jgit.lib.BatchRefUpdate; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectIdRef; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.RefDatabase; -import org.eclipse.jgit.transport.ReceiveCommand; - -public class BatchRefUpdateValidator extends RefUpdateValidator { - private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - - public static interface Factory { - BatchRefUpdateValidator create(String projectName, RefDatabase refDb); - } - - public interface BatchValidationWrapper { - void apply(BatchRefUpdate batchRefUpdate, NoParameterVoidFunction arg) throws IOException; - } - - @Inject - public BatchRefUpdateValidator( - SharedRefDatabaseWrapper sharedRefDb, - ValidationMetrics validationMetrics, - SharedRefEnforcement refEnforcement, - LockWrapper.Factory lockWrapperFactory, - ProjectsFilter projectsFilter, - @Assisted String projectName, - @Assisted RefDatabase refDb) { - super( - sharedRefDb, - validationMetrics, - refEnforcement, - lockWrapperFactory, - projectsFilter, - projectName, - refDb); - } - - public void executeBatchUpdateWithValidation( - BatchRefUpdate batchRefUpdate, - NoParameterVoidFunction batchRefUpdateFunction, - OneParameterVoidFunction<List<ReceiveCommand>> batchRefUpdateRollbackFunction) - throws IOException { - if (refEnforcement.getPolicy(projectName) == EnforcePolicy.IGNORED - || !isGlobalProject(projectName)) { - batchRefUpdateFunction.invoke(); - return; - } - - try { - doExecuteBatchUpdate(batchRefUpdate, batchRefUpdateFunction, batchRefUpdateRollbackFunction); - } catch (IOException e) { - logger.atWarning().withCause(e).log( - "Failed to execute Batch Update on project %s", projectName); - if (refEnforcement.getPolicy(projectName) == EnforcePolicy.REQUIRED) { - throw e; - } - } - } - - private void doExecuteBatchUpdate( - BatchRefUpdate batchRefUpdate, - NoParameterVoidFunction delegateUpdate, - OneParameterVoidFunction<List<ReceiveCommand>> delegateUpdateRollback) - throws IOException { - - List<ReceiveCommand> commands = batchRefUpdate.getCommands(); - if (commands.isEmpty()) { - return; - } - - List<RefPair> refsToUpdate = getRefsPairs(commands).collect(Collectors.toList()); - List<RefPair> refsFailures = - refsToUpdate.stream().filter(RefPair::hasFailed).collect(Collectors.toList()); - if (!refsFailures.isEmpty()) { - String allFailuresMessage = - refsFailures.stream() - .map(refPair -> String.format("Failed to fetch ref %s", refPair.compareRef.getName())) - .collect(Collectors.joining(", ")); - Exception firstFailureException = refsFailures.get(0).exception; - - logger.atSevere().withCause(firstFailureException).log(allFailuresMessage); - throw new IOException(allFailuresMessage, firstFailureException); - } - - try (CloseableSet<AutoCloseable> locks = new CloseableSet<>()) { - final List<RefPair> finalRefsToUpdate = compareAndGetLatestLocalRefs(refsToUpdate, locks); - delegateUpdate.invoke(); - try { - updateSharedRefDb(batchRefUpdate.getCommands().stream(), finalRefsToUpdate); - } catch (Exception e) { - List<ReceiveCommand> receiveCommands = batchRefUpdate.getCommands(); - logger.atWarning().withCause(e).log( - String.format( - "Batch ref-update failing because of failure during the global refdb update. Set all commands Result to LOCK_FAILURE [%d]", - receiveCommands.size())); - rollback(delegateUpdateRollback, finalRefsToUpdate, receiveCommands); - } - } catch (OutOfSyncException e) { - List<ReceiveCommand> receiveCommands = batchRefUpdate.getCommands(); - logger.atWarning().withCause(e).log( - String.format( - "Batch ref-update failing because node is out of sync with the shared ref-db. Set all commands Result to LOCK_FAILURE [%d]", - receiveCommands.size())); - receiveCommands.forEach((command) -> command.setResult(ReceiveCommand.Result.LOCK_FAILURE)); - } - } - - private void rollback( - OneParameterVoidFunction<List<ReceiveCommand>> delegateUpdateRollback, - List<RefPair> refsBeforeUpdate, - List<ReceiveCommand> receiveCommands) - throws IOException { - List<ReceiveCommand> rollbackCommands = - refsBeforeUpdate.stream() - .map( - refBeforeUpdate -> - new ReceiveCommand( - refBeforeUpdate.putValue, - refBeforeUpdate.compareRef.getObjectId(), - refBeforeUpdate.getName())) - .collect(Collectors.toList()); - delegateUpdateRollback.invoke(rollbackCommands); - receiveCommands.forEach(command -> command.setResult(ReceiveCommand.Result.LOCK_FAILURE)); - } - - private void updateSharedRefDb(Stream<ReceiveCommand> commandStream, List<RefPair> refsToUpdate) - throws IOException { - if (commandStream - .filter(cmd -> cmd.getResult() != ReceiveCommand.Result.OK) - .findFirst() - .isPresent()) { - return; - } - - for (RefPair refPair : refsToUpdate) { - updateSharedDbOrThrowExceptionFor(refPair); - } - } - - private Stream<RefPair> getRefsPairs(List<ReceiveCommand> receivedCommands) { - return receivedCommands.stream().map(this::getRefPairForCommand); - } - - private RefPair getRefPairForCommand(ReceiveCommand command) { - try { - switch (command.getType()) { - case CREATE: - return new RefPair(nullRef(command.getRefName()), getNewRef(command)); - - case UPDATE: - case UPDATE_NONFASTFORWARD: - return new RefPair(getCurrentRef(command.getRefName()), getNewRef(command)); - - case DELETE: - return new RefPair(getCurrentRef(command.getRefName()), ObjectId.zeroId()); - - default: - return new RefPair( - command.getRef(), - new IllegalArgumentException("Unsupported command type " + command.getType())); - } - } catch (IOException e) { - return new RefPair(command.getRef(), e); - } - } - - private ObjectId getNewRef(ReceiveCommand command) { - return command.getNewId(); - } - - private List<RefPair> compareAndGetLatestLocalRefs( - List<RefPair> refsToUpdate, CloseableSet<AutoCloseable> locks) throws IOException { - List<RefPair> latestRefsToUpdate = new ArrayList<>(); - for (RefPair refPair : refsToUpdate) { - latestRefsToUpdate.add(compareAndGetLatestLocalRef(refPair, locks)); - } - return latestRefsToUpdate; - } - - private static final Ref nullRef(String refName) { - return new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, refName, ObjectId.zeroId()); - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteBatchRefUpdate.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteBatchRefUpdate.java deleted file mode 100644 index fd4f910..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteBatchRefUpdate.java +++ /dev/null
@@ -1,196 +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.inject.Inject; -import com.google.inject.assistedinject.Assisted; -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import org.eclipse.jgit.lib.BatchRefUpdate; -import org.eclipse.jgit.lib.PersonIdent; -import org.eclipse.jgit.lib.ProgressMonitor; -import org.eclipse.jgit.lib.RefDatabase; -import org.eclipse.jgit.revwalk.RevWalk; -import org.eclipse.jgit.transport.PushCertificate; -import org.eclipse.jgit.transport.ReceiveCommand; -import org.eclipse.jgit.util.time.ProposedTimestamp; - -public class MultiSiteBatchRefUpdate extends BatchRefUpdate { - - private final BatchRefUpdate batchRefUpdate; - private final BatchRefUpdate batchRefUpdateRollback; - private final String project; - private final BatchRefUpdateValidator.Factory batchRefValidatorFactory; - private final RefDatabase refDb; - - public static interface Factory { - MultiSiteBatchRefUpdate create(String project, RefDatabase refDb); - } - - @Inject - public MultiSiteBatchRefUpdate( - BatchRefUpdateValidator.Factory batchRefValidatorFactory, - @Assisted String project, - @Assisted RefDatabase refDb) { - super(refDb); - this.refDb = refDb; - this.project = project; - this.batchRefUpdate = refDb.newBatchUpdate(); - this.batchRefUpdateRollback = refDb.newBatchUpdate(); - this.batchRefValidatorFactory = batchRefValidatorFactory; - } - - @Override - public int hashCode() { - return batchRefUpdate.hashCode(); - } - - @Override - public boolean equals(Object obj) { - return batchRefUpdate.equals(obj); - } - - @Override - public boolean isAllowNonFastForwards() { - return batchRefUpdate.isAllowNonFastForwards(); - } - - @Override - public BatchRefUpdate setAllowNonFastForwards(boolean allow) { - batchRefUpdateRollback.setAllowNonFastForwards(allow); - return batchRefUpdate.setAllowNonFastForwards(allow); - } - - @Override - public PersonIdent getRefLogIdent() { - return batchRefUpdate.getRefLogIdent(); - } - - @Override - public BatchRefUpdate setRefLogIdent(PersonIdent pi) { - batchRefUpdateRollback.setRefLogIdent(pi); - return batchRefUpdate.setRefLogIdent(pi); - } - - @Override - public String getRefLogMessage() { - return batchRefUpdate.getRefLogMessage(); - } - - @Override - public boolean isRefLogIncludingResult() { - return batchRefUpdate.isRefLogIncludingResult(); - } - - @Override - public BatchRefUpdate setRefLogMessage(String msg, boolean appendStatus) { - batchRefUpdateRollback.setRefLogMessage(msg, appendStatus); - return batchRefUpdate.setRefLogMessage(msg, appendStatus); - } - - @Override - public BatchRefUpdate disableRefLog() { - return batchRefUpdate.disableRefLog(); - } - - @Override - public BatchRefUpdate setForceRefLog(boolean force) { - batchRefUpdateRollback.setForceRefLog(force); - return batchRefUpdate.setForceRefLog(force); - } - - @Override - public boolean isRefLogDisabled() { - return batchRefUpdate.isRefLogDisabled(); - } - - @Override - public BatchRefUpdate setAtomic(boolean atomic) { - return batchRefUpdate.setAtomic(atomic); - } - - @Override - public boolean isAtomic() { - return batchRefUpdate.isAtomic(); - } - - @Override - public void setPushCertificate(PushCertificate cert) { - batchRefUpdate.setPushCertificate(cert); - } - - @Override - public List<ReceiveCommand> getCommands() { - return batchRefUpdate.getCommands(); - } - - @Override - public BatchRefUpdate addCommand(ReceiveCommand cmd) { - return batchRefUpdate.addCommand(cmd); - } - - @Override - public BatchRefUpdate addCommand(ReceiveCommand... cmd) { - return batchRefUpdate.addCommand(cmd); - } - - @Override - public BatchRefUpdate addCommand(Collection<ReceiveCommand> cmd) { - return batchRefUpdate.addCommand(cmd); - } - - @Override - public List<String> getPushOptions() { - return batchRefUpdate.getPushOptions(); - } - - @Override - public List<ProposedTimestamp> getProposedTimestamps() { - return batchRefUpdate.getProposedTimestamps(); - } - - @Override - public BatchRefUpdate addProposedTimestamp(ProposedTimestamp ts) { - return batchRefUpdate.addProposedTimestamp(ts); - } - - @Override - public void execute(RevWalk walk, ProgressMonitor monitor, List<String> options) - throws IOException { - batchRefValidatorFactory - .create(project, refDb) - .executeBatchUpdateWithValidation( - batchRefUpdate, - () -> batchRefUpdate.execute(walk, monitor, options), - (commands) -> - batchRefUpdateRollback.addCommand(commands).execute(walk, monitor, options)); - } - - @Override - public void execute(RevWalk walk, ProgressMonitor monitor) throws IOException { - batchRefValidatorFactory - .create(project, refDb) - .executeBatchUpdateWithValidation( - batchRefUpdate, - () -> batchRefUpdate.execute(walk, monitor), - (commands) -> batchRefUpdateRollback.addCommand(commands).execute(walk, monitor)); - } - - @Override - public String toString() { - return batchRefUpdate.toString(); - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteGitRepositoryManager.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteGitRepositoryManager.java deleted file mode 100644 index 6ece734..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteGitRepositoryManager.java +++ /dev/null
@@ -1,66 +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.entities.Project; -import com.google.gerrit.server.git.GitRepositoryManager; -import com.google.gerrit.server.git.LocalDiskRepositoryManager; -import com.google.gerrit.server.git.RepositoryCaseMismatchException; -import com.google.inject.Inject; -import com.google.inject.Singleton; -import java.io.IOException; -import java.util.SortedSet; -import org.eclipse.jgit.errors.RepositoryNotFoundException; -import org.eclipse.jgit.lib.Repository; - -@Singleton -public class MultiSiteGitRepositoryManager implements GitRepositoryManager { - private final GitRepositoryManager gitRepositoryManager; - private final MultiSiteRepository.Factory multiSiteRepoFactory; - - @Inject - public MultiSiteGitRepositoryManager( - MultiSiteRepository.Factory multiSiteRepoFactory, - LocalDiskRepositoryManager localDiskRepositoryManager) { - this.multiSiteRepoFactory = multiSiteRepoFactory; - this.gitRepositoryManager = localDiskRepositoryManager; - } - - @Override - public Repository openRepository(Project.NameKey name) - throws RepositoryNotFoundException, IOException { - return wrap(name, gitRepositoryManager.openRepository(name)); - } - - @Override - public Repository createRepository(Project.NameKey name) - throws RepositoryCaseMismatchException, RepositoryNotFoundException, IOException { - return wrap(name, gitRepositoryManager.createRepository(name)); - } - - @Override - public Boolean canPerformGC() { - return gitRepositoryManager.canPerformGC(); - } - - @Override - public SortedSet<Project.NameKey> list() { - return gitRepositoryManager.list(); - } - - private Repository wrap(Project.NameKey projectName, Repository projectRepo) { - return multiSiteRepoFactory.create(projectName.get(), projectRepo); - } -}
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 deleted file mode 100644 index e1d1c65..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRefDatabase.java +++ /dev/null
@@ -1,160 +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.inject.Inject; -import com.google.inject.assistedinject.Assisted; -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import org.eclipse.jgit.lib.BatchRefUpdate; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.RefDatabase; -import org.eclipse.jgit.lib.RefRename; -import org.eclipse.jgit.lib.RefUpdate; - -public class MultiSiteRefDatabase extends RefDatabase { - private final MultiSiteRefUpdate.Factory refUpdateFactory; - private final MultiSiteBatchRefUpdate.Factory batchRefUpdateFactory; - private final String projectName; - private final RefDatabase refDatabase; - - public interface Factory { - public MultiSiteRefDatabase create(String projectName, RefDatabase refDatabase); - } - - @Inject - public MultiSiteRefDatabase( - MultiSiteRefUpdate.Factory refUpdateFactory, - MultiSiteBatchRefUpdate.Factory batchRefUpdateFactory, - @Assisted String projectName, - @Assisted RefDatabase refDatabase) { - this.refUpdateFactory = refUpdateFactory; - this.batchRefUpdateFactory = batchRefUpdateFactory; - this.projectName = projectName; - this.refDatabase = refDatabase; - } - - @Override - public int hashCode() { - return refDatabase.hashCode(); - } - - @Override - public boolean equals(Object obj) { - return refDatabase.equals(obj); - } - - @Override - public void create() throws IOException { - refDatabase.create(); - } - - @Override - public void close() { - refDatabase.close(); - } - - @Override - public boolean isNameConflicting(String name) throws IOException { - return refDatabase.isNameConflicting(name); - } - - @Override - public Collection<String> getConflictingNames(String name) throws IOException { - return refDatabase.getConflictingNames(name); - } - - @Override - public RefUpdate newUpdate(String name, boolean detach) throws IOException { - return wrapRefUpdate(refDatabase.newUpdate(name, detach)); - } - - @Override - public RefRename newRename(String fromName, String toName) throws IOException { - return refDatabase.newRename(fromName, toName); - } - - @Override - public BatchRefUpdate newBatchUpdate() { - return batchRefUpdateFactory.create(projectName, refDatabase); - } - - @Override - public boolean performsAtomicTransactions() { - return refDatabase.performsAtomicTransactions(); - } - - @Override - public String toString() { - return refDatabase.toString(); - } - - @Override - public Ref exactRef(String name) throws IOException { - return refDatabase.exactRef(name); - } - - @Override - public Map<String, Ref> exactRef(String... refs) throws IOException { - return refDatabase.exactRef(refs); - } - - @Override - public Ref firstExactRef(String... refs) throws IOException { - return refDatabase.firstExactRef(refs); - } - - @Override - public List<Ref> getRefs() throws IOException { - return refDatabase.getRefs(); - } - - @SuppressWarnings("deprecation") - @Override - public Map<String, Ref> getRefs(String prefix) throws IOException { - return refDatabase.getRefs(prefix); - } - - @Override - public List<Ref> getRefsByPrefix(String prefix) throws IOException { - return refDatabase.getRefsByPrefix(prefix); - } - - @Override - public boolean hasRefs() throws IOException { - return refDatabase.hasRefs(); - } - - @Override - public List<Ref> getAdditionalRefs() throws IOException { - return refDatabase.getAdditionalRefs(); - } - - @Override - public Ref peel(Ref ref) throws IOException { - return refDatabase.peel(ref); - } - - @Override - public void refresh() { - refDatabase.refresh(); - } - - RefUpdate wrapRefUpdate(RefUpdate refUpdate) { - return refUpdateFactory.create(projectName, refUpdate, refDatabase); - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRefUpdate.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRefUpdate.java deleted file mode 100644 index 20e12fe..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRefUpdate.java +++ /dev/null
@@ -1,260 +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.inject.Inject; -import com.google.inject.assistedinject.Assisted; -import com.googlesource.gerrit.plugins.multisite.validation.RefUpdateValidator.NoParameterFunction; -import java.io.IOException; -import org.eclipse.jgit.lib.AnyObjectId; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.PersonIdent; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.RefDatabase; -import org.eclipse.jgit.lib.RefUpdate; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.revwalk.RevWalk; -import org.eclipse.jgit.transport.PushCertificate; - -public class MultiSiteRefUpdate extends RefUpdate { - - protected final RefUpdate refUpdateBase; - private final String projectName; - private final RefUpdateValidator.Factory refValidatorFactory; - private final RefUpdateValidator refUpdateValidator; - - public interface Factory { - MultiSiteRefUpdate create(String projectName, RefUpdate refUpdate, RefDatabase refDb); - } - - @Inject - public MultiSiteRefUpdate( - RefUpdateValidator.Factory refValidatorFactory, - @Assisted String projectName, - @Assisted RefUpdate refUpdate, - @Assisted RefDatabase refDb) { - super(refUpdate.getRef()); - refUpdateBase = refUpdate; - this.projectName = projectName; - this.refValidatorFactory = refValidatorFactory; - refUpdateValidator = this.refValidatorFactory.create(this.projectName, refDb); - } - - @Override - protected RefDatabase getRefDatabase() { - return notImplementedException(); - } - - private <T> T notImplementedException() { - throw new IllegalStateException("This method should have never been invoked"); - } - - @Override - protected Repository getRepository() { - return notImplementedException(); - } - - @Override - protected boolean tryLock(boolean deref) throws IOException { - return notImplementedException(); - } - - @Override - protected void unlock() { - notImplementedException(); - } - - @Override - protected Result doUpdate(Result result) throws IOException { - return notImplementedException(); - } - - @Override - protected Result doDelete(Result result) throws IOException { - return notImplementedException(); - } - - @Override - protected Result doLink(String target) throws IOException { - return notImplementedException(); - } - - @Override - public Result update() throws IOException { - return refUpdateValidator.executeRefUpdate( - refUpdateBase, - refUpdateBase::update, - objectId -> rollback(objectId, refUpdateBase::update)); - } - - @Override - public Result update(RevWalk rev) throws IOException { - return refUpdateValidator.executeRefUpdate( - refUpdateBase, - () -> refUpdateBase.update(rev), - objectId -> rollback(objectId, () -> refUpdateBase.update(rev))); - } - - @Override - public Result delete() throws IOException { - return refUpdateValidator.executeRefUpdate( - refUpdateBase, - refUpdateBase::delete, - objectId -> rollback(objectId, refUpdateBase::update)); - } - - @Override - public Result delete(RevWalk walk) throws IOException { - return refUpdateValidator.executeRefUpdate( - refUpdateBase, - () -> refUpdateBase.delete(walk), - objectId -> rollback(objectId, () -> refUpdateBase.update(walk))); - } - - @Override - public int hashCode() { - return refUpdateBase.hashCode(); - } - - @Override - public boolean equals(Object obj) { - return refUpdateBase.equals(obj); - } - - @Override - public String toString() { - return refUpdateBase.toString(); - } - - @Override - public String getName() { - return refUpdateBase.getName(); - } - - @Override - public Ref getRef() { - return refUpdateBase.getRef(); - } - - @Override - public ObjectId getNewObjectId() { - return refUpdateBase.getNewObjectId(); - } - - @Override - public void setDetachingSymbolicRef() { - refUpdateBase.setDetachingSymbolicRef(); - } - - @Override - public boolean isDetachingSymbolicRef() { - return refUpdateBase.isDetachingSymbolicRef(); - } - - @Override - public void setNewObjectId(AnyObjectId id) { - refUpdateBase.setNewObjectId(id); - } - - @Override - public ObjectId getExpectedOldObjectId() { - return refUpdateBase.getExpectedOldObjectId(); - } - - @Override - public void setExpectedOldObjectId(AnyObjectId id) { - refUpdateBase.setExpectedOldObjectId(id); - } - - @Override - public boolean isForceUpdate() { - return refUpdateBase.isForceUpdate(); - } - - @Override - public void setForceUpdate(boolean b) { - refUpdateBase.setForceUpdate(b); - } - - @Override - public PersonIdent getRefLogIdent() { - return refUpdateBase.getRefLogIdent(); - } - - @Override - public void setRefLogIdent(PersonIdent pi) { - refUpdateBase.setRefLogIdent(pi); - } - - @Override - public String getRefLogMessage() { - return refUpdateBase.getRefLogMessage(); - } - - @Override - public void setRefLogMessage(String msg, boolean appendStatus) { - refUpdateBase.setRefLogMessage(msg, appendStatus); - } - - @Override - public void disableRefLog() { - refUpdateBase.disableRefLog(); - } - - @Override - public void setForceRefLog(boolean force) { - refUpdateBase.setForceRefLog(force); - } - - @Override - public ObjectId getOldObjectId() { - return refUpdateBase.getOldObjectId(); - } - - @Override - public void setPushCertificate(PushCertificate cert) { - refUpdateBase.setPushCertificate(cert); - } - - @Override - public Result getResult() { - return refUpdateBase.getResult(); - } - - @Override - public Result forceUpdate() throws IOException { - return refUpdateValidator.executeRefUpdate( - refUpdateBase, - refUpdateBase::forceUpdate, - objectId -> rollback(objectId, refUpdateBase::forceUpdate)); - } - - @Override - public Result link(String target) throws IOException { - return refUpdateBase.link(target); - } - - @Override - public void setCheckConflicting(boolean check) { - refUpdateBase.setCheckConflicting(check); - } - - private Result rollback(ObjectId objectId, NoParameterFunction<Result> updateFunction) - throws IOException { - refUpdateBase.setExpectedOldObjectId(refUpdateBase.getNewObjectId()); - refUpdateBase.setNewObjectId(objectId); - return updateFunction.invoke(); - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRepository.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRepository.java deleted file mode 100644 index fa3de64..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRepository.java +++ /dev/null
@@ -1,407 +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.inject.Inject; -import com.google.inject.assistedinject.Assisted; -import java.io.File; -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.Set; -import org.eclipse.jgit.attributes.AttributesNodeProvider; -import org.eclipse.jgit.dircache.DirCache; -import org.eclipse.jgit.errors.AmbiguousObjectException; -import org.eclipse.jgit.errors.CorruptObjectException; -import org.eclipse.jgit.errors.IncorrectObjectTypeException; -import org.eclipse.jgit.errors.MissingObjectException; -import org.eclipse.jgit.errors.NoWorkTreeException; -import org.eclipse.jgit.errors.RevisionSyntaxException; -import org.eclipse.jgit.events.ListenerList; -import org.eclipse.jgit.events.RepositoryEvent; -import org.eclipse.jgit.lib.AnyObjectId; -import org.eclipse.jgit.lib.BaseRepositoryBuilder; -import org.eclipse.jgit.lib.ObjectDatabase; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectInserter; -import org.eclipse.jgit.lib.ObjectLoader; -import org.eclipse.jgit.lib.ObjectReader; -import org.eclipse.jgit.lib.ProgressMonitor; -import org.eclipse.jgit.lib.RebaseTodoLine; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.RefDatabase; -import org.eclipse.jgit.lib.RefRename; -import org.eclipse.jgit.lib.RefUpdate; -import org.eclipse.jgit.lib.ReflogReader; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.lib.RepositoryState; -import org.eclipse.jgit.lib.StoredConfig; -import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.util.FS; - -public class MultiSiteRepository extends Repository { - - private final Repository repository; - private final RefDatabase refDatabase; - private final MultiSiteRefDatabase multiSiteRefDatabase; - - public interface Factory { - public MultiSiteRepository create(String projectName, Repository repository); - } - - @Inject - public MultiSiteRepository( - MultiSiteRefDatabase.Factory multiSiteRefDbFactory, - @Assisted String projectName, - @Assisted Repository repository) { - super(new BaseRepositoryBuilder()); - this.repository = repository; - this.refDatabase = repository.getRefDatabase(); - this.multiSiteRefDatabase = multiSiteRefDbFactory.create(projectName, refDatabase); - } - - @Override - public void create(boolean b) throws IOException {} - - @Override - public ObjectDatabase getObjectDatabase() { - return repository.getObjectDatabase(); - } - - @Override - public RefDatabase getRefDatabase() { - return multiSiteRefDatabase; - } - - @Override - public StoredConfig getConfig() { - return repository.getConfig(); - } - - @Override - public AttributesNodeProvider createAttributesNodeProvider() { - return repository.createAttributesNodeProvider(); - } - - @Override - public void scanForRepoChanges() throws IOException { - repository.scanForRepoChanges(); - } - - @Override - public void notifyIndexChanged(boolean b) { - repository.notifyIndexChanged(b); - } - - @Override - public ReflogReader getReflogReader(String s) throws IOException { - return repository.getReflogReader(s); - } - - @Override - public int hashCode() { - return repository.hashCode(); - } - - @Override - public boolean equals(Object obj) { - return repository.equals(obj); - } - - @Override - public ListenerList getListenerList() { - return repository.getListenerList(); - } - - @Override - public void fireEvent(RepositoryEvent<?> event) { - repository.fireEvent(event); - } - - @Override - public void create() throws IOException { - repository.create(); - } - - @Override - public File getDirectory() { - return repository.getDirectory(); - } - - @Override - public ObjectInserter newObjectInserter() { - return repository.newObjectInserter(); - } - - @Override - public ObjectReader newObjectReader() { - return repository.newObjectReader(); - } - - @Override - public FS getFS() { - return repository.getFS(); - } - - @SuppressWarnings("deprecation") - @Override - public boolean hasObject(AnyObjectId objectId) { - return repository.hasObject(objectId); - } - - @Override - public ObjectLoader open(AnyObjectId objectId) throws MissingObjectException, IOException { - return repository.open(objectId); - } - - @Override - public ObjectLoader open(AnyObjectId objectId, int typeHint) - throws MissingObjectException, IncorrectObjectTypeException, IOException { - return repository.open(objectId, typeHint); - } - - @Override - public RefUpdate updateRef(String ref) throws IOException { - return multiSiteRefDatabase.wrapRefUpdate(repository.updateRef(ref)); - } - - @Override - public RefUpdate updateRef(String ref, boolean detach) throws IOException { - return multiSiteRefDatabase.wrapRefUpdate(repository.updateRef(ref, detach)); - } - - @Override - public RefRename renameRef(String fromRef, String toRef) throws IOException { - return repository.renameRef(fromRef, toRef); - } - - @Override - public ObjectId resolve(String revstr) - throws AmbiguousObjectException, IncorrectObjectTypeException, RevisionSyntaxException, - IOException { - return repository.resolve(revstr); - } - - @Override - public String simplify(String revstr) throws AmbiguousObjectException, IOException { - return repository.simplify(revstr); - } - - @Override - public void incrementOpen() { - repository.incrementOpen(); - } - - @Override - public void close() { - repository.close(); - } - - @Override - public String toString() { - return repository.toString(); - } - - @Override - public String getFullBranch() throws IOException { - return repository.getFullBranch(); - } - - @Override - public String getBranch() throws IOException { - return repository.getBranch(); - } - - @Override - public Set<ObjectId> getAdditionalHaves() { - return repository.getAdditionalHaves(); - } - - @SuppressWarnings("deprecation") - @Override - public Map<String, Ref> getAllRefs() { - return repository.getAllRefs(); - } - - @SuppressWarnings("deprecation") - @Override - public Map<String, Ref> getTags() { - return repository.getTags(); - } - - @SuppressWarnings("deprecation") - @Override - public Ref peel(Ref ref) { - return repository.peel(ref); - } - - @Override - public Map<AnyObjectId, Set<Ref>> getAllRefsByPeeledObjectId() { - return repository.getAllRefsByPeeledObjectId(); - } - - @Override - public File getIndexFile() throws NoWorkTreeException { - return repository.getIndexFile(); - } - - @Override - public RevCommit parseCommit(AnyObjectId id) - throws IncorrectObjectTypeException, IOException, MissingObjectException { - return repository.parseCommit(id); - } - - @Override - public DirCache readDirCache() throws NoWorkTreeException, CorruptObjectException, IOException { - return repository.readDirCache(); - } - - @Override - public DirCache lockDirCache() throws NoWorkTreeException, CorruptObjectException, IOException { - return repository.lockDirCache(); - } - - @Override - public RepositoryState getRepositoryState() { - return repository.getRepositoryState(); - } - - @Override - public boolean isBare() { - return repository.isBare(); - } - - @Override - public File getWorkTree() throws NoWorkTreeException { - return repository.getWorkTree(); - } - - @Override - public String shortenRemoteBranchName(String refName) { - return repository.shortenRemoteBranchName(refName); - } - - @Override - public String getRemoteName(String refName) { - return repository.getRemoteName(refName); - } - - @Override - public String getGitwebDescription() throws IOException { - return repository.getGitwebDescription(); - } - - @Override - public void setGitwebDescription(String description) throws IOException { - repository.setGitwebDescription(description); - } - - @Override - public String readMergeCommitMsg() throws IOException, NoWorkTreeException { - return repository.readMergeCommitMsg(); - } - - @Override - public void writeMergeCommitMsg(String msg) throws IOException { - repository.writeMergeCommitMsg(msg); - } - - @Override - public String readCommitEditMsg() throws IOException, NoWorkTreeException { - return repository.readCommitEditMsg(); - } - - @Override - public void writeCommitEditMsg(String msg) throws IOException { - repository.writeCommitEditMsg(msg); - } - - @Override - public List<ObjectId> readMergeHeads() throws IOException, NoWorkTreeException { - return repository.readMergeHeads(); - } - - @Override - public void writeMergeHeads(List<? extends ObjectId> heads) throws IOException { - repository.writeMergeHeads(heads); - } - - @Override - public ObjectId readCherryPickHead() throws IOException, NoWorkTreeException { - return repository.readCherryPickHead(); - } - - @Override - public ObjectId readRevertHead() throws IOException, NoWorkTreeException { - return repository.readRevertHead(); - } - - @Override - public void writeCherryPickHead(ObjectId head) throws IOException { - repository.writeCherryPickHead(head); - } - - @Override - public void writeRevertHead(ObjectId head) throws IOException { - repository.writeRevertHead(head); - } - - @Override - public void writeOrigHead(ObjectId head) throws IOException { - repository.writeOrigHead(head); - } - - @Override - public ObjectId readOrigHead() throws IOException, NoWorkTreeException { - return repository.readOrigHead(); - } - - @Override - public String readSquashCommitMsg() throws IOException { - return repository.readSquashCommitMsg(); - } - - @Override - public void writeSquashCommitMsg(String msg) throws IOException { - repository.writeSquashCommitMsg(msg); - } - - @Override - public List<RebaseTodoLine> readRebaseTodo(String path, boolean includeComments) - throws IOException { - return repository.readRebaseTodo(path, includeComments); - } - - @Override - public void writeRebaseTodoFile(String path, List<RebaseTodoLine> steps, boolean append) - throws IOException { - repository.writeRebaseTodoFile(path, steps, append); - } - - @Override - public Set<String> getRemoteNames() { - return repository.getRemoteNames(); - } - - @Override - public void autoGC(ProgressMonitor monitor) { - repository.autoGC(monitor); - } - - @Override - public String getIdentifier() { - return repository.getIdentifier(); - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationPushFilter.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationPushFilter.java index f831671..98f4897 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationPushFilter.java +++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationPushFilter.java
@@ -15,13 +15,13 @@ package com.googlesource.gerrit.plugins.multisite.validation; import com.gerritforge.gerrit.globalrefdb.GlobalRefDbLockException; +import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDatabaseWrapper; import com.google.common.base.Preconditions; import com.google.common.flogger.FluentLogger; import com.google.gerrit.entities.Project; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.inject.Inject; import com.google.inject.Singleton; -import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper; import com.googlesource.gerrit.plugins.replication.ReplicationPushFilter; import java.io.IOException; import java.util.Collections;
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 deleted file mode 100644 index 329c1c3..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectDeletedSharedDbCleanup.java +++ /dev/null
@@ -1,54 +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.gerritforge.gerrit.globalrefdb.GlobalRefDbSystemError; -import com.google.common.flogger.FluentLogger; -import com.google.gerrit.entities.Project; -import com.google.gerrit.extensions.events.ProjectDeletedListener; -import com.google.inject.Inject; -import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper; - -public class ProjectDeletedSharedDbCleanup implements ProjectDeletedListener { - private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - - private final SharedRefDatabaseWrapper sharedDb; - - private final ValidationMetrics validationMetrics; - - @Inject - public ProjectDeletedSharedDbCleanup( - SharedRefDatabaseWrapper 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.remove(Project.nameKey(projectName)); - } catch (GlobalRefDbSystemError 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/ProjectVersionRefUpdate.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectVersionRefUpdate.java index c8ddb43..28eddbb 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectVersionRefUpdate.java +++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectVersionRefUpdate.java
@@ -18,6 +18,8 @@ import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; import com.gerritforge.gerrit.globalrefdb.GlobalRefDbSystemError; +import com.gerritforge.gerrit.globalrefdb.validation.ProjectsFilter; +import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDatabaseWrapper; import com.google.common.collect.ImmutableSet; import com.google.common.flogger.FluentLogger; import com.google.gerrit.entities.Project; @@ -31,8 +33,6 @@ import com.google.inject.Inject; import com.google.inject.Singleton; import com.googlesource.gerrit.plugins.multisite.ProjectVersionLogger; -import com.googlesource.gerrit.plugins.multisite.ProjectsFilter; -import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper; import com.googlesource.gerrit.plugins.multisite.forwarder.Context; import java.io.IOException; import java.util.Optional;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/RefPair.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/RefPair.java deleted file mode 100644 index 77ae4f1..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/RefPair.java +++ /dev/null
@@ -1,47 +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 org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.Ref; - -public class RefPair { - public final Ref compareRef; - public final ObjectId putValue; - public final Exception exception; - - RefPair(Ref oldRef, ObjectId newRefValue) { - if (oldRef == null) { - throw new IllegalArgumentException("Required not-null ref in RefPair"); - } - this.compareRef = oldRef; - this.putValue = newRefValue; - this.exception = null; - } - - RefPair(Ref newRef, Exception e) { - this.compareRef = newRef; - this.exception = e; - this.putValue = ObjectId.zeroId(); - } - - public String getName() { - return compareRef.getName(); - } - - public boolean hasFailed() { - return exception != null; - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/RefUpdateValidator.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/RefUpdateValidator.java deleted file mode 100644 index c110f0f..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/RefUpdateValidator.java +++ /dev/null
@@ -1,309 +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.gerritforge.gerrit.globalrefdb.GlobalRefDbSystemError; -import com.google.common.base.MoreObjects; -import com.google.common.flogger.FluentLogger; -import com.google.gerrit.entities.Project; -import com.google.inject.Inject; -import com.google.inject.assistedinject.Assisted; -import com.googlesource.gerrit.plugins.multisite.LockWrapper; -import com.googlesource.gerrit.plugins.multisite.ProjectsFilter; -import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.OutOfSyncException; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedDbSplitBrainException; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedLockException; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedRefEnforcement; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedRefEnforcement.EnforcePolicy; -import java.io.IOException; -import java.util.HashMap; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectIdRef; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.RefDatabase; -import org.eclipse.jgit.lib.RefUpdate; -import org.eclipse.jgit.lib.RefUpdate.Result; - -public class RefUpdateValidator { - private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - - protected final SharedRefDatabaseWrapper sharedRefDb; - protected final ValidationMetrics validationMetrics; - - protected final String projectName; - private final LockWrapper.Factory lockWrapperFactory; - protected final RefDatabase refDb; - protected final SharedRefEnforcement refEnforcement; - protected final ProjectsFilter projectsFilter; - - public static interface Factory { - RefUpdateValidator create(String projectName, RefDatabase refDb); - } - - public interface ExceptionThrowingSupplier<T, E extends Exception> { - T create() throws E; - } - - public interface RefValidationWrapper { - RefUpdate.Result apply(NoParameterFunction<RefUpdate.Result> arg, RefUpdate refUpdate) - throws IOException; - } - - public interface NoParameterFunction<T> { - T invoke() throws IOException; - } - - public interface NoParameterVoidFunction { - void invoke() throws IOException; - } - - public interface OneParameterFunction<F, T> { - T invoke(F f) throws IOException; - } - - public interface OneParameterVoidFunction<T> { - void invoke(T f) throws IOException; - } - - @Inject - public RefUpdateValidator( - SharedRefDatabaseWrapper sharedRefDb, - ValidationMetrics validationMetrics, - SharedRefEnforcement refEnforcement, - LockWrapper.Factory lockWrapperFactory, - ProjectsFilter projectsFilter, - @Assisted String projectName, - @Assisted RefDatabase refDb) { - this.sharedRefDb = sharedRefDb; - this.validationMetrics = validationMetrics; - this.lockWrapperFactory = lockWrapperFactory; - this.refDb = refDb; - this.projectName = projectName; - this.refEnforcement = refEnforcement; - this.projectsFilter = projectsFilter; - } - - public RefUpdate.Result executeRefUpdate( - RefUpdate refUpdate, - NoParameterFunction<RefUpdate.Result> refUpdateFunction, - OneParameterFunction<ObjectId, Result> rollbackFunction) - throws IOException { - if (isProjectVersionUpdate(refUpdate.getName()) - || !isGlobalProject(projectName) - || refEnforcement.getPolicy(projectName) == EnforcePolicy.IGNORED) { - return refUpdateFunction.invoke(); - } - - return doExecuteRefUpdate(refUpdate, refUpdateFunction, rollbackFunction); - } - - private Boolean isProjectVersionUpdate(String refName) { - Boolean isProjectVersionUpdate = - refName.equals(ProjectVersionRefUpdate.MULTI_SITE_VERSIONING_REF); - logger.atFine().log("Is project version update? " + isProjectVersionUpdate); - return isProjectVersionUpdate; - } - - private <T extends Throwable> void softFailBasedOnEnforcement(T e, EnforcePolicy policy) - throws T { - logger.atWarning().withCause(e).log( - String.format( - "Failure while running with policy enforcement %s. Error message: %s", - policy, e.getMessage())); - if (policy == EnforcePolicy.REQUIRED) { - throw e; - } - } - - protected Boolean isGlobalProject(String projectName) { - Boolean isGlobalProject = projectsFilter.matches(projectName); - logger.atFine().log("Is global project? " + isGlobalProject); - return isGlobalProject; - } - - protected RefUpdate.Result doExecuteRefUpdate( - RefUpdate refUpdate, - NoParameterFunction<Result> refUpdateFunction, - OneParameterFunction<ObjectId, Result> rollbackFunction) - throws IOException { - try (CloseableSet<AutoCloseable> locks = new CloseableSet<>()) { - RefPair refPairForUpdate = newRefPairFrom(refUpdate); - compareAndGetLatestLocalRef(refPairForUpdate, locks); - RefUpdate.Result result = refUpdateFunction.invoke(); - try { - if (isSuccessful(result)) { - updateSharedDbOrThrowExceptionFor(refPairForUpdate); - } - } catch (Exception e) { - result = rollbackFunction.invoke(refPairForUpdate.compareRef.getObjectId()); - if (isSuccessful(result)) { - result = RefUpdate.Result.LOCK_FAILURE; - } - logger.atSevere().withCause(e).log( - String.format( - "Failed to update global refdb, the local refdb has been rolled back: %s", - e.getMessage())); - } - return result; - } catch (OutOfSyncException e) { - logger.atWarning().withCause(e).log( - String.format("Local node is out of sync with ref-db: %s", e.getMessage())); - - return RefUpdate.Result.LOCK_FAILURE; - } - } - - protected void updateSharedDbOrThrowExceptionFor(RefPair refPair) throws IOException { - // We are not checking refs that should be ignored - final EnforcePolicy refEnforcementPolicy = - refEnforcement.getPolicy(projectName, refPair.getName()); - if (refEnforcementPolicy == EnforcePolicy.IGNORED) return; - - String errorMessage = - String.format( - "Not able to persist the data in Zookeeper for project '%s' and ref '%s'," - + "the cluster is now in Split Brain since the commit has been " - + "persisted locally but not in SharedRef the value %s", - projectName, refPair.getName(), refPair.putValue); - boolean succeeded; - try { - succeeded = - sharedRefDb.compareAndPut( - Project.nameKey(projectName), refPair.compareRef, refPair.putValue); - } catch (GlobalRefDbSystemError e) { - logger.atWarning().withCause(e).log( - "Not able to persist the data in Zookeeper for project '{}' and ref '{}', message: {}", - projectName, - refPair.getName(), - e.getMessage()); - throw e; - } - - if (!succeeded) { - throw new SharedDbSplitBrainException(errorMessage); - } - } - - protected RefPair compareAndGetLatestLocalRef(RefPair refPair, CloseableSet<AutoCloseable> locks) - throws SharedLockException, OutOfSyncException, IOException { - String refName = refPair.getName(); - EnforcePolicy refEnforcementPolicy = refEnforcement.getPolicy(projectName, refName); - if (refEnforcementPolicy == EnforcePolicy.IGNORED) { - return refPair; - } - - locks.addResourceIfNotExist( - String.format("%s-%s", projectName, refName), - () -> - lockWrapperFactory.create( - projectName, refName, sharedRefDb.lockRef(Project.nameKey(projectName), refName))); - - RefPair latestRefPair = getLatestLocalRef(refPair); - if (sharedRefDb.isUpToDate(Project.nameKey(projectName), latestRefPair.compareRef)) { - return latestRefPair; - } - - if (isNullRef(latestRefPair.compareRef) - || sharedRefDb.exists(Project.nameKey(projectName), refName)) { - validationMetrics.incrementSplitBrainPrevention(); - - softFailBasedOnEnforcement( - new OutOfSyncException(projectName, latestRefPair.compareRef), refEnforcementPolicy); - } - - return latestRefPair; - } - - private boolean isNullRef(Ref ref) { - return ref.getObjectId().equals(ObjectId.zeroId()); - } - - private RefPair getLatestLocalRef(RefPair refPair) throws IOException { - Ref latestRef = refDb.exactRef(refPair.getName()); - return new RefPair( - latestRef == null ? nullRef(refPair.getName()) : latestRef, refPair.putValue); - } - - private Ref nullRef(String name) { - return new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, name, ObjectId.zeroId()); - } - - protected boolean isSuccessful(RefUpdate.Result result) { - switch (result) { - case NEW: - case FORCED: - case FAST_FORWARD: - case NO_CHANGE: - case RENAMED: - return true; - - case REJECTED_OTHER_REASON: - case REJECTED_MISSING_OBJECT: - case REJECTED_CURRENT_BRANCH: - case NOT_ATTEMPTED: - case LOCK_FAILURE: - case IO_FAILURE: - case REJECTED: - default: - return false; - } - } - - protected RefPair newRefPairFrom(RefUpdate refUpdate) throws IOException { - return new RefPair(getCurrentRef(refUpdate.getName()), refUpdate.getNewObjectId()); - } - - protected Ref getCurrentRef(String refName) throws IOException { - return MoreObjects.firstNonNull(refDb.findRef(refName), nullRef(refName)); - } - - public static class CloseableSet<T extends AutoCloseable> implements AutoCloseable { - private final HashMap<String, AutoCloseable> elements; - - public CloseableSet() { - this(new HashMap<>()); - } - - public CloseableSet(HashMap<String, AutoCloseable> elements) { - this.elements = elements; - } - - public void addResourceIfNotExist( - String key, ExceptionThrowingSupplier<T, SharedLockException> resourceFactory) - throws SharedLockException { - if (!elements.containsKey(key)) { - elements.put(key, resourceFactory.create()); - } - } - - @Override - public void close() { - elements.values().stream() - .forEach( - closeable -> { - try { - closeable.close(); - } catch (Exception closingException) { - logger.atSevere().withCause(closingException).log( - "Exception trying to release resource %s, " - + "the locked resources won't be accessible in all cluster unless" - + " the lock is removed from ZK manually", - closeable); - } - }); - } - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationMetrics.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationMetrics.java deleted file mode 100644 index cd2129a..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationMetrics.java +++ /dev/null
@@ -1,57 +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.metrics.Counter1; -import com.google.gerrit.metrics.MetricMaker; -import com.google.inject.Inject; -import com.google.inject.Singleton; -import com.googlesource.gerrit.plugins.multisite.MultiSiteMetrics; - -@Singleton -public class ValidationMetrics extends MultiSiteMetrics { - private static final String GIT_UPDATE_SPLIT_BRAIN_PREVENTED = "git_update_split_brain_prevented"; - private static final String GIT_UPDATE_SPLIT_BRAIN = "git_update_split_brain"; - - private final Counter1<String> splitBrainPreventionCounter; - private final Counter1<String> splitBrainCounter; - - @Inject - public ValidationMetrics(MetricMaker metricMaker) { - this.splitBrainPreventionCounter = - metricMaker.newCounter( - "multi_site/validation/git_update_split_brain_prevented", - rateDescription("errors", "Rate of REST API error responses"), - stringField( - GIT_UPDATE_SPLIT_BRAIN_PREVENTED, - "Ref-update operations, split-brain detected and prevented")); - - this.splitBrainCounter = - metricMaker.newCounter( - "multi_site/validation/git_update_split_brain", - rateDescription("errors", "Rate of REST API error responses"), - stringField( - GIT_UPDATE_SPLIT_BRAIN, - "Ref-update operation left node in a split-brain scenario")); - } - - public void incrementSplitBrainPrevention() { - splitBrainPreventionCounter.increment(GIT_UPDATE_SPLIT_BRAIN_PREVENTED); - } - - public void incrementSplitBrain() { - splitBrainCounter.increment(GIT_UPDATE_SPLIT_BRAIN); - } -}
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 4a34b7a..fe224ae 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,20 +14,31 @@ package com.googlesource.gerrit.plugins.multisite.validation; +import com.gerritforge.gerrit.globalrefdb.validation.BatchRefUpdateValidator; +import com.gerritforge.gerrit.globalrefdb.validation.LockWrapper; +import com.gerritforge.gerrit.globalrefdb.validation.Log4jSharedRefLogger; +import com.gerritforge.gerrit.globalrefdb.validation.RefUpdateValidator; +import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDatabaseWrapper; +import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbBatchRefUpdate; +import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbConfiguration; +import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbGitRepositoryManager; +import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbRefDatabase; +import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbRefUpdate; +import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbRepository; +import com.gerritforge.gerrit.globalrefdb.validation.SharedRefLogger; +import com.gerritforge.gerrit.globalrefdb.validation.dfsrefdb.CustomSharedRefEnforcementByProject; +import com.gerritforge.gerrit.globalrefdb.validation.dfsrefdb.DefaultSharedRefEnforcement; +import com.gerritforge.gerrit.globalrefdb.validation.dfsrefdb.SharedRefEnforcement; +import com.google.common.collect.ImmutableSet; import com.google.gerrit.extensions.config.FactoryModule; import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.inject.Scopes; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; import com.googlesource.gerrit.plugins.multisite.Configuration; -import com.googlesource.gerrit.plugins.multisite.LockWrapper; import com.googlesource.gerrit.plugins.multisite.Log4jProjectVersionLogger; -import com.googlesource.gerrit.plugins.multisite.Log4jSharedRefLogger; import com.googlesource.gerrit.plugins.multisite.ProjectVersionLogger; -import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper; -import com.googlesource.gerrit.plugins.multisite.SharedRefLogger; -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.replication.ReplicationExtensionPointModule; import com.googlesource.gerrit.plugins.replication.ReplicationPushFilter; @@ -47,18 +58,25 @@ bind(ProjectVersionLogger.class).to(Log4jProjectVersionLogger.class); factory(LockWrapper.Factory.class); - factory(MultiSiteRepository.Factory.class); - factory(MultiSiteRefDatabase.Factory.class); - factory(MultiSiteRefUpdate.Factory.class); - factory(MultiSiteBatchRefUpdate.Factory.class); + factory(SharedRefDbRepository.Factory.class); + factory(SharedRefDbRefDatabase.Factory.class); + factory(SharedRefDbRefUpdate.Factory.class); + factory(SharedRefDbBatchRefUpdate.Factory.class); factory(RefUpdateValidator.Factory.class); factory(BatchRefUpdateValidator.Factory.class); - bind(GitRepositoryManager.class).to(MultiSiteGitRepositoryManager.class); + bind(SharedRefDbConfiguration.class).toInstance(cfg.getSharedRefDbConfiguration()); + bind(new TypeLiteral<ImmutableSet<String>>() {}) + .annotatedWith(Names.named(SharedRefDbGitRepositoryManager.IGNORED_REFS)) + .toInstance( + ImmutableSet.of( + ProjectVersionRefUpdate.MULTI_SITE_VERSIONING_REF, + ProjectVersionRefUpdate.MULTI_SITE_VERSIONING_VALUE_REF)); + bind(GitRepositoryManager.class).to(SharedRefDbGitRepositoryManager.class); DynamicItem.bind(binder(), ReplicationPushFilter.class) .to(MultisiteReplicationPushFilter.class); - if (cfg.getSharedRefDb().getEnforcementRules().isEmpty()) { + if (cfg.getSharedRefDbConfiguration().getSharedRefDb().getEnforcementRules().isEmpty()) { bind(SharedRefEnforcement.class).to(DefaultSharedRefEnforcement.class).in(Scopes.SINGLETON); } else { bind(SharedRefEnforcement.class)
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 deleted file mode 100644 index 77a0c0b..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/CustomSharedRefEnforcementByProject.java +++ /dev/null
@@ -1,103 +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.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.getSharedRefDb().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/DefaultSharedRefEnforcement.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/DefaultSharedRefEnforcement.java deleted file mode 100644 index 01cd5c5..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/DefaultSharedRefEnforcement.java +++ /dev/null
@@ -1,28 +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.dfsrefdb; - -public class DefaultSharedRefEnforcement implements SharedRefEnforcement { - - @Override - public EnforcePolicy getPolicy(String projectName, String refName) { - return isRefToBeIgnoredBySharedRefDb(refName) ? EnforcePolicy.IGNORED : EnforcePolicy.REQUIRED; - } - - @Override - public EnforcePolicy getPolicy(String projectName) { - return EnforcePolicy.REQUIRED; - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/NoopSharedRefDatabase.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/NoopSharedRefDatabase.java deleted file mode 100644 index 1530838..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/NoopSharedRefDatabase.java +++ /dev/null
@@ -1,63 +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.dfsrefdb; - -import com.gerritforge.gerrit.globalrefdb.GlobalRefDatabase; -import com.gerritforge.gerrit.globalrefdb.GlobalRefDbLockException; -import com.gerritforge.gerrit.globalrefdb.GlobalRefDbSystemError; -import com.google.gerrit.entities.Project; -import java.util.Optional; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.Ref; - -public class NoopSharedRefDatabase implements GlobalRefDatabase { - - @Override - public boolean isUpToDate(Project.NameKey project, Ref ref) throws GlobalRefDbLockException { - return true; - } - - @Override - public boolean compareAndPut(Project.NameKey project, Ref currRef, ObjectId newRefValue) - throws GlobalRefDbSystemError { - return true; - } - - @Override - public <T> boolean compareAndPut(Project.NameKey project, String refName, T currValue, T newValue) - throws GlobalRefDbSystemError { - return false; - } - - @Override - public AutoCloseable lockRef(Project.NameKey project, String refName) - throws GlobalRefDbLockException { - return () -> {}; - } - - @Override - public boolean exists(Project.NameKey project, String refName) { - return false; - } - - @Override - public void remove(Project.NameKey project) throws GlobalRefDbSystemError {} - - @Override - public <T> Optional<T> get(Project.NameKey project, String refName, Class<T> clazz) - throws GlobalRefDbSystemError { - return Optional.empty(); - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/OutOfSyncException.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/OutOfSyncException.java deleted file mode 100644 index 50f06b9..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/OutOfSyncException.java +++ /dev/null
@@ -1,34 +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.dfsrefdb; - -import java.io.IOException; -import org.eclipse.jgit.lib.Ref; - -/** Local project/ref is out of sync with the shared refdb */ -public class OutOfSyncException extends IOException { - private static final long serialVersionUID = 1L; - - public OutOfSyncException(String project, Ref localRef) { - super( - localRef == null - ? String.format( - "Local ref doesn't exists locally for project %s but exists in the shared ref-db", - project) - : String.format( - "Local ref %s (ObjectId=%s) on project %s is out of sync with the shared ref-db", - localRef.getName(), localRef.getObjectId().getName(), project)); - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/SharedDbSplitBrainException.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/SharedDbSplitBrainException.java deleted file mode 100644 index 8ca54c9..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/SharedDbSplitBrainException.java +++ /dev/null
@@ -1,29 +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.dfsrefdb; - -import java.io.IOException; - -public class SharedDbSplitBrainException extends IOException { - private static final long serialVersionUID = 1L; - - public SharedDbSplitBrainException(String message) { - super(message); - } - - public SharedDbSplitBrainException(String message, Throwable cause) { - super(message, cause); - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/SharedLockException.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/SharedLockException.java deleted file mode 100644 index e53c37c..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/SharedLockException.java +++ /dev/null
@@ -1,26 +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.dfsrefdb; - -import java.io.IOException; - -/** Unable to lock a project/ref resource. */ -public class SharedLockException extends IOException { - private static final long serialVersionUID = 1L; - - public SharedLockException(String project, String refName, Exception cause) { - super(String.format("Unable to lock project %s on ref %s", project, refName), cause); - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/SharedRefEnforcement.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/SharedRefEnforcement.java deleted file mode 100644 index 100def2..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/SharedRefEnforcement.java +++ /dev/null
@@ -1,53 +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.dfsrefdb; - -/** Type of enforcement to implement between the local and shared RefDb. */ -public interface SharedRefEnforcement { - public enum EnforcePolicy { - IGNORED, - REQUIRED; - } - - /** - * Get the enforcement policy for a project/refName. - * - * @param projectName project to be enforced - * @param refName ref name to be enforced - * @return the {@link EnforcePolicy} value - */ - public EnforcePolicy getPolicy(String projectName, String refName); - - /** - * Get the enforcement policy for a project - * - * @param projectName - * @return the {@link EnforcePolicy} value - */ - public EnforcePolicy getPolicy(String projectName); - - /** - * Check if a refName should be ignored by shared Ref-Db - * - * @param refName - * @return true if ref should be ignored; false otherwise - */ - default boolean isRefToBeIgnoredBySharedRefDb(String refName) { - return refName == null - || refName.startsWith("refs/draft-comments") - || (refName.startsWith("refs/changes") && !refName.endsWith("/meta")) - || refName.startsWith("refs/cache-automerge"); - } -}
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md index b6de0a9..623871b 100644 --- a/src/main/resources/Documentation/about.md +++ b/src/main/resources/Documentation/about.md
@@ -10,6 +10,8 @@ * events-broker library must be installed as a library module in the `$GERRIT_SITE/lib` directory of all the masters +* global-refdb library must be installed as a library module in the + `$GERRIT_SITE/lib` directory of all the masters * connected to the same message broker * behind a load balancer (e.g., HAProxy)
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/ProjectsFilterTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/ProjectsFilterTest.java deleted file mode 100644 index e81c906..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/ProjectsFilterTest.java +++ /dev/null
@@ -1,180 +0,0 @@ -// Copyright (C) 2020 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package com.googlesource.gerrit.plugins.multisite; - -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.google.common.collect.Lists; -import com.google.gerrit.entities.Project.NameKey; -import com.google.gerrit.server.events.Event; -import com.google.gerrit.server.events.ProjectEvent; -import com.google.gerrit.server.events.RefUpdatedEvent; -import com.google.gerrit.testing.GerritJUnit; -import com.googlesource.gerrit.plugins.multisite.Configuration.Projects; -import java.util.Collections; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class ProjectsFilterTest { - - @Mock private Configuration configuration; - @Mock private Projects projects; - - private ProjectsFilter objectUnderTest; - - @Test - public void shouldMatchByExactProjectName() { - when(projects.getPatterns()).thenReturn(Lists.newArrayList("test_project")); - when(configuration.projects()).thenReturn(projects); - - objectUnderTest = new ProjectsFilter(configuration); - - assertThat(objectUnderTest.matches(NameKey.parse("test_project"))).isTrue(); - assertThat(objectUnderTest.matches(NameKey.parse("test_project2"))).isFalse(); - } - - @Test - public void shouldMatchByWildcard() { - when(projects.getPatterns()).thenReturn(Lists.newArrayList("test_project*")); - when(configuration.projects()).thenReturn(projects); - - objectUnderTest = new ProjectsFilter(configuration); - - assertThat(objectUnderTest.matches(NameKey.parse("test_project"))).isTrue(); - assertThat(objectUnderTest.matches(NameKey.parse("test_project2"))).isTrue(); - assertThat(objectUnderTest.matches(NameKey.parse("2test_project"))).isFalse(); - } - - @Test - public void shouldMatchByRegex() { - when(projects.getPatterns()).thenReturn(Lists.newArrayList("^test_(project|project2)")); - when(configuration.projects()).thenReturn(projects); - - objectUnderTest = new ProjectsFilter(configuration); - - assertThat(objectUnderTest.matches(NameKey.parse("test_project"))).isTrue(); - assertThat(objectUnderTest.matches(NameKey.parse("test_project2"))).isTrue(); - assertThat(objectUnderTest.matches(NameKey.parse("test_project3"))).isFalse(); - } - - @Test - public void shouldExcludeByRegex() { - when(projects.getPatterns()).thenReturn(Lists.newArrayList("^(?:(?!test_project3).)*$")); - when(configuration.projects()).thenReturn(projects); - - objectUnderTest = new ProjectsFilter(configuration); - - assertThat(objectUnderTest.matches(NameKey.parse("test_project"))).isTrue(); - assertThat(objectUnderTest.matches(NameKey.parse("test_project2"))).isTrue(); - assertThat(objectUnderTest.matches(NameKey.parse("test_project3"))).isFalse(); - } - - @Test - public void shouldExcludeByMultipleProjectsRegexPattern() { - when(projects.getPatterns()) - .thenReturn(Lists.newArrayList("^(?:(?!(test_project3|test_project4)).)*$")); - when(configuration.projects()).thenReturn(projects); - - objectUnderTest = new ProjectsFilter(configuration); - - assertThat(objectUnderTest.matches(NameKey.parse("test_project"))).isTrue(); - assertThat(objectUnderTest.matches(NameKey.parse("test_project2"))).isTrue(); - assertThat(objectUnderTest.matches(NameKey.parse("test_project3"))).isFalse(); - assertThat(objectUnderTest.matches(NameKey.parse("test_project4"))).isFalse(); - } - - @Test - public void shouldMatchWhenNoPatternProvided() { - when(projects.getPatterns()).thenReturn(Collections.emptyList()); - when(configuration.projects()).thenReturn(projects); - - objectUnderTest = new ProjectsFilter(configuration); - - assertThat(objectUnderTest.matches(NameKey.parse("test_project"))).isTrue(); - } - - @Test - public void shouldMatchProjectEvent() { - ProjectEvent event = mock(ProjectEvent.class); - when(event.getProjectNameKey()).thenReturn(NameKey.parse("test_project")); - when(projects.getPatterns()).thenReturn(Lists.newArrayList("test_project")); - when(configuration.projects()).thenReturn(projects); - - objectUnderTest = new ProjectsFilter(configuration); - - assertThat(objectUnderTest.matches(event)).isTrue(); - } - - @Test - public void shouldMatchRefUpdatedEvent() { - RefUpdatedEvent event = mock(RefUpdatedEvent.class); - when(event.getProjectNameKey()).thenReturn(NameKey.parse("test_project")); - when(projects.getPatterns()).thenReturn(Lists.newArrayList("test_project")); - when(configuration.projects()).thenReturn(projects); - - objectUnderTest = new ProjectsFilter(configuration); - - assertThat(objectUnderTest.matches(event)).isTrue(); - } - - @Test - public void shouldExcludedNonProjectEvents() { - Event event = mock(Event.class); - when(projects.getPatterns()).thenReturn(Lists.newArrayList("test_project)")); - when(configuration.projects()).thenReturn(projects); - - objectUnderTest = new ProjectsFilter(configuration); - - assertThat(objectUnderTest.matches(event)).isFalse(); - } - - @Test - public void shouldThrowExceptionWhenProjecNameIsNull() { - when(projects.getPatterns()).thenReturn(Collections.emptyList()); - when(configuration.projects()).thenReturn(projects); - - objectUnderTest = new ProjectsFilter(configuration); - - GerritJUnit.assertThrows( - IllegalArgumentException.class, () -> objectUnderTest.matches((NameKey) null)); - } - - @Test - public void shouldThrowExceptionWhenProjecNameIsEmpty() { - when(projects.getPatterns()).thenReturn(Collections.emptyList()); - when(configuration.projects()).thenReturn(projects); - - objectUnderTest = new ProjectsFilter(configuration); - - GerritJUnit.assertThrows( - IllegalArgumentException.class, () -> objectUnderTest.matches(NameKey.parse(""))); - } - - @Test - public void shouldThrowExceptionWhenEventIsNull() { - when(projects.getPatterns()).thenReturn(Collections.emptyList()); - when(configuration.projects()).thenReturn(projects); - - objectUnderTest = new ProjectsFilter(configuration); - - GerritJUnit.assertThrows( - IllegalArgumentException.class, () -> objectUnderTest.matches((Event) null)); - } -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/cache/ProjectListUpdateHandlerTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/cache/ProjectListUpdateHandlerTest.java index 2a25c37..4263ddb 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/cache/ProjectListUpdateHandlerTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/cache/ProjectListUpdateHandlerTest.java
@@ -23,11 +23,11 @@ import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; +import com.gerritforge.gerrit.globalrefdb.validation.ProjectsFilter; import com.google.common.util.concurrent.MoreExecutors; import com.google.gerrit.extensions.events.NewProjectCreatedListener; import com.google.gerrit.extensions.events.ProjectDeletedListener; import com.google.gerrit.extensions.registration.DynamicSet; -import com.googlesource.gerrit.plugins.multisite.ProjectsFilter; import com.googlesource.gerrit.plugins.multisite.cache.ProjectListUpdateHandler.ProjectListUpdateTask; import com.googlesource.gerrit.plugins.multisite.forwarder.Context; import com.googlesource.gerrit.plugins.multisite.forwarder.ProjectListUpdateForwarder;
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/consumer/SubscriberMetricsTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/consumer/SubscriberMetricsTest.java index 99148fa..8aa043d 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/consumer/SubscriberMetricsTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/consumer/SubscriberMetricsTest.java
@@ -18,6 +18,7 @@ import static org.mockito.Mockito.when; import com.gerritforge.gerrit.eventbroker.EventMessage; +import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDatabaseWrapper; import com.google.common.base.Suppliers; import com.google.gerrit.entities.Project; import com.google.gerrit.metrics.MetricMaker; @@ -25,7 +26,6 @@ import com.google.gerrit.server.events.RefUpdatedEvent; import com.google.gerrit.server.extensions.events.GitReferenceUpdated; import com.googlesource.gerrit.plugins.multisite.ProjectVersionLogger; -import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper; import com.googlesource.gerrit.plugins.multisite.validation.ProjectVersionRefUpdate; import java.util.Optional; import java.util.UUID;
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/event/CacheEvictionEventRouterTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/event/CacheEvictionEventRouterTest.java index a632b74..bf5c5d9 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/event/CacheEvictionEventRouterTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/event/CacheEvictionEventRouterTest.java
@@ -18,8 +18,8 @@ import com.google.gson.Gson; import com.googlesource.gerrit.plugins.multisite.forwarder.CacheEntry; +import com.googlesource.gerrit.plugins.multisite.forwarder.CacheKeyJsonParser; import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedCacheEvictionHandler; -import com.googlesource.gerrit.plugins.multisite.forwarder.GsonParser; import com.googlesource.gerrit.plugins.multisite.forwarder.events.CacheEvictionEvent; import com.googlesource.gerrit.plugins.multisite.forwarder.router.CacheEvictionEventRouter; import org.junit.Before; @@ -36,7 +36,7 @@ @Before public void setUp() { - router = new CacheEvictionEventRouter(cacheEvictionHandler, new GsonParser(new Gson())); + router = new CacheEvictionEventRouter(cacheEvictionHandler, new CacheKeyJsonParser(new Gson())); } @Test
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/event/EventHandlerTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/event/EventHandlerTest.java index bac0851..b9b416d 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/event/EventHandlerTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/event/EventHandlerTest.java
@@ -22,12 +22,12 @@ import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; +import com.gerritforge.gerrit.globalrefdb.validation.ProjectsFilter; import com.google.common.util.concurrent.MoreExecutors; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.server.events.Event; import com.google.gerrit.server.events.ProjectEvent; import com.google.gerrit.server.events.RefUpdatedEvent; -import com.googlesource.gerrit.plugins.multisite.ProjectsFilter; import com.googlesource.gerrit.plugins.multisite.event.EventHandler.EventTask; import com.googlesource.gerrit.plugins.multisite.forwarder.Context; import com.googlesource.gerrit.plugins.multisite.forwarder.StreamEventForwarder;
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/GsonParserTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/CacheKeyJsonParserTest.java similarity index 81% rename from src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/GsonParserTest.java rename to src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/CacheKeyJsonParserTest.java index 12bdb74..7efd4dd 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/GsonParserTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/CacheKeyJsonParserTest.java
@@ -18,16 +18,17 @@ import com.google.gerrit.entities.Account; import com.google.gerrit.entities.AccountGroup; +import com.google.gerrit.entities.Project; import com.google.gerrit.server.events.EventGsonProvider; import com.google.gson.Gson; import com.googlesource.gerrit.plugins.multisite.cache.Constants; import org.junit.Test; -public class GsonParserTest { +public class CacheKeyJsonParserTest { private static final Object EMPTY_JSON = "{}"; private final Gson gson = new EventGsonProvider().get(); - private final GsonParser gsonParser = new GsonParser(gson); + private final CacheKeyJsonParser gsonParser = new CacheKeyJsonParser(gson); @Test public void accountIDParse() { @@ -51,9 +52,16 @@ } @Test + public void projectNameKeyParse() { + Project.NameKey name = Project.nameKey("foo"); + String json = gson.toJson(name); + assertThat(name).isEqualTo(gsonParser.fromJson(Constants.PROJECTS, json)); + } + + @Test public void stringParse() { String key = "key"; - assertThat(key).isEqualTo(gsonParser.fromJson(Constants.PROJECTS, key)); + assertThat(key).isEqualTo(gsonParser.fromJson("any-cache-with-string-key", key)); } @Test
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedCacheEvictionHandlerIT.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedCacheEvictionHandlerIT.java new file mode 100644 index 0000000..fb2a50b --- /dev/null +++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedCacheEvictionHandlerIT.java
@@ -0,0 +1,132 @@ +// Copyright (C) 2021 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.forwarder; + +import static com.google.common.truth.Truth.assertThat; + +import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbConfiguration; +import com.google.common.cache.RemovalNotification; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.gerrit.acceptance.LightweightPluginDaemonTest; +import com.google.gerrit.acceptance.TestPlugin; +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.gerrit.extensions.registration.RegistrationHandle; +import com.google.gerrit.server.cache.CacheRemovalListener; +import com.google.gerrit.server.events.EventGson; +import com.google.gerrit.server.project.ProjectCacheImpl; +import com.google.gson.Gson; +import com.google.inject.AbstractModule; +import com.google.inject.Inject; +import com.googlesource.gerrit.plugins.multisite.cache.CacheModule; +import com.googlesource.gerrit.plugins.multisite.forwarder.events.CacheEvictionEvent; +import com.googlesource.gerrit.plugins.multisite.forwarder.router.CacheEvictionEventRouter; +import com.googlesource.gerrit.plugins.multisite.forwarder.router.RouterModule; +import com.googlesource.gerrit.plugins.multisite.index.IndexModule; +import java.time.Duration; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import org.eclipse.jgit.lib.Config; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +@TestPlugin( + name = "multi-site", + sysModule = + "com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedCacheEvictionHandlerIT$TestModule") +public class ForwardedCacheEvictionHandlerIT extends LightweightPluginDaemonTest { + private static final Duration CACHE_EVICTIONS_WAIT_TIMEOUT = Duration.ofMinutes(1); + + @SuppressWarnings("rawtypes") + @Inject + private DynamicSet<CacheRemovalListener> cacheRemovalListeners; + + @Inject private CacheEvictionEventRouter objectUnderTest; + @Inject @EventGson private Gson gson; + private CacheEvictionsTracker<?, ?> evictionsCacheTracker; + private RegistrationHandle cacheEvictionRegistrationHandle; + + public static class TestModule extends AbstractModule { + @Override + protected void configure() { + install(new ForwarderModule()); + install(new CacheModule()); + install(new RouterModule()); + install(new IndexModule()); + SharedRefDbConfiguration sharedRefDbConfig = + new SharedRefDbConfiguration(new Config(), "multi-site"); + bind(SharedRefDbConfiguration.class).toInstance(sharedRefDbConfig); + } + } + + public static class CacheEvictionsTracker<K, V> implements CacheRemovalListener<K, V> { + private final Map<String, Set<Object>> trackedEvictions; + private final CountDownLatch allExpectedEvictionsArrived; + + public CacheEvictionsTracker(int numExpectedEvictions) { + allExpectedEvictionsArrived = new CountDownLatch(numExpectedEvictions); + trackedEvictions = Maps.newHashMap(); + } + + public Set<Object> trackedEvictionsFor(String cacheName) { + return trackedEvictions.getOrDefault(cacheName, Collections.emptySet()); + } + + public void waitForExpectedEvictions() throws InterruptedException { + allExpectedEvictionsArrived.await( + CACHE_EVICTIONS_WAIT_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS); + } + + @Override + public void onRemoval( + String pluginName, String cacheName, RemovalNotification<K, V> notification) { + trackedEvictions.compute( + cacheName, + (k, v) -> { + if (v == null) { + return Sets.newHashSet(notification.getKey()); + } + v.add(notification.getKey()); + return v; + }); + allExpectedEvictionsArrived.countDown(); + } + } + + @Before + public void startTrackingCacheEvictions() { + evictionsCacheTracker = new CacheEvictionsTracker<>(1); + cacheEvictionRegistrationHandle = cacheRemovalListeners.add("gerrit", evictionsCacheTracker); + } + + @After + public void stopTrackingCacheEvictions() { + cacheEvictionRegistrationHandle.remove(); + } + + @Test + public void shouldEvictProjectCache() throws Exception { + objectUnderTest.route( + new CacheEvictionEvent(ProjectCacheImpl.CACHE_NAME, gson.toJson(project))); + evictionsCacheTracker.waitForExpectedEvictions(); + + assertThat(evictionsCacheTracker.trackedEvictionsFor(ProjectCacheImpl.CACHE_NAME)) + .contains(project); + } +}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/index/IndexEventHandlerTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/index/IndexEventHandlerTest.java index 022dec5..660a302 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/index/IndexEventHandlerTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/index/IndexEventHandlerTest.java
@@ -21,9 +21,9 @@ import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; +import com.gerritforge.gerrit.globalrefdb.validation.ProjectsFilter; import com.google.common.util.concurrent.MoreExecutors; import com.google.gerrit.extensions.registration.DynamicSet; -import com.googlesource.gerrit.plugins.multisite.ProjectsFilter; import com.googlesource.gerrit.plugins.multisite.forwarder.IndexEventForwarder; import com.googlesource.gerrit.plugins.multisite.forwarder.events.ProjectIndexEvent; import com.googlesource.gerrit.plugins.multisite.index.IndexEventHandler.IndexProjectTask;
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/BatchRefUpdateValidatorTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/BatchRefUpdateValidatorTest.java deleted file mode 100644 index 41bebc2..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/BatchRefUpdateValidatorTest.java +++ /dev/null
@@ -1,207 +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.eclipse.jgit.transport.ReceiveCommand.Type.UPDATE; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.gerrit.entities.Project; -import com.google.gerrit.metrics.DisabledMetricMaker; -import com.googlesource.gerrit.plugins.multisite.ProjectsFilter; -import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper; -import com.googlesource.gerrit.plugins.multisite.validation.RefUpdateValidator.OneParameterVoidFunction; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.DefaultSharedRefEnforcement; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.RefFixture; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedRefEnforcement; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.eclipse.jgit.internal.storage.file.RefDirectory; -import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; -import org.eclipse.jgit.junit.TestRepository; -import org.eclipse.jgit.lib.BatchRefUpdate; -import org.eclipse.jgit.lib.NullProgressMonitor; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.revwalk.RevWalk; -import org.eclipse.jgit.transport.ReceiveCommand; -import org.eclipse.jgit.transport.ReceiveCommand.Result; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class BatchRefUpdateValidatorTest extends LocalDiskRepositoryTestCase implements RefFixture { - @Rule public TestName nameRule = new TestName(); - - private Repository diskRepo; - private TestRepository<Repository> repo; - private RefDirectory refdir; - private RevCommit A; - private RevCommit B; - - @Mock SharedRefDatabaseWrapper sharedRefDatabase; - - @Mock SharedRefEnforcement tmpRefEnforcement; - - @Mock ProjectsFilter projectsFilter; - - @Mock OneParameterVoidFunction<List<ReceiveCommand>> rollbackFunction; - - @Before - public void setup() throws Exception { - super.setUp(); - when(projectsFilter.matches(anyString())).thenReturn(true); - gitRepoSetup(); - } - - private void gitRepoSetup() throws Exception { - diskRepo = createBareRepository(); - refdir = (RefDirectory) diskRepo.getRefDatabase(); - repo = new TestRepository<>(diskRepo); - A = repo.commit().create(); - B = repo.commit(repo.getRevWalk().parseCommit(A)); - } - - @Test - public void immutableChangeShouldNotBeWrittenIntoZk() throws Exception { - String AN_IMMUTABLE_REF = "refs/changes/01/1/1"; - - List<ReceiveCommand> cmds = Arrays.asList(new ReceiveCommand(A, B, AN_IMMUTABLE_REF, UPDATE)); - - BatchRefUpdate batchRefUpdate = newBatchUpdate(cmds); - BatchRefUpdateValidator BatchRefUpdateValidator = newDefaultValidator(A_TEST_PROJECT_NAME); - - BatchRefUpdateValidator.executeBatchUpdateWithValidation( - batchRefUpdate, () -> execute(batchRefUpdate), this::defaultRollback); - - verify(sharedRefDatabase, never()) - .compareAndPut(any(Project.NameKey.class), any(Ref.class), any(ObjectId.class)); - } - - @Test - public void compareAndPutShouldAlwaysIngoreAlwaysDraftCommentsEvenOutOfOrder() throws Exception { - String DRAFT_COMMENT = "refs/draft-comments/56/450756/1013728"; - List<ReceiveCommand> cmds = Arrays.asList(new ReceiveCommand(A, B, DRAFT_COMMENT, UPDATE)); - - BatchRefUpdate batchRefUpdate = newBatchUpdate(cmds); - BatchRefUpdateValidator BatchRefUpdateValidator = newDefaultValidator(A_TEST_PROJECT_NAME); - - BatchRefUpdateValidator.executeBatchUpdateWithValidation( - batchRefUpdate, () -> execute(batchRefUpdate), this::defaultRollback); - - verify(sharedRefDatabase, never()) - .compareAndPut(A_TEST_PROJECT_NAME_KEY, newRef(DRAFT_COMMENT, A.getId()), B.getId()); - } - - @Test - public void validationShouldFailWhenLocalRefDbIsOutOfSync() throws Exception { - String AN_OUT_OF_SYNC_REF = "refs/changes/01/1/1"; - BatchRefUpdate batchRefUpdate = - newBatchUpdate( - Collections.singletonList(new ReceiveCommand(A, B, AN_OUT_OF_SYNC_REF, UPDATE))); - BatchRefUpdateValidator batchRefUpdateValidator = - getRefValidatorForEnforcement(A_TEST_PROJECT_NAME, tmpRefEnforcement); - - doReturn(SharedRefEnforcement.EnforcePolicy.REQUIRED) - .when(batchRefUpdateValidator.refEnforcement) - .getPolicy(A_TEST_PROJECT_NAME, AN_OUT_OF_SYNC_REF); - lenient() - .doReturn(false) - .when(sharedRefDatabase) - .isUpToDate(A_TEST_PROJECT_NAME_KEY, newRef(AN_OUT_OF_SYNC_REF, AN_OBJECT_ID_1)); - - batchRefUpdateValidator.executeBatchUpdateWithValidation( - batchRefUpdate, () -> execute(batchRefUpdate), rollbackFunction); - - verify(rollbackFunction, never()).invoke(any()); - - final List<ReceiveCommand> commands = batchRefUpdate.getCommands(); - assertThat(commands.size()).isEqualTo(1); - commands.forEach( - (command) -> assertThat(command.getResult()).isEqualTo(ReceiveCommand.Result.LOCK_FAILURE)); - } - - @Test - public void shouldNotUpdateSharedRefDbWhenProjectIsLocal() throws Exception { - when(projectsFilter.matches(anyString())).thenReturn(false); - - String AN_OUT_OF_SYNC_REF = "refs/changes/01/1/1"; - BatchRefUpdate batchRefUpdate = - newBatchUpdate( - Collections.singletonList(new ReceiveCommand(A, B, AN_OUT_OF_SYNC_REF, UPDATE))); - BatchRefUpdateValidator batchRefUpdateValidator = - getRefValidatorForEnforcement(A_TEST_PROJECT_NAME, tmpRefEnforcement); - - batchRefUpdateValidator.executeBatchUpdateWithValidation( - batchRefUpdate, () -> execute(batchRefUpdate), this::defaultRollback); - - verify(sharedRefDatabase, never()) - .compareAndPut(any(Project.NameKey.class), any(Ref.class), any(ObjectId.class)); - } - - private BatchRefUpdateValidator newDefaultValidator(String projectName) { - return getRefValidatorForEnforcement(projectName, new DefaultSharedRefEnforcement()); - } - - private BatchRefUpdateValidator getRefValidatorForEnforcement( - String projectName, SharedRefEnforcement sharedRefEnforcement) { - return new BatchRefUpdateValidator( - sharedRefDatabase, - new ValidationMetrics(new DisabledMetricMaker()), - sharedRefEnforcement, - new DummyLockWrapper(), - projectsFilter, - projectName, - diskRepo.getRefDatabase()); - } - - private Void execute(BatchRefUpdate u) throws IOException { - try (RevWalk rw = new RevWalk(diskRepo)) { - u.execute(rw, NullProgressMonitor.INSTANCE); - } - return null; - } - - private BatchRefUpdate newBatchUpdate(List<ReceiveCommand> cmds) { - BatchRefUpdate u = refdir.newBatchUpdate(); - u.addCommand(cmds); - cmds.forEach(c -> c.setResult(Result.OK)); - return u; - } - - @Override - public String testBranch() { - return "branch_" + nameRule.getMethodName(); - } - - private void defaultRollback(List<ReceiveCommand> cmds) throws IOException { - // do nothing - } -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/DisabledSharedRefLogger.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/DisabledSharedRefLogger.java deleted file mode 100644 index 047a1c5..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/DisabledSharedRefLogger.java +++ /dev/null
@@ -1,39 +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.googlesource.gerrit.plugins.multisite.SharedRefLogger; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.Ref; -import org.junit.Ignore; - -@Ignore -public class DisabledSharedRefLogger implements SharedRefLogger { - - @Override - public void logRefUpdate(String project, Ref currRef, ObjectId newRefValue) {} - - @Override - public void logProjectDelete(String project) {} - - @Override - public void logLockAcquisition(String project, String refName) {} - - @Override - public void logLockRelease(String project, String refName) {} - - @Override - public <T> void logRefUpdate(String project, String refName, T currRef, T newRefValue) {} -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/DummyLockWrapper.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/DummyLockWrapper.java deleted file mode 100644 index 1ff0429..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/DummyLockWrapper.java +++ /dev/null
@@ -1,13 +0,0 @@ -package com.googlesource.gerrit.plugins.multisite.validation; - -import com.googlesource.gerrit.plugins.multisite.LockWrapper; -import org.junit.Ignore; - -@Ignore -public class DummyLockWrapper implements LockWrapper.Factory { - - @Override - public LockWrapper create(String project, String refName, AutoCloseable lock) { - return new LockWrapper(new DisabledSharedRefLogger(), project, refName, lock); - } -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/Log4jSharedRefLoggerTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/Log4jSharedRefLoggerTest.java deleted file mode 100644 index 3debdf4..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/Log4jSharedRefLoggerTest.java +++ /dev/null
@@ -1,167 +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 com.google.gerrit.acceptance.AbstractDaemonTest; -import com.google.gerrit.acceptance.PushOneCommit; -import com.google.gerrit.entities.RefNames; -import com.google.gerrit.json.OutputFormat; -import com.google.gerrit.server.config.SitePaths; -import com.google.gerrit.server.notedb.Sequences; -import com.google.gerrit.server.util.SystemLog; -import com.google.gson.Gson; -import com.googlesource.gerrit.plugins.multisite.Log4jSharedRefLogger; -import com.googlesource.gerrit.plugins.multisite.SharedRefLogEntry; -import java.io.IOException; -import java.io.StringWriter; -import java.nio.file.Files; -import java.nio.file.Path; -import org.apache.log4j.LogManager; -import org.apache.log4j.PatternLayout; -import org.apache.log4j.WriterAppender; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.Repository; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class Log4jSharedRefLoggerTest extends AbstractDaemonTest { - - private static final Gson gson = OutputFormat.JSON_COMPACT.newGson(); - private StringWriter logWriter; - private Log4jSharedRefLogger log4jSharedRefLogger; - - @Before - public void setUp() throws IOException { - this.logWriter = new StringWriter(); - this.log4jSharedRefLogger = newLog4jSharedRefLogger(); - } - - @Test - public void shouldLogProjectDeletion() { - log4jSharedRefLogger.logProjectDelete(project.get()); - - SharedRefLogEntry.DeleteProject gotLogEntry = - gson.fromJson(logWriter.toString(), SharedRefLogEntry.DeleteProject.class); - - assertThat(gotLogEntry.type).isEqualTo(SharedRefLogEntry.Type.DELETE_PROJECT); - assertThat(gotLogEntry.projectName).isEqualTo(project.get()); - } - - @Test - public void shouldLogUpdateRef() throws Exception { - final String refName = "refs/remotes/origin/master"; - Ref currRef = repo().exactRef(refName); - PushOneCommit.Result result = pushTo(refName); - ObjectId newRefValue = result.getCommit().toObjectId(); - - log4jSharedRefLogger.logRefUpdate(project.get(), currRef, newRefValue); - - SharedRefLogEntry.UpdateRef gotLogEntry = - gson.fromJson(logWriter.toString(), SharedRefLogEntry.UpdateRef.class); - - assertThat(gotLogEntry.type).isEqualTo(SharedRefLogEntry.Type.UPDATE_REF); - assertThat(gotLogEntry.projectName).isEqualTo(project.get()); - assertThat(gotLogEntry.refName).isEqualTo(refName); - assertThat(gotLogEntry.oldId).isEqualTo(currRef.getObjectId().getName()); - assertThat(gotLogEntry.newId).isEqualTo(newRefValue.getName()); - assertThat(gotLogEntry.comment).isNotNull(); - assertThat(gotLogEntry.committer).isNotNull(); - } - - @Test - public void shouldLogDeleteRef() throws Exception { - final String refName = "refs/remotes/origin/master"; - Ref currRef = repo().exactRef(refName); - - log4jSharedRefLogger.logRefUpdate(project.get(), currRef, ObjectId.zeroId()); - - SharedRefLogEntry.DeleteRef gotLogEntry = - gson.fromJson(logWriter.toString(), SharedRefLogEntry.DeleteRef.class); - - assertThat(gotLogEntry.type).isEqualTo(SharedRefLogEntry.Type.DELETE_REF); - assertThat(gotLogEntry.projectName).isEqualTo(project.get()); - assertThat(gotLogEntry.refName).isEqualTo(refName); - assertThat(gotLogEntry.oldId).isEqualTo(currRef.getObjectId().getName()); - } - - @Test - public void shouldLogBlobRefs() throws Exception { - Repository allUsersRepo = repoManager.openRepository(allUsers); - String blobRefName = RefNames.REFS_SEQUENCES + Sequences.NAME_ACCOUNTS; - Ref currRef = allUsersRepo.exactRef(blobRefName); - log4jSharedRefLogger.logRefUpdate(allUsers.get(), currRef, currRef.getObjectId()); - - SharedRefLogEntry.UpdateRef gotLogEntry = - gson.fromJson(logWriter.toString(), SharedRefLogEntry.UpdateRef.class); - - assertThat(gotLogEntry.type).isEqualTo(SharedRefLogEntry.Type.UPDATE_REF); - assertThat(gotLogEntry.projectName).isEqualTo(allUsers.get()); - assertThat(gotLogEntry.refName).isEqualTo(blobRefName); - assertThat(gotLogEntry.oldId).isEqualTo(currRef.getObjectId().getName()); - assertThat(gotLogEntry.newId).isEqualTo(currRef.getObjectId().getName()); - assertThat(gotLogEntry.comment).isNull(); - assertThat(gotLogEntry.committer).isNull(); - } - - @Test - public void shouldLogLockAcquisition() { - String refName = "refs/foo/bar"; - log4jSharedRefLogger.logLockAcquisition(project.get(), refName); - - SharedRefLogEntry.LockAcquire gotLogEntry = - gson.fromJson(logWriter.toString(), SharedRefLogEntry.LockAcquire.class); - - assertThat(gotLogEntry.type).isEqualTo(SharedRefLogEntry.Type.LOCK_ACQUIRE); - assertThat(gotLogEntry.projectName).isEqualTo(project.get()); - assertThat(gotLogEntry.refName).isEqualTo(refName); - } - - @Test - public void shouldLogLockRelease() { - String refName = "refs/foo/bar"; - log4jSharedRefLogger.logLockRelease(project.get(), refName); - - SharedRefLogEntry.LockAcquire gotLogEntry = - gson.fromJson(logWriter.toString(), SharedRefLogEntry.LockAcquire.class); - - assertThat(gotLogEntry.type).isEqualTo(SharedRefLogEntry.Type.LOCK_RELEASE); - assertThat(gotLogEntry.projectName).isEqualTo(project.get()); - assertThat(gotLogEntry.refName).isEqualTo(refName); - } - - private Log4jSharedRefLogger newLog4jSharedRefLogger() throws IOException { - final Log4jSharedRefLogger log4jSharedRefLogger = - new Log4jSharedRefLogger(new SystemLog(new SitePaths(newPath()), baseConfig), repoManager); - log4jSharedRefLogger.setLogger(logWriterLogger()); - return log4jSharedRefLogger; - } - - private Logger logWriterLogger() { - org.apache.log4j.Logger logger = LogManager.getLogger("logWriterLogger"); - logger.addAppender(new WriterAppender(new PatternLayout("%m"), logWriter)); - return LoggerFactory.getLogger("logWriterLogger"); - } - - private static Path newPath() throws IOException { - Path tmp = Files.createTempFile("gerrit_test_", "_site"); - Files.deleteIfExists(tmp); - return tmp; - } -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteBatchRefUpdateTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteBatchRefUpdateTest.java deleted file mode 100644 index 4aa4ba1..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteBatchRefUpdateTest.java +++ /dev/null
@@ -1,214 +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 java.util.Arrays.asList; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -import com.googlesource.gerrit.plugins.multisite.ProjectsFilter; -import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper; -import com.googlesource.gerrit.plugins.multisite.validation.RefUpdateValidator.OneParameterVoidFunction; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.DefaultSharedRefEnforcement; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.RefFixture; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import org.eclipse.jgit.lib.BatchRefUpdate; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectIdRef; -import org.eclipse.jgit.lib.ProgressMonitor; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.RefDatabase; -import org.eclipse.jgit.revwalk.RevWalk; -import org.eclipse.jgit.transport.ReceiveCommand; -import org.eclipse.jgit.transport.ReceiveCommand.Result; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatcher; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class MultiSiteBatchRefUpdateTest implements RefFixture { - - @Mock SharedRefDatabaseWrapper sharedRefDb; - @Mock BatchRefUpdate batchRefUpdate; - @Mock BatchRefUpdateValidator batchRefUpdateValidator; - @Mock RefDatabase refDatabase; - @Mock RevWalk revWalk; - @Mock ProgressMonitor progressMonitor; - @Mock ValidationMetrics validationMetrics; - @Mock ProjectsFilter projectsFilter; - @Mock OneParameterVoidFunction<List<ReceiveCommand>> rollbackFunction; - - private final Ref oldRef = - new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, A_TEST_REF_NAME, AN_OBJECT_ID_1); - private final Ref newRef = - new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, A_TEST_REF_NAME, AN_OBJECT_ID_2); - ReceiveCommand receiveCommandBeforeExecution = - createReceiveCommand( - oldRef.getObjectId(), newRef.getObjectId(), oldRef.getName(), Result.NOT_ATTEMPTED); - - ReceiveCommand successReceiveCommandAfterExecution = - createReceiveCommand(oldRef.getObjectId(), newRef.getObjectId(), oldRef.getName(), Result.OK); - - ReceiveCommand rejectReceiveCommandAfterExecution = - createReceiveCommand( - oldRef.getObjectId(), - newRef.getObjectId(), - oldRef.getName(), - Result.REJECTED_NONFASTFORWARD); - - private ReceiveCommand createReceiveCommand( - ObjectId oldRefObjectId, ObjectId newRefObjectId, String refName, Result result) { - ReceiveCommand receiveCommand = new ReceiveCommand(oldRefObjectId, newRefObjectId, refName); - receiveCommand.setResult(result); - return receiveCommand; - } - - private MultiSiteBatchRefUpdate multiSiteRefUpdate; - - @Rule public TestName nameRule = new TestName(); - - @Override - public String testBranch() { - return "branch_" + nameRule.getMethodName(); - } - - @Before - public void setup() { - when(projectsFilter.matches(anyString())).thenReturn(true); - } - - @SuppressWarnings("deprecation") - private void setMockRequiredReturnValues() throws IOException { - - doReturn(batchRefUpdate).when(refDatabase).newBatchUpdate(); - - when(batchRefUpdate.getCommands()) - .thenReturn(asList(receiveCommandBeforeExecution)) - .thenReturn(asList(successReceiveCommandAfterExecution)); - - doReturn(oldRef).when(refDatabase).getRef(A_TEST_REF_NAME); - doReturn(oldRef).when(refDatabase).exactRef(A_TEST_REF_NAME); - - multiSiteRefUpdate = getMultiSiteBatchRefUpdateWithDefaultPolicyEnforcement(); - - verifyZeroInteractions(validationMetrics); - } - - @Test - public void executeAndDelegateSuccessfullyWithNoExceptions() throws Exception { - setMockRequiredReturnValues(); - - // When compareAndPut against sharedDb succeeds - doReturn(true).when(sharedRefDb).isUpToDate(A_TEST_PROJECT_NAME_KEY, oldRef); - doReturn(true) - .when(sharedRefDb) - .compareAndPut(eq(A_TEST_PROJECT_NAME_KEY), refEquals(oldRef), eq(newRef.getObjectId())); - multiSiteRefUpdate.execute(revWalk, progressMonitor, Collections.emptyList()); - verify(sharedRefDb) - .compareAndPut(eq(A_TEST_PROJECT_NAME_KEY), refEquals(oldRef), eq(newRef.getObjectId())); - } - - private Ref refEquals(Ref oldRef) { - return argThat(new RefMatcher(oldRef)); - } - - @Test(expected = IOException.class) - public void executeAndFailsWithExceptions() throws IOException { - multiSiteRefUpdate = getMultiSiteBatchRefUpdateWithMockedValidator(); - doThrow(new IOException("IO Test Exception")) - .when(batchRefUpdateValidator) - .executeBatchUpdateWithValidation(any(), any(), any()); - - multiSiteRefUpdate.execute(revWalk, progressMonitor, Collections.emptyList()); - } - - @Test - public void executeSuccessfullyWithNoExceptionsWhenOutOfSync() throws IOException { - setMockRequiredReturnValues(); - doReturn(true).when(sharedRefDb).exists(A_TEST_PROJECT_NAME_KEY, A_TEST_REF_NAME); - doReturn(false).when(sharedRefDb).isUpToDate(A_TEST_PROJECT_NAME_KEY, oldRef); - - multiSiteRefUpdate.execute(revWalk, progressMonitor, Collections.emptyList()); - - verify(validationMetrics).incrementSplitBrainPrevention(); - } - - @Test - public void executeSuccessfullyWithNoExceptionsWhenEmptyList() throws IOException { - doReturn(batchRefUpdate).when(refDatabase).newBatchUpdate(); - doReturn(Collections.emptyList()).when(batchRefUpdate).getCommands(); - - multiSiteRefUpdate = getMultiSiteBatchRefUpdateWithDefaultPolicyEnforcement(); - - multiSiteRefUpdate.execute(revWalk, progressMonitor, Collections.emptyList()); - } - - private MultiSiteBatchRefUpdate getMultiSiteBatchRefUpdateWithDefaultPolicyEnforcement() { - BatchRefUpdateValidator.Factory batchRefValidatorFactory = - new BatchRefUpdateValidator.Factory() { - @Override - public BatchRefUpdateValidator create(String projectName, RefDatabase refDb) { - return new BatchRefUpdateValidator( - sharedRefDb, - validationMetrics, - new DefaultSharedRefEnforcement(), - new DummyLockWrapper(), - projectsFilter, - projectName, - refDb); - } - }; - return new MultiSiteBatchRefUpdate(batchRefValidatorFactory, A_TEST_PROJECT_NAME, refDatabase); - } - - private MultiSiteBatchRefUpdate getMultiSiteBatchRefUpdateWithMockedValidator() { - BatchRefUpdateValidator.Factory batchRefValidatorFactory = - new BatchRefUpdateValidator.Factory() { - @Override - public BatchRefUpdateValidator create(String projectName, RefDatabase refDb) { - return batchRefUpdateValidator; - } - }; - return new MultiSiteBatchRefUpdate(batchRefValidatorFactory, A_TEST_PROJECT_NAME, refDatabase); - } - - protected static class RefMatcher implements ArgumentMatcher<Ref> { - private Ref left; - - public RefMatcher(Ref ref) { - this.left = ref; - } - - @Override - public boolean matches(Ref right) { - return left.getName().equals(right.getName()) - && left.getObjectId().equals(right.getObjectId()); - } - } -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteGitRepositoryManagerTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteGitRepositoryManagerTest.java deleted file mode 100644 index 491ced4..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteGitRepositoryManagerTest.java +++ /dev/null
@@ -1,82 +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 org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; - -import com.google.gerrit.server.git.LocalDiskRepositoryManager; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.RefFixture; -import org.eclipse.jgit.lib.Repository; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class MultiSiteGitRepositoryManagerTest implements RefFixture { - - @Mock LocalDiskRepositoryManager localDiskRepositoryManagerMock; - - @Mock MultiSiteRepository.Factory multiSiteRepositoryFactoryMock; - - @Mock Repository repositoryMock; - - @Mock MultiSiteRepository multiSiteRepositoryMock; - - MultiSiteGitRepositoryManager msRepoMgr; - - @Override - public String testBranch() { - return "foo"; - } - - @Before - public void setUp() throws Exception { - doReturn(multiSiteRepositoryMock) - .when(multiSiteRepositoryFactoryMock) - .create(A_TEST_PROJECT_NAME, repositoryMock); - msRepoMgr = - new MultiSiteGitRepositoryManager( - multiSiteRepositoryFactoryMock, localDiskRepositoryManagerMock); - } - - @Test - public void openRepositoryShouldCreateMultiSiteRepositoryWrapper() throws Exception { - doReturn(repositoryMock) - .when(localDiskRepositoryManagerMock) - .openRepository(A_TEST_PROJECT_NAME_KEY); - - msRepoMgr.openRepository(A_TEST_PROJECT_NAME_KEY); - - verifyThatMultiSiteRepositoryWrapperHasBeenCreated(); - } - - @Test - public void createRepositoryShouldCreateMultiSiteRepositoryWrapper() throws Exception { - doReturn(repositoryMock) - .when(localDiskRepositoryManagerMock) - .createRepository(A_TEST_PROJECT_NAME_KEY); - - msRepoMgr.createRepository(A_TEST_PROJECT_NAME_KEY); - - verifyThatMultiSiteRepositoryWrapperHasBeenCreated(); - } - - private void verifyThatMultiSiteRepositoryWrapperHasBeenCreated() { - verify(multiSiteRepositoryFactoryMock).create(A_TEST_PROJECT_NAME, repositoryMock); - } -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRefDatabaseTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRefDatabaseTest.java deleted file mode 100644 index 41b83e5..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRefDatabaseTest.java +++ /dev/null
@@ -1,59 +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 org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; - -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.RefFixture; -import org.eclipse.jgit.lib.RefDatabase; -import org.eclipse.jgit.lib.RefUpdate; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class MultiSiteRefDatabaseTest implements RefFixture { - - @Rule public TestName nameRule = new TestName(); - - @Mock MultiSiteRefUpdate.Factory refUpdateFactoryMock; - @Mock MultiSiteBatchRefUpdate.Factory refBatchUpdateFactoryMock; - - @Mock RefDatabase refDatabaseMock; - - @Mock RefUpdate refUpdateMock; - - @Override - public String testBranch() { - return "branch_" + nameRule.getMethodName(); - } - - @Test - public void newUpdateShouldCreateMultiSiteRefUpdate() throws Exception { - String refName = aBranchRef(); - MultiSiteRefDatabase multiSiteRefDb = - new MultiSiteRefDatabase( - refUpdateFactoryMock, refBatchUpdateFactoryMock, A_TEST_PROJECT_NAME, refDatabaseMock); - doReturn(refUpdateMock).when(refDatabaseMock).newUpdate(refName, false); - - multiSiteRefDb.newUpdate(refName, false); - - verify(refUpdateFactoryMock).create(A_TEST_PROJECT_NAME, refUpdateMock, refDatabaseMock); - } -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRefUpdateTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRefUpdateTest.java deleted file mode 100644 index 029a4c6..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRefUpdateTest.java +++ /dev/null
@@ -1,203 +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 com.google.gerrit.testing.GerritJUnit.assertThrows; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -import com.googlesource.gerrit.plugins.multisite.ProjectsFilter; -import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper; -import com.googlesource.gerrit.plugins.multisite.validation.RefUpdateValidator.Factory; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.DefaultSharedRefEnforcement; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.RefFixture; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.RefUpdateStub; -import java.io.IOException; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectIdRef; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.RefDatabase; -import org.eclipse.jgit.lib.RefUpdate; -import org.eclipse.jgit.lib.RefUpdate.Result; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -@Ignore // The focus of this test suite is unclear and all tests are failing when the code is -// working, and the other way around -public class MultiSiteRefUpdateTest implements RefFixture { - - @Mock SharedRefDatabaseWrapper sharedRefDb; - @Mock ValidationMetrics validationMetrics; - @Mock RefDatabase refDb; - @Mock ProjectsFilter projectsFilter; - - private final Ref oldRef = - new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, A_TEST_REF_NAME, AN_OBJECT_ID_1); - private final Ref newRef = - new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, A_TEST_REF_NAME, AN_OBJECT_ID_2); - - @Rule public TestName nameRule = new TestName(); - - @Override - public String testBranch() { - return "branch_" + nameRule.getMethodName(); - } - - @Before - public void setup() { - when(projectsFilter.matches(anyString())).thenReturn(true); - } - - @Test - public void newUpdateShouldValidateAndSucceed() throws Exception { - - doReturn(true).when(sharedRefDb).isUpToDate(A_TEST_PROJECT_NAME_KEY, oldRef); - doReturn(true) - .when(sharedRefDb) - .compareAndPut(A_TEST_PROJECT_NAME_KEY, oldRef, newRef.getObjectId()); - - RefUpdate refUpdate = RefUpdateStub.forSuccessfulUpdate(oldRef, newRef.getObjectId()); - - MultiSiteRefUpdate multiSiteRefUpdate = - getMultiSiteRefUpdateWithDefaultPolicyEnforcement(refUpdate); - - assertThat(multiSiteRefUpdate.update()).isEqualTo(Result.FAST_FORWARD); - verifyZeroInteractions(validationMetrics); - } - - @Test(expected = Exception.class) - public void newUpdateShouldValidateAndFailWithIOException() throws Exception { - - doReturn(false).when(sharedRefDb).isUpToDate(A_TEST_PROJECT_NAME_KEY, oldRef); - - RefUpdate refUpdate = RefUpdateStub.forSuccessfulUpdate(oldRef, newRef.getObjectId()); - - MultiSiteRefUpdate multiSiteRefUpdate = - getMultiSiteRefUpdateWithDefaultPolicyEnforcement(refUpdate); - multiSiteRefUpdate.update(); - } - - @Test - public void newUpdateShouldIncreaseRefUpdateFailureCountWhenFailing() { - - doReturn(false).when(sharedRefDb).isUpToDate(A_TEST_PROJECT_NAME_KEY, oldRef); - - RefUpdate refUpdate = RefUpdateStub.forSuccessfulUpdate(oldRef, newRef.getObjectId()); - - MultiSiteRefUpdate multiSiteRefUpdate = - getMultiSiteRefUpdateWithDefaultPolicyEnforcement(refUpdate); - - assertThrows(IOException.class, () -> multiSiteRefUpdate.update()); - verify(validationMetrics).incrementSplitBrainPrevention(); - } - - @Test - public void newUpdateShouldNotIncreaseSplitBrainPreventedCounterIfFailingSharedDbPostUpdate() { - - doReturn(true).when(sharedRefDb).isUpToDate(A_TEST_PROJECT_NAME_KEY, oldRef); - doReturn(false) - .when(sharedRefDb) - .compareAndPut(A_TEST_PROJECT_NAME_KEY, oldRef, newRef.getObjectId()); - - RefUpdate refUpdate = RefUpdateStub.forSuccessfulUpdate(oldRef, newRef.getObjectId()); - - MultiSiteRefUpdate multiSiteRefUpdate = - getMultiSiteRefUpdateWithDefaultPolicyEnforcement(refUpdate); - - assertThrows(IOException.class, () -> multiSiteRefUpdate.update()); - verify(validationMetrics, never()).incrementSplitBrainPrevention(); - } - - @Test - public void newUpdateShouldtIncreaseSplitBrainCounterIfFailingSharedDbPostUpdate() { - - doReturn(true).when(sharedRefDb).isUpToDate(A_TEST_PROJECT_NAME_KEY, oldRef); - doReturn(false) - .when(sharedRefDb) - .compareAndPut(A_TEST_PROJECT_NAME_KEY, oldRef, newRef.getObjectId()); - - RefUpdate refUpdate = RefUpdateStub.forSuccessfulUpdate(oldRef, newRef.getObjectId()); - - MultiSiteRefUpdate multiSiteRefUpdate = - getMultiSiteRefUpdateWithDefaultPolicyEnforcement(refUpdate); - - assertThrows(IOException.class, () -> multiSiteRefUpdate.update()); - verify(validationMetrics).incrementSplitBrain(); - } - - @Test - public void deleteShouldValidateAndSucceed() throws IOException { - doReturn(true).when(sharedRefDb).isUpToDate(A_TEST_PROJECT_NAME_KEY, oldRef); - - doReturn(true) - .when(sharedRefDb) - .compareAndPut(A_TEST_PROJECT_NAME_KEY, oldRef, ObjectId.zeroId()); - - RefUpdate refUpdate = RefUpdateStub.forSuccessfulDelete(oldRef); - - MultiSiteRefUpdate multiSiteRefUpdate = - getMultiSiteRefUpdateWithDefaultPolicyEnforcement(refUpdate); - - assertThat(multiSiteRefUpdate.delete()).isEqualTo(Result.FORCED); - verifyZeroInteractions(validationMetrics); - } - - @Test - public void deleteShouldIncreaseRefUpdateFailureCountWhenFailing() { - - doReturn(false).when(sharedRefDb).isUpToDate(A_TEST_PROJECT_NAME_KEY, oldRef); - - RefUpdate refUpdate = RefUpdateStub.forSuccessfulDelete(oldRef); - - MultiSiteRefUpdate multiSiteRefUpdate = - getMultiSiteRefUpdateWithDefaultPolicyEnforcement(refUpdate); - - assertThrows(IOException.class, () -> multiSiteRefUpdate.delete()); - verify(validationMetrics).incrementSplitBrainPrevention(); - } - - private MultiSiteRefUpdate getMultiSiteRefUpdateWithDefaultPolicyEnforcement( - RefUpdate refUpdate) { - Factory batchRefValidatorFactory = - new Factory() { - @Override - public RefUpdateValidator create(String projectName, RefDatabase refDb) { - RefUpdateValidator RefUpdateValidator = - new RefUpdateValidator( - sharedRefDb, - validationMetrics, - new DefaultSharedRefEnforcement(), - new DummyLockWrapper(), - projectsFilter, - projectName, - refDb); - return RefUpdateValidator; - } - }; - return new MultiSiteRefUpdate(batchRefValidatorFactory, A_TEST_PROJECT_NAME, refUpdate, refDb); - } -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRepositoryTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRepositoryTest.java deleted file mode 100644 index 15c596f..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteRepositoryTest.java +++ /dev/null
@@ -1,93 +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.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; - -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.RefFixture; -import java.io.IOException; -import org.eclipse.jgit.lib.RefDatabase; -import org.eclipse.jgit.lib.RefUpdate.Result; -import org.eclipse.jgit.lib.Repository; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class MultiSiteRepositoryTest implements RefFixture { - - @Mock MultiSiteRefDatabase.Factory multiSiteRefDbFactory; - @Mock MultiSiteRefDatabase multiSiteRefDb; - @Mock RefDatabase genericRefDb; - - @Mock MultiSiteRefUpdate multiSiteRefUpdate; - - @Mock Repository repository; - - private final String PROJECT_NAME = "ProjectName"; - private final String REFS_HEADS_MASTER = "refs/heads/master"; - - @Override - public String testBranch() { - return null; - } - - private void setMockitoCommon() { - doReturn(genericRefDb).when(repository).getRefDatabase(); - doReturn(multiSiteRefDb).when(multiSiteRefDbFactory).create(PROJECT_NAME, genericRefDb); - } - - @Test - public void shouldInvokeMultiSiteRefDbFactoryCreate() { - setMockitoCommon(); - try (MultiSiteRepository multiSiteRepository = - new MultiSiteRepository(multiSiteRefDbFactory, PROJECT_NAME, repository)) { - - multiSiteRepository.getRefDatabase(); - verify(multiSiteRefDbFactory).create(PROJECT_NAME, genericRefDb); - } - } - - @Test - public void shouldInvokeNewUpdateInMultiSiteRefDatabase() throws IOException { - setMockitoCommon(); - try (MultiSiteRepository multiSiteRepository = - new MultiSiteRepository(multiSiteRefDbFactory, PROJECT_NAME, repository)) { - multiSiteRepository.getRefDatabase().newUpdate(REFS_HEADS_MASTER, false); - - verify(multiSiteRefDb).newUpdate(REFS_HEADS_MASTER, false); - } - } - - @Test - public void shouldInvokeUpdateInMultiSiteRefUpdate() throws IOException { - setMockitoCommon(); - doReturn(Result.NEW).when(multiSiteRefUpdate).update(); - doReturn(multiSiteRefUpdate).when(multiSiteRefDb).newUpdate(REFS_HEADS_MASTER, false); - - try (MultiSiteRepository multiSiteRepository = - new MultiSiteRepository(multiSiteRefDbFactory, PROJECT_NAME, repository)) { - - Result updateResult = - multiSiteRepository.getRefDatabase().newUpdate(REFS_HEADS_MASTER, false).update(); - - verify(multiSiteRefUpdate).update(); - assertThat(updateResult).isEqualTo(Result.NEW); - } - } -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectDeletedSharedDbCleanupTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectDeletedSharedDbCleanupTest.java deleted file mode 100644 index ba381a4..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectDeletedSharedDbCleanupTest.java +++ /dev/null
@@ -1,45 +0,0 @@ -package com.googlesource.gerrit.plugins.multisite.validation; - -import com.google.gerrit.extensions.api.changes.NotifyHandling; -import com.google.gerrit.extensions.events.ProjectDeletedListener; -import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.RefFixture; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class ProjectDeletedSharedDbCleanupTest implements RefFixture { - @Rule public TestName nameRule = new TestName(); - - @Mock ValidationMetrics mockValidationMetrics; - @Mock SharedRefDatabaseWrapper sharedRefDatabase; - - @Test - public void aDeleteProjectEventShouldCleanupProjectFromZk() throws Exception { - String projectName = A_TEST_PROJECT_NAME; - ProjectDeletedSharedDbCleanup projectDeletedSharedDbCleanup = - new ProjectDeletedSharedDbCleanup(sharedRefDatabase, mockValidationMetrics); - - ProjectDeletedListener.Event event = - new ProjectDeletedListener.Event() { - @Override - public String getProjectName() { - return projectName; - } - - @Override - public NotifyHandling getNotify() { - return NotifyHandling.NONE; - } - }; - - projectDeletedSharedDbCleanup.onProjectDeleted(event); - - Mockito.verify(sharedRefDatabase, Mockito.times(1)).remove(A_TEST_PROJECT_NAME_KEY); - } -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectVersionRefUpdateTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectVersionRefUpdateTest.java index d437a73..917c6bf 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectVersionRefUpdateTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectVersionRefUpdateTest.java
@@ -24,6 +24,8 @@ import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; +import com.gerritforge.gerrit.globalrefdb.validation.ProjectsFilter; +import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDatabaseWrapper; import com.google.gerrit.entities.Project; import com.google.gerrit.entities.RefNames; import com.google.gerrit.server.events.Event; @@ -34,14 +36,13 @@ import com.google.gerrit.testing.InMemoryTestEnvironment; import com.google.inject.Inject; import com.googlesource.gerrit.plugins.multisite.ProjectVersionLogger; -import com.googlesource.gerrit.plugins.multisite.ProjectsFilter; -import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper; import com.googlesource.gerrit.plugins.multisite.forwarder.Context; import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.RefFixture; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.util.Optional; -import org.apache.commons.io.IOUtils; +import org.eclipse.jgit.errors.LargeObjectException; import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.lib.ObjectId; @@ -121,8 +122,7 @@ assertThat(ref).isNotNull(); ObjectLoader loader = repo.getRepository().open(ref.getObjectId()); - long storedVersion = - Long.parseLong(IOUtils.toString(loader.openStream(), StandardCharsets.UTF_8.name())); + long storedVersion = readLongObject(loader); assertThat(storedVersion).isGreaterThan((long) masterCommit.getCommitTime()); verify(verLogger).log(A_TEST_PROJECT_NAME_KEY, storedVersion, 0); @@ -167,8 +167,7 @@ assertThat(ref).isNotNull(); ObjectLoader loader = repo.getRepository().open(ref.getObjectId()); - long storedVersion = - Long.parseLong(IOUtils.toString(loader.openStream(), StandardCharsets.UTF_8.name())); + long storedVersion = readLongObject(loader); assertThat(storedVersion).isGreaterThan((long) masterPlusOneCommit.getCommitTime()); verify(verLogger).log(A_TEST_PROJECT_NAME_KEY, storedVersion, 0); @@ -208,8 +207,7 @@ assertThat(ref).isNotNull(); ObjectLoader loader = repo.getRepository().open(ref.getObjectId()); - long storedVersion = - Long.parseLong(IOUtils.toString(loader.openStream(), StandardCharsets.UTF_8.name())); + long storedVersion = readLongObject(loader); assertThat(storedVersion).isGreaterThan((long) masterCommit.getCommitTime()); verify(verLogger).log(A_TEST_PROJECT_NAME_KEY, storedVersion, 0); @@ -226,6 +224,12 @@ producerShouldNotUpdateProjectVersionUponMagicRefUpdatedEvent(RefNames.REFS_STARRED_CHANGES); } + private long readLongObject(ObjectLoader loader) + throws LargeObjectException, UnsupportedEncodingException { + String boutString = new String(loader.getBytes(), StandardCharsets.UTF_8.name()); + return Long.parseLong(boutString); + } + private void producerShouldNotUpdateProjectVersionUponMagicRefUpdatedEvent(String magicRefPrefix) throws Exception { String magicRefName = magicRefPrefix + "/foo";
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/RefUpdateValidatorTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/RefUpdateValidatorTest.java deleted file mode 100644 index b9b07bd..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/RefUpdateValidatorTest.java +++ /dev/null
@@ -1,244 +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.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.gerrit.entities.Project; -import com.googlesource.gerrit.plugins.multisite.ProjectsFilter; -import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper; -import com.googlesource.gerrit.plugins.multisite.SharedRefLogger; -import com.googlesource.gerrit.plugins.multisite.validation.RefUpdateValidator.OneParameterFunction; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.DefaultSharedRefEnforcement; -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.RefFixture; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.RefDatabase; -import org.eclipse.jgit.lib.RefUpdate; -import org.eclipse.jgit.lib.RefUpdate.Result; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class RefUpdateValidatorTest implements RefFixture { - private static final DefaultSharedRefEnforcement defaultRefEnforcement = - new DefaultSharedRefEnforcement(); - - @Mock SharedRefDatabaseWrapper sharedRefDb; - - @Mock SharedRefLogger sharedRefLogger; - - @Mock RefDatabase localRefDb; - - @Mock ValidationMetrics validationMetrics; - - @Mock RefUpdate refUpdate; - - @Mock ProjectsFilter projectsFilter; - - @Mock OneParameterFunction<ObjectId, Result> rollbackFunction; - - String refName; - Ref oldUpdateRef; - Ref newUpdateRef; - Ref localRef; - - RefUpdateValidator refUpdateValidator; - - @Before - public void setupMocks() throws Exception { - refName = aBranchRef(); - oldUpdateRef = newRef(refName, AN_OBJECT_ID_1); - newUpdateRef = newRef(refName, AN_OBJECT_ID_2); - localRef = newRef(refName, AN_OBJECT_ID_3); - - doReturn(localRef).when(localRefDb).findRef(refName); - doReturn(localRef).when(localRefDb).exactRef(refName); - doReturn(newUpdateRef.getObjectId()).when(refUpdate).getNewObjectId(); - doReturn(refName).when(refUpdate).getName(); - lenient().doReturn(oldUpdateRef.getObjectId()).when(refUpdate).getOldObjectId(); - doReturn(Result.FAST_FORWARD).when(rollbackFunction).invoke(any()); - - doReturn(true).when(projectsFilter).matches(anyString()); - - refUpdateValidator = newRefUpdateValidator(sharedRefDb); - } - - @Test - public void validationShouldSucceedWhenSharedRefDbIsNoop() throws Exception { - SharedRefDatabaseWrapper noopSharedRefDbWrapper = new SharedRefDatabaseWrapper(sharedRefLogger); - - Result result = - newRefUpdateValidator(noopSharedRefDbWrapper) - .executeRefUpdate(refUpdate, () -> RefUpdate.Result.NEW, this::defaultRollback); - assertThat(result).isEqualTo(RefUpdate.Result.NEW); - } - - @Test - public void validationShouldSucceedWhenLocalRefDbIsUpToDate() throws Exception { - lenient() - .doReturn(false) - .when(sharedRefDb) - .isUpToDate(any(Project.NameKey.class), any(Ref.class)); - doReturn(true).when(sharedRefDb).isUpToDate(A_TEST_PROJECT_NAME_KEY, localRef); - lenient() - .doReturn(false) - .when(sharedRefDb) - .compareAndPut(any(Project.NameKey.class), any(Ref.class), any(ObjectId.class)); - doReturn(true) - .when(sharedRefDb) - .compareAndPut(A_TEST_PROJECT_NAME_KEY, localRef, newUpdateRef.getObjectId()); - - Result result = - refUpdateValidator.executeRefUpdate( - refUpdate, () -> RefUpdate.Result.NEW, this::defaultRollback); - - assertThat(result).isEqualTo(RefUpdate.Result.NEW); - } - - @Test - public void sharedRefDbShouldBeUpdatedWithRefDeleted() throws Exception { - doReturn(ObjectId.zeroId()).when(refUpdate).getNewObjectId(); - doReturn(true).when(sharedRefDb).isUpToDate(any(Project.NameKey.class), any(Ref.class)); - lenient() - .doReturn(false) - .when(sharedRefDb) - .compareAndPut(any(Project.NameKey.class), any(Ref.class), any(ObjectId.class)); - doReturn(true) - .when(sharedRefDb) - .compareAndPut(A_TEST_PROJECT_NAME_KEY, localRef, ObjectId.zeroId()); - doReturn(localRef).doReturn(null).when(localRefDb).findRef(refName); - - Result result = - refUpdateValidator.executeRefUpdate( - refUpdate, () -> RefUpdate.Result.FORCED, this::defaultRollback); - - assertThat(result).isEqualTo(RefUpdate.Result.FORCED); - } - - @Test - public void sharedRefDbShouldBeUpdatedWithNewRefCreated() throws Exception { - Ref localNullRef = nullRef(refName); - - doReturn(true).when(sharedRefDb).isUpToDate(any(Project.NameKey.class), any(Ref.class)); - lenient() - .doReturn(false) - .when(sharedRefDb) - .compareAndPut(any(Project.NameKey.class), any(Ref.class), any(ObjectId.class)); - doReturn(true) - .when(sharedRefDb) - .compareAndPut(A_TEST_PROJECT_NAME_KEY, localNullRef, newUpdateRef.getObjectId()); - doReturn(localNullRef).doReturn(newUpdateRef).when(localRefDb).findRef(refName); - - Result result = - refUpdateValidator.executeRefUpdate( - refUpdate, () -> RefUpdate.Result.NEW, this::defaultRollback); - - assertThat(result).isEqualTo(RefUpdate.Result.NEW); - } - - @Test - public void validationShouldFailWhenLocalRefDbIsOutOfSync() throws Exception { - lenient() - .doReturn(true) - .when(sharedRefDb) - .isUpToDate(any(Project.NameKey.class), any(Ref.class)); - doReturn(true).when(sharedRefDb).exists(A_TEST_PROJECT_NAME_KEY, refName); - doReturn(false).when(sharedRefDb).isUpToDate(A_TEST_PROJECT_NAME_KEY, localRef); - - Result result = - refUpdateValidator.executeRefUpdate( - refUpdate, () -> RefUpdate.Result.NEW, this::defaultRollback); - - assertThat(result).isEqualTo(Result.LOCK_FAILURE); - } - - @Test - public void shouldRollbackWhenLocalRefDbIsUpToDateButFinalCompareAndPutIsFailing() - throws Exception { - lenient() - .doReturn(false) - .when(sharedRefDb) - .isUpToDate(any(Project.NameKey.class), any(Ref.class)); - doReturn(true).when(sharedRefDb).isUpToDate(A_TEST_PROJECT_NAME_KEY, localRef); - lenient() - .doReturn(true) - .when(sharedRefDb) - .compareAndPut(any(Project.NameKey.class), any(Ref.class), any(ObjectId.class)); - doReturn(false) - .when(sharedRefDb) - .compareAndPut(A_TEST_PROJECT_NAME_KEY, localRef, newUpdateRef.getObjectId()); - - Result result = - refUpdateValidator.executeRefUpdate(refUpdate, () -> Result.NEW, rollbackFunction); - - verify(rollbackFunction, times(1)).invoke(any()); - assertThat(result).isEqualTo(Result.LOCK_FAILURE); - } - - @Test - public void shouldNotUpdateSharedRefDbWhenFinalCompareAndPutIsFailing() throws Exception { - lenient() - .doReturn(false) - .when(sharedRefDb) - .isUpToDate(any(Project.NameKey.class), any(Ref.class)); - doReturn(true).when(sharedRefDb).isUpToDate(A_TEST_PROJECT_NAME_KEY, localRef); - - Result result = - refUpdateValidator.executeRefUpdate( - refUpdate, () -> Result.LOCK_FAILURE, this::defaultRollback); - - verify(sharedRefDb, never()) - .compareAndPut(any(Project.NameKey.class), any(Ref.class), any(ObjectId.class)); - assertThat(result).isEqualTo(RefUpdate.Result.LOCK_FAILURE); - } - - @Test - public void shouldNotUpdateSharedRefDbWhenProjectIsLocal() throws Exception { - when(projectsFilter.matches(anyString())).thenReturn(false); - - refUpdateValidator.executeRefUpdate( - refUpdate, () -> RefUpdate.Result.NEW, this::defaultRollback); - - verify(sharedRefDb, never()) - .compareAndPut(any(Project.NameKey.class), any(Ref.class), any(ObjectId.class)); - } - - private RefUpdateValidator newRefUpdateValidator(SharedRefDatabaseWrapper refDbWrapper) { - return new RefUpdateValidator( - refDbWrapper, - validationMetrics, - defaultRefEnforcement, - new DummyLockWrapper(), - projectsFilter, - A_TEST_PROJECT_NAME, - localRefDb); - } - - private Result defaultRollback(ObjectId objectId) { - return Result.NO_CHANGE; - } -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/CustomSharedRefEnforcementByProjectTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/CustomSharedRefEnforcementByProjectTest.java deleted file mode 100644 index f3008a2..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/CustomSharedRefEnforcementByProjectTest.java +++ /dev/null
@@ -1,151 +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.dfsrefdb; - -import static com.google.common.truth.Truth.assertThat; - -import com.googlesource.gerrit.plugins.multisite.Configuration; -import com.googlesource.gerrit.plugins.multisite.Configuration.SharedRefDatabase; -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 sharedRefDbConfig = new Config(); - sharedRefDbConfig.setStringList( - SharedRefDatabase.SECTION, - SharedRefDatabase.SUBSECTION_ENFORCEMENT_RULES, - EnforcePolicy.IGNORED.name(), - Arrays.asList( - "ProjectOne", - "ProjectTwo:refs/heads/master/test", - "ProjectTwo:refs/heads/master/test2")); - - refEnforcement = newCustomRefEnforcement(sharedRefDbConfig); - } - - @Test - public void projectOneShouldReturnDesiredForAllRefs() { - Ref aRef = newRef("refs/heads/master/2", AN_OBJECT_ID_1); - assertThat(refEnforcement.getPolicy("ProjectOne", aRef.getName())) - .isEqualTo(EnforcePolicy.IGNORED); - } - - @Test - public void projectOneEnforcementShouldAlwaysPrevail() { - Ref aRef = newRef("refs/heads/master/test", AN_OBJECT_ID_1); - assertThat(refEnforcement.getPolicy("ProjectOne", aRef.getName())) - .isEqualTo(EnforcePolicy.IGNORED); - } - - @Test - public void aNonListedProjectShouldRequireRefForMasterTest() { - Ref aRef = newRef("refs/heads/master/test", AN_OBJECT_ID_1); - assertThat(refEnforcement.getPolicy("NonListedProject", aRef.getName())) - .isEqualTo(EnforcePolicy.REQUIRED); - } - - @Test - public void projectTwoSpecificRefShouldReturnIgnoredPolicy() { - 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.IGNORED); - assertThat(refEnforcement.getPolicy("ProjectTwo", refTwo.getName())) - .isEqualTo(EnforcePolicy.IGNORED); - } - - @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 getProjectPolicyForProjectOneShouldReturnIgnored() { - assertThat(refEnforcement.getPolicy("ProjectOne")).isEqualTo(EnforcePolicy.IGNORED); - } - - @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.IGNORED, ":refs/heads/master"); - - assertThat(customEnforcement.getPolicy("NonListedProject")).isEqualTo(EnforcePolicy.REQUIRED); - } - - @Test - public void getANonListedProjectWhenOnlyOneProjectIsListedShouldReturnRequired() { - SharedRefEnforcement customEnforcement = - newCustomRefEnforcementWithValue(EnforcePolicy.IGNORED, "AProject:"); - assertThat(customEnforcement.getPolicy("NonListedProject", "refs/heads/master")) - .isEqualTo(EnforcePolicy.REQUIRED); - } - - private SharedRefEnforcement newCustomRefEnforcementWithValue( - EnforcePolicy policy, String... projectAndRefs) { - Config sharedRefDbConfiguration = new Config(); - sharedRefDbConfiguration.setStringList( - SharedRefDatabase.SECTION, - SharedRefDatabase.SUBSECTION_ENFORCEMENT_RULES, - policy.name(), - Arrays.asList(projectAndRefs)); - return newCustomRefEnforcement(sharedRefDbConfiguration); - } - - private SharedRefEnforcement newCustomRefEnforcement(Config sharedRefDbConfig) { - return new CustomSharedRefEnforcementByProject( - new Configuration(sharedRefDbConfig, new Config())); - } - - @Override - public String testBranch() { - return "fooBranch"; - } -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/DefaultSharedRefEnforcementTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/DefaultSharedRefEnforcementTest.java deleted file mode 100644 index 2964e15..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/DefaultSharedRefEnforcementTest.java +++ /dev/null
@@ -1,80 +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.dfsrefdb; - -import static com.google.common.truth.Truth.assertThat; - -import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.SharedRefEnforcement.EnforcePolicy; -import org.eclipse.jgit.lib.Ref; -import org.junit.Test; - -public class DefaultSharedRefEnforcementTest implements RefFixture { - - SharedRefEnforcement refEnforcement = new DefaultSharedRefEnforcement(); - - @Test - public void anImmutableChangeShouldBeIgnored() { - Ref immutableChangeRef = newRef(A_REF_NAME_OF_A_PATCHSET, AN_OBJECT_ID_1); - assertThat(refEnforcement.getPolicy(A_TEST_PROJECT_NAME, immutableChangeRef.getName())) - .isEqualTo(EnforcePolicy.IGNORED); - } - - @Test - public void aChangeMetaShouldNotBeIgnored() { - Ref immutableChangeRef = newRef("refs/changes/01/1/meta", AN_OBJECT_ID_1); - assertThat(refEnforcement.getPolicy(A_TEST_PROJECT_NAME, immutableChangeRef.getName())) - .isEqualTo(EnforcePolicy.REQUIRED); - } - - @Test - public void aCacheAutomergeShouldBeIgnored() { - Ref immutableChangeRef = newRef("refs/cache-automerge/01/1/1000000", AN_OBJECT_ID_1); - assertThat(refEnforcement.getPolicy(A_TEST_PROJECT_NAME, immutableChangeRef.getName())) - .isEqualTo(EnforcePolicy.IGNORED); - } - - @Test - public void aDraftCommentsShouldBeIgnored() { - Ref immutableChangeRef = newRef("refs/draft-comments/01/1/1000000", AN_OBJECT_ID_1); - assertThat(refEnforcement.getPolicy(A_TEST_PROJECT_NAME, immutableChangeRef.getName())) - .isEqualTo(EnforcePolicy.IGNORED); - } - - @Test - public void regularRefHeadsMasterShouldNotBeIgnored() { - Ref immutableChangeRef = newRef("refs/heads/master", AN_OBJECT_ID_1); - assertThat(refEnforcement.getPolicy(A_TEST_PROJECT_NAME, immutableChangeRef.getName())) - .isEqualTo(EnforcePolicy.REQUIRED); - } - - @Test - public void regularCommitShouldNotBeIgnored() { - Ref immutableChangeRef = newRef("refs/heads/stable-2.16", AN_OBJECT_ID_1); - assertThat(refEnforcement.getPolicy(A_TEST_PROJECT_NAME, immutableChangeRef.getName())) - .isEqualTo(EnforcePolicy.REQUIRED); - } - - @Test - public void allUsersExternalIdsRefShouldBeRequired() { - Ref refOne = newRef("refs/meta/external-ids", AN_OBJECT_ID_1); - assertThat(refEnforcement.getPolicy("All-Users", refOne.getName())) - .isEqualTo(EnforcePolicy.REQUIRED); - } - - @Override - public String testBranch() { - return "fooBranch"; - } -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/MultisiteReplicationPushFilterTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/MultisiteReplicationPushFilterTest.java deleted file mode 100644 index f2b57a1..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/MultisiteReplicationPushFilterTest.java +++ /dev/null
@@ -1,207 +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.dfsrefdb; - -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import com.gerritforge.gerrit.globalrefdb.GlobalRefDatabase; -import com.gerritforge.gerrit.globalrefdb.GlobalRefDbLockException; -import com.gerritforge.gerrit.globalrefdb.GlobalRefDbSystemError; -import com.google.gerrit.entities.Project; -import com.google.gerrit.extensions.registration.DynamicItem; -import com.google.gerrit.testing.InMemoryRepositoryManager; -import com.google.gerrit.testing.InMemoryTestEnvironment; -import com.google.inject.Inject; -import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper; -import com.googlesource.gerrit.plugins.multisite.validation.DisabledSharedRefLogger; -import com.googlesource.gerrit.plugins.multisite.validation.MultisiteReplicationPushFilter; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; -import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; -import org.eclipse.jgit.junit.TestRepository; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectIdRef; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.transport.RemoteRefUpdate; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class MultisiteReplicationPushFilterTest extends LocalDiskRepositoryTestCase - implements RefFixture { - - @Rule public InMemoryTestEnvironment testEnvironment = new InMemoryTestEnvironment(); - - @Mock SharedRefDatabaseWrapper sharedRefDatabaseMock; - - @Inject private InMemoryRepositoryManager gitRepositoryManager; - - String project = A_TEST_PROJECT_NAME; - Project.NameKey projectName = A_TEST_PROJECT_NAME_KEY; - - private TestRepository<InMemoryRepository> repo; - - @Before - public void setupTestRepo() throws Exception { - InMemoryRepository inMemoryRepo = - gitRepositoryManager.createRepository(A_TEST_PROJECT_NAME_KEY); - repo = new TestRepository<>(inMemoryRepo); - } - - @Test - public void shouldReturnAllRefUpdatesWhenAllUpToDate() throws Exception { - List<RemoteRefUpdate> refUpdates = - Arrays.asList(refUpdate("refs/heads/foo"), refUpdate("refs/heads/bar")); - doReturn(true).when(sharedRefDatabaseMock).isUpToDate(eq(projectName), any()); - - MultisiteReplicationPushFilter pushFilter = - new MultisiteReplicationPushFilter(sharedRefDatabaseMock, gitRepositoryManager); - List<RemoteRefUpdate> filteredRefUpdates = pushFilter.filter(project, refUpdates); - - assertThat(filteredRefUpdates).containsExactlyElementsIn(refUpdates); - } - - @Test - public void shouldFilterOutOneOutdatedRef() throws Exception { - RemoteRefUpdate refUpToDate = refUpdate("refs/heads/uptodate"); - RemoteRefUpdate outdatedRef = refUpdate("refs/heads/outdated"); - List<RemoteRefUpdate> refUpdates = Arrays.asList(refUpToDate, outdatedRef); - SharedRefDatabaseWrapper sharedRefDatabase = newSharedRefDatabase(outdatedRef.getSrcRef()); - - MultisiteReplicationPushFilter pushFilter = - new MultisiteReplicationPushFilter(sharedRefDatabase, gitRepositoryManager); - List<RemoteRefUpdate> filteredRefUpdates = pushFilter.filter(project, refUpdates); - - assertThat(filteredRefUpdates).containsExactly(refUpToDate); - } - - @Test - public void shouldLoadLocalVersionAndNotFilter() throws Exception { - RemoteRefUpdate temporaryOutdated = refUpdate("refs/heads/temporaryOutdated"); - List<RemoteRefUpdate> refUpdates = Collections.singletonList(temporaryOutdated); - doReturn(false).doReturn(true).when(sharedRefDatabaseMock).isUpToDate(eq(projectName), any()); - - MultisiteReplicationPushFilter pushFilter = - new MultisiteReplicationPushFilter(sharedRefDatabaseMock, gitRepositoryManager); - List<RemoteRefUpdate> filteredRefUpdates = pushFilter.filter(project, refUpdates); - - assertThat(filteredRefUpdates).containsExactly(temporaryOutdated); - verify(sharedRefDatabaseMock, times(2)).isUpToDate(any(), any()); - } - - @Test - public void shouldLoadLocalVersionAndFilter() throws Exception { - RemoteRefUpdate temporaryOutdated = refUpdate("refs/heads/temporaryOutdated"); - repo.branch("refs/heads/temporaryOutdated").commit().create(); - List<RemoteRefUpdate> refUpdates = Collections.singletonList(temporaryOutdated); - doReturn(false).doReturn(false).when(sharedRefDatabaseMock).isUpToDate(eq(projectName), any()); - - MultisiteReplicationPushFilter pushFilter = - new MultisiteReplicationPushFilter(sharedRefDatabaseMock, gitRepositoryManager); - List<RemoteRefUpdate> filteredRefUpdates = pushFilter.filter(project, refUpdates); - - assertThat(filteredRefUpdates).isEmpty(); - verify(sharedRefDatabaseMock, times(2)).isUpToDate(any(), any()); - } - - @Test - public void shouldFilterOutAllOutdatedChangesRef() throws Exception { - RemoteRefUpdate refUpToDate = refUpdate("refs/heads/uptodate"); - RemoteRefUpdate refChangeUpToDate = refUpdate("refs/changes/25/1225/2"); - RemoteRefUpdate changeMetaRef = refUpdate("refs/changes/12/4512/meta"); - RemoteRefUpdate changeRef = refUpdate("refs/changes/12/4512/1"); - List<RemoteRefUpdate> refUpdates = - Arrays.asList(refUpToDate, refChangeUpToDate, changeMetaRef, changeRef); - SharedRefDatabaseWrapper sharedRefDatabase = newSharedRefDatabase(changeMetaRef.getSrcRef()); - - MultisiteReplicationPushFilter pushFilter = - new MultisiteReplicationPushFilter(sharedRefDatabase, gitRepositoryManager); - List<RemoteRefUpdate> filteredRefUpdates = pushFilter.filter(project, refUpdates); - - assertThat(filteredRefUpdates).containsExactly(refUpToDate, refChangeUpToDate); - } - - private SharedRefDatabaseWrapper newSharedRefDatabase(String... rejectedRefs) { - Set<String> rejectedSet = new HashSet<>(); - rejectedSet.addAll(Arrays.asList(rejectedRefs)); - - GlobalRefDatabase sharedRefDatabase = - new GlobalRefDatabase() { - - @Override - public boolean isUpToDate(Project.NameKey project, Ref ref) - throws GlobalRefDbLockException { - return !rejectedSet.contains(ref.getName()); - } - - @Override - public boolean exists(Project.NameKey project, String refName) { - return true; - } - - @Override - public boolean compareAndPut(Project.NameKey project, Ref currRef, ObjectId newRefValue) - throws GlobalRefDbSystemError { - return false; - } - - @Override - public <T> boolean compareAndPut( - Project.NameKey project, String refName, T currValue, T newValue) - throws GlobalRefDbSystemError { - return false; - } - - @Override - public AutoCloseable lockRef(Project.NameKey project, String refName) - throws GlobalRefDbLockException { - return null; - } - - @Override - public void remove(Project.NameKey project) throws GlobalRefDbSystemError {} - - @Override - public <T> Optional<T> get(Project.NameKey project, String refName, Class<T> clazz) - throws GlobalRefDbSystemError { - return Optional.empty(); - } - }; - return new SharedRefDatabaseWrapper( - DynamicItem.itemOf(GlobalRefDatabase.class, sharedRefDatabase), - new DisabledSharedRefLogger()); - } - - private RemoteRefUpdate refUpdate(String refName) throws Exception { - ObjectId srcObjId = ObjectId.fromString("0000000000000000000000000000000000000001"); - Ref srcRef = new ObjectIdRef.Unpeeled(Ref.Storage.NEW, refName, srcObjId); - repo.branch(refName).commit().create(); - return new RemoteRefUpdate(null, srcRef, "origin", false, "origin", srcObjId); - } -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/NoopSharedRefDatabaseTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/NoopSharedRefDatabaseTest.java deleted file mode 100644 index c63530a..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/NoopSharedRefDatabaseTest.java +++ /dev/null
@@ -1,28 +0,0 @@ -package com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb; - -import static com.google.common.truth.Truth.assertThat; - -import org.eclipse.jgit.lib.Ref; -import org.junit.Test; - -public class NoopSharedRefDatabaseTest implements RefFixture { - - private Ref sampleRef = newRef(A_TEST_REF_NAME, AN_OBJECT_ID_1); - private NoopSharedRefDatabase objectUnderTest = new NoopSharedRefDatabase(); - - @Test - public void isUpToDateShouldAlwaysReturnTrue() { - assertThat(objectUnderTest.isUpToDate(A_TEST_PROJECT_NAME_KEY, sampleRef)).isTrue(); - } - - @Test - public void compareAndPutShouldAlwaysReturnTrue() { - assertThat(objectUnderTest.compareAndPut(A_TEST_PROJECT_NAME_KEY, sampleRef, AN_OBJECT_ID_2)) - .isTrue(); - } - - @Test - public void existsShouldAlwaysReturnFalse() { - assertThat(objectUnderTest.exists(A_TEST_PROJECT_NAME_KEY, A_TEST_REF_NAME)).isFalse(); - } -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/RefSharedDatabaseTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/RefSharedDatabaseTest.java deleted file mode 100644 index c9eeaa8..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/RefSharedDatabaseTest.java +++ /dev/null
@@ -1,47 +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.dfsrefdb; - -import static com.google.common.truth.Truth.assertThat; - -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectIdRef; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.Ref.Storage; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -public class RefSharedDatabaseTest implements RefFixture { - @Rule public TestName nameRule = new TestName(); - - @Override - public String testBranch() { - return "branch_" + nameRule.getMethodName(); - } - - @Test - public void shouldCreateANewRef() { - - ObjectId objectId = AN_OBJECT_ID_1; - String refName = aBranchRef(); - - Ref aNewRef = new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, refName, objectId); - - assertThat(aNewRef.getName()).isEqualTo(refName); - assertThat(aNewRef.getObjectId()).isEqualTo(objectId); - assertThat(aNewRef.getStorage()).isEqualTo(Storage.NETWORK); - } -}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/RefUpdateStub.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/RefUpdateStub.java deleted file mode 100644 index 7c1d7b4..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/RefUpdateStub.java +++ /dev/null
@@ -1,114 +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.dfsrefdb; - -import java.io.IOException; -import org.apache.commons.lang.NotImplementedException; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.RefDatabase; -import org.eclipse.jgit.lib.RefUpdate; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.revwalk.RevWalk; -import org.junit.Ignore; - -@Ignore -public class RefUpdateStub extends RefUpdate { - - public static RefUpdate forSuccessfulCreate(Ref newRef) { - return new RefUpdateStub(Result.NEW, null, newRef, newRef.getObjectId()); - } - - public static RefUpdate forSuccessfulUpdate(Ref oldRef, ObjectId newObjectId) { - return new RefUpdateStub(Result.FAST_FORWARD, null, oldRef, newObjectId); - } - - public static RefUpdate forSuccessfulDelete(Ref oldRef) { - return new RefUpdateStub(null, Result.FORCED, oldRef, ObjectId.zeroId()); - } - - private final Result updateResult; - private final Result deleteResult; - - public RefUpdateStub(Result updateResult, Result deleteResult, Ref oldRef, ObjectId newObjectId) { - super(oldRef); - this.setNewObjectId(newObjectId); - this.updateResult = updateResult; - this.deleteResult = deleteResult; - } - - @Override - protected RefDatabase getRefDatabase() { - throw new NotImplementedException("Method not implemented yet, not assumed you needed it!!"); - } - - @Override - protected Repository getRepository() { - throw new NotImplementedException("Method not implemented yet, not assumed you needed it!!"); - } - - @Override - protected boolean tryLock(boolean deref) throws IOException { - throw new NotImplementedException("Method not implemented yet, not assumed you needed it!!"); - } - - @Override - protected void unlock() { - throw new NotImplementedException("Method not implemented yet, not assumed you needed it!!"); - } - - @Override - protected Result doUpdate(Result desiredResult) throws IOException { - throw new NotImplementedException("Method not implemented, shouldn't be called!!"); - } - - @Override - protected Result doDelete(Result desiredResult) throws IOException { - throw new NotImplementedException("Method not implemented, shouldn't be called!!"); - } - - @Override - protected Result doLink(String target) throws IOException { - throw new NotImplementedException("Method not implemented yet, not assumed you needed it!!"); - } - - @Override - public Result update() throws IOException { - if (updateResult != null) return updateResult; - - throw new NotImplementedException("Not assumed you needed to stub this call!!"); - } - - @Override - public Result update(RevWalk walk) throws IOException { - if (updateResult != null) return updateResult; - - throw new NotImplementedException("Not assumed you needed to stub this call!!"); - } - - @Override - public Result delete() throws IOException { - if (deleteResult != null) return deleteResult; - - throw new NotImplementedException("Not assumed you needed to stub this call!!"); - } - - @Override - public Result delete(RevWalk walk) throws IOException { - if (deleteResult != null) return deleteResult; - - throw new NotImplementedException("Not assumed you needed to stub this call!!"); - } -}