Introduce local (docker) setup for e2e tests

This is the initial commit that creates local (docker based) setup
to run e2e tests. Tests are integrated with bazel and are part of
test target:

  bazel test //plugins/multi-site/...

One can also start them independently by calling:

  e2e-tests/test.sh

For now it set all multi-site plugins as mandatory in Gerrit
config and checks if everything gets started.

See `e2e-tests/README.md` for requirements and details about the
test setup and call:

  e2e-tests/test.sh --help

for all configuration options.

Bug: Issue 14475
Change-Id: Ibb123a5e100d8abedb9035ba02ecb95acfab5ef8
diff --git a/BUILD b/BUILD
index 0284dc6..39e1bc3 100644
--- a/BUILD
+++ b/BUILD
@@ -53,3 +53,41 @@
         "//plugins/replication",
     ],
 )
+
+filegroup(
+    name = "e2e_multi_site_test_dir",
+    srcs = [
+        "e2e-tests",
+    ],
+)
+
+filegroup(
+    name = "e2e_multi_site_setup_local_env_dir",
+    srcs = [
+        "setup_local_env",
+    ],
+)
+
+sh_test(
+    name = "e2e_multi_site_tests",
+    srcs = [
+        "e2e-tests/test.sh",
+    ],
+    data = [
+        "//plugins/multi-site",
+        "//plugins/multi-site:e2e_multi_site_test_dir",
+        "//plugins/multi-site:e2e_multi_site_setup_local_env_dir",
+        "external_plugin_deps.bzl",
+    ] + glob(["setup_local_env/**/*"]) + glob(["e2e-tests/**/*"]),
+    args = [
+        "--multisite-lib-file $(location //plugins/multi-site)",
+        "--healthcheck-interval 5s",
+        "--healthcheck-timeout 10s",
+        "--healthcheck-retries 30",
+        "--location '$(location //plugins/multi-site:e2e_multi_site_test_dir)'",
+        "--local-env '$(location //plugins/multi-site:e2e_multi_site_setup_local_env_dir)'",
+    ],
+    tags = [
+        "e2e-multi-site",
+    ],
+)
diff --git a/e2e-tests/README.md b/e2e-tests/README.md
new file mode 100644
index 0000000..f15c8eb
--- /dev/null
+++ b/e2e-tests/README.md
@@ -0,0 +1,51 @@
+# Local e2e tests
+
+This script configures an environment to simulate a Gerrit Multi-Site setup so
+that automated e2e tests (so far only startup and check if all necessary plugins
+were loaded) could be performed by CI.
+
+The environment is composed by:
+* 2 gerrit instances deployed by default in `/tmp/[random]`
+* 1 zookeeper node
+* 1 broker node (kafka - implemented, kinesis or gcloud-pubsub - to be implemented
+  if/when needed)
+
+## Requirements
+
+- java
+- docker and docker-compose
+- wget
+- envsubst
+- git
+
+## Execution
+
+Tests defined in `scenarios.sh` are called automatically when plugin tests are called:
+
+```bash
+bazel test //plugins/multi-site/...
+```
+
+But one can also start them independently with:
+
+```bash
+./test.sh
+```
+
+Upon start docker logs are tailed to file in deployment dir. They will be printed to
+the console (together with `docker-compose.yaml` used to start the setup) upon tests
+failure (`test.sh` will exit with `1` in such case). No ports/volumes are exposed and
+multiple test instances can be started in the same CI node (internal docker network is
+used to perform tests).
+
+# Assumptions
+
+When called in the independent mode it is assumed that `multi-site` jar is available
+under in-tree gerrit repository that is related to the `multi-site` repo (e.g.
+`../../../bazel-bin/plugins/[multi-site/multi-site|replication/replication].jar`).
+It can be further customised with `--multisite-lib-file` execution option. Full list
+of options can be obtained with:
+
+```bash
+./test.sh --help
+```
diff --git a/e2e-tests/docker-compose-kafka.yaml b/e2e-tests/docker-compose-kafka.yaml
new file mode 100644
index 0000000..da39cca
--- /dev/null
+++ b/e2e-tests/docker-compose-kafka.yaml
@@ -0,0 +1,17 @@
+version: '3'
+services:
+  kafka:
+    image: wurstmeister/kafka:2.12-2.1.0
+    depends_on:
+      - zookeeper
+    environment:
+      KAFKA_ADVERTISED_HOST_NAME: kafka
+      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
+
+  gerrit1:
+    depends_on:
+      - kafka
+
+  gerrit2:
+    depends_on:
+      - kafka
\ No newline at end of file
diff --git a/e2e-tests/docker-compose.yaml b/e2e-tests/docker-compose.yaml
new file mode 100644
index 0000000..3abb757
--- /dev/null
+++ b/e2e-tests/docker-compose.yaml
@@ -0,0 +1,36 @@
+version: '3'
+services:
+  zookeeper:
+    image: wurstmeister/zookeeper:latest
+
+  gerrit1:
+    image: gerritcodereview/gerrit:${GERRIT_IMAGE}
+    depends_on:
+      - zookeeper
+    volumes:
+      - "gerrit1_git:/var/gerrit/git"
+      - "gerrit2_git:/var/gerrit/git-instance2"
+    healthcheck:
+      test: ["CMD", "curl", "-f", "http://localhost:8080/config/server/healthcheck~status"]
+      start_period: ${GERRIT_HEALTHCHECK_START_PERIOD:-60s}
+      interval: ${GERRIT_HEALTHCHECK_INTERVAL-5s}
+      timeout: ${GERRIT_HEALTHCHECK_TIMEOUT-5s}
+      retries: ${GERRIT_HEALTHCHECK_RETRIES-5}
+
+  gerrit2:
+    image: gerritcodereview/gerrit:${GERRIT_IMAGE}
+    depends_on:
+      - zookeeper
+    volumes:
+      - "gerrit2_git:/var/gerrit/git"
+      - "gerrit1_git:/var/gerrit/git-instance1"
+    healthcheck:
+      test: ["CMD", "curl", "-f", "http://localhost:8080/config/server/healthcheck~status"]
+      start_period: ${GERRIT_HEALTHCHECK_START_PERIOD:-60s}
+      interval: ${GERRIT_HEALTHCHECK_INTERVAL:-5s}
+      timeout: ${GERRIT_HEALTHCHECK_TIMEOUT:-5s}
+      retries: ${GERRIT_HEALTHCHECK_RETRIES:-5}
+
+volumes:
+  gerrit1_git:
+  gerrit2_git:
\ No newline at end of file
diff --git a/e2e-tests/docker-tester.yaml b/e2e-tests/docker-tester.yaml
new file mode 100644
index 0000000..4b8bf58
--- /dev/null
+++ b/e2e-tests/docker-tester.yaml
@@ -0,0 +1,11 @@
+version: '3'
+services:
+  tester:
+    image: gerritcodereview/gerrit:${GERRIT_IMAGE}
+    user: root
+    depends_on:
+      gerrit1:
+        condition: service_healthy
+      gerrit2:
+        condition: service_healthy
+    entrypoint: ["/var/gerrit/scenarios.sh"]
diff --git a/e2e-tests/scenarios.sh b/e2e-tests/scenarios.sh
new file mode 100755
index 0000000..c61c635
--- /dev/null
+++ b/e2e-tests/scenarios.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+# 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.
+
+SSH_OPTS='-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
+
+function call_gerrit {
+  SERVER=$1
+  shift
+  su gerrit -c "ssh -p 29418 ${SSH_OPTS} admin@${SERVER} gerrit \"$@\""
+}
+
+
+chown -R gerrit:gerrit /var/gerrit/.ssh
+
+call_gerrit gerrit1 version || exit 1;
+call_gerrit gerrit2 version || exit 1;
+echo "All tests were finished successfully."
diff --git a/e2e-tests/test.sh b/e2e-tests/test.sh
new file mode 100755
index 0000000..49615e7
--- /dev/null
+++ b/e2e-tests/test.sh
@@ -0,0 +1,366 @@
+#!/bin/bash
+
+# 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.
+
+LOCATION="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+LOCAL_ENV="$( cd "${LOCATION}/../setup_local_env" >/dev/null 2>&1 && pwd )"
+GERRIT_BRANCH=stable-3.3
+GERRIT_CI=https://gerrit-ci.gerritforge.com/view/Plugins-$GERRIT_BRANCH/job
+LAST_BUILD=lastSuccessfulBuild/artifact/bazel-bin/plugins
+DEF_MULTISITE_LOCATION=${LOCATION}/../../../bazel-bin/plugins/multi-site/multi-site.jar
+DEF_GERRIT_IMAGE=3.3.6-centos8
+DEF_GERRIT_HEALTHCHECK_START_PERIOD=60s
+DEF_GERRIT_HEALTHCHECK_INTERVAL=5s
+DEF_GERRIT_HEALTHCHECK_TIMEOUT=5s
+DEF_GERRIT_HEALTHCHECK_RETRIES=5
+
+function check_application_requirements {
+  type java >/dev/null 2>&1 || { echo >&2 "Require java but it's not installed. Aborting."; exit 1; }
+  type docker >/dev/null 2>&1 || { echo >&2 "Require docker but it's not installed. Aborting."; exit 1; }
+  type docker-compose >/dev/null 2>&1 || { echo >&2 "Require docker-compose but it's not installed. Aborting."; exit 1; }
+  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; }
+  type git >/dev/null 2>&1 || { echo >&2 "Require git but it's not installed. Aborting."; exit 1; }
+}
+
+function setup_zookeeper_config {
+  SOURCE_ZOOKEEPER_CONFIG=${LOCAL_ENV}/configs/zookeeper-refdb.config
+  DESTINATION_ZOOKEEPER_CONFIG=$1
+
+  export ZK_HOST=zookeeper
+  export ZK_PORT=2181
+
+  echo "Replacing variables for file ${SOURCE_ZOOKEEPER_CONFIG} and copying to ${DESTINATION_ZOOKEEPER_CONFIG}"
+  cat $SOURCE_ZOOKEEPER_CONFIG | envsubst | sed 's/#{name}#/${name}/g' > $DESTINATION_ZOOKEEPER_CONFIG
+}
+
+function setup_replication_config {
+  SOURCE_REPLICATION_CONFIG=${LOCAL_ENV}/configs/replication.config
+  DESTINATION_REPLICATION_CONFIG=$1
+
+  export REPLICATION_URL="url = $2"
+  export REPLICATION_DELAY_SEC=1
+
+  echo "Replacing variables for file ${SOURCE_REPLICATION_CONFIG} and copying to ${DESTINATION_REPLICATION_CONFIG}"
+  cat $SOURCE_REPLICATION_CONFIG | envsubst | sed 's/#{name}#/${name}/g' > $DESTINATION_REPLICATION_CONFIG
+}
+
+function setup_gerrit_config {
+  SOURCE_RGERRIT_CONFIG=${LOCAL_ENV}/configs/gerrit.config
+  DESTINATION_GERRIT_CONFIG=$1
+
+  export BROKER_HOST=$2
+  export BROKER_PORT=$3
+  export GROUP_ID=$4
+  export SSH_ADVERTISED_PORT=$5
+  export LOCATION_TEST_SITE=/var/gerrit
+  export REMOTE_DEBUG_PORT=5005
+  export GERRIT_SSHD_PORT=29418
+  export HTTP_PROTOCOL=http
+  export GERRIT_HTTPD_PORT=8080
+
+  echo "Replacing variables for file ${SOURCE_RGERRIT_CONFIG} and copying to ${DESTINATION_GERRIT_CONFIG}"
+  cat $SOURCE_RGERRIT_CONFIG | envsubst | sed 's/#{name}#/${name}/g' > $DESTINATION_GERRIT_CONFIG
+
+  # set plugins for multi-site as mandatory so that gerrit will not start if they are not loaded
+  declare -a MANDATORY_PLUGINS=(${BROKER_PLUGIN} multi-site replication websession-broker zookeeper-refdb)
+  for plugin in "${MANDATORY_PLUGINS[@]}"
+  do
+    git config --file $DESTINATION_GERRIT_CONFIG --add plugins.mandatory "${plugin}"
+  done
+}
+
+function cleanup_tests_hook {
+  echo "Shutting down the setup"
+  docker-compose -f ${DEPLOYMENT_LOCATION}/docker-compose.yaml down -v
+  echo "Removing setup dir"
+  rm -rf ${DEPLOYMENT_LOCATION}
+}
+
+function check_result {
+  local CONTAINER_ID=$1
+  local OLD_RES=$2
+
+  if [ $OLD_RES -ne 0 ]; then
+    return $OLD_RES;
+  fi
+
+  local RES_VAL=$(docker inspect -f '{{ .State.ExitCode }}' "${CONTAINER_ID}")
+  # first check if RES_VAL (output) is a number
+  if [[ -z "${RES_VAL##*[!0-9]*}" || $RES_VAL -ne 0 ]]; then
+    echo "Tests failed. Here is [docker-compose.yaml] content:"
+    cat "${DEPLOYMENT_LOCATION}/docker-compose.yaml"
+
+    echo "Docker logs:"
+    cat "${DEPLOYMENT_LOCATION}/site.log"
+    return 1
+  fi
+
+  return 0
+}
+
+# Check application requirements
+check_application_requirements
+
+while [ $# -ne 0 ]
+do
+case "$1" in
+  "--help" )
+    echo "Usage: sh $0 [--option $value]"
+    echo
+    echo "[--gerrit-image]                Gerrit docker image to be used for testing; defaults to [${DEF_GERRIT_IMAGE}]"
+    echo "[--multisite-lib-file]          Location to lib multi-site.jar file; defaults to [${DEF_MULTISITE_LOCATION}]"
+    echo "[--broker-type]                 events broker type; 'kafka', 'kinesis' or 'gcloud-pubsub'. Default 'kafka' TODO: so far only 'kafka'"
+    echo "[--start-period]                Gerrit start period timeout (until it gets healthy); defaults to [${DEF_GERRIT_HEALTHCHECK_START_PERIOD}]"
+    echo "[--healthcheck-interval]        Every interval Gerrit health check is performed; defaults to [${DEF_GERRIT_HEALTHCHECK_INTERVAL}]"
+    echo "[--healthcheck-timeout]         If a single run of the check takes longer than timeout it is considered a failure; defaults to [${DEF_GERRIT_HEALTHCHECK_TIMEOUT}]"
+    echo "[--healthcheck-retries]         How many consequtive times health check can fail to consider Gerrit server unhealthy; defaults to [${DEF_GERRIT_HEALTHCHECK_RETRIES}]"
+    echo "[--location]                    Directory in which this script resides. Needed only when called from 'bazel test'."
+    echo "[--local-env]                   'setup_local_env' directory location. Needed only when called from 'bazel test'."
+    echo
+    exit 0
+  ;;
+  "--gerrit-image" )
+    GERRIT_IMAGE=$2
+    shift
+    shift
+  ;;
+  "--multisite-lib-file" )
+    MULTISITE_LIB_LOCATION=$2
+    shift
+    shift
+  ;;
+  "--replication-lib-file" )
+    REPLICATION_LIB_LOCATION=$2
+    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
+  ;;
+  "--start-period" )
+    GERRIT_HEALTHCHECK_START_PERIOD=$2
+    shift
+    shift
+  ;;
+  "--healthcheck-interval" )
+    GERRIT_HEALTHCHECK_INTERVAL=$2
+    shift
+    shift
+  ;;
+  "--healthcheck-timeout" )
+    GERRIT_HEALTHCHECK_TIMEOUT=$2
+    shift
+    shift
+  ;;
+  "--healthcheck-retries" )
+    GERRIT_HEALTHCHECK_RETRIES=$2
+    shift
+    shift
+  ;;
+  "--location" )
+    LOCATION=$2
+    shift
+    shift
+  ;;
+  "--local-env" )
+    LOCAL_ENV=$2
+    shift
+    shift
+  ;;
+  *     )
+    echo "Unknown option argument: $1"
+    shift
+    shift
+  ;;
+esac
+done
+
+# Defaults
+EVENTS_BROKER_VER=`grep 'com.gerritforge:events-broker' ${LOCATION}/../external_plugin_deps.bzl | cut -d '"' -f 2 | cut -d ':' -f 3`
+GLOBAL_REFDB_VER=`grep 'com.gerritforge:global-refdb' ${LOCATION}/../external_plugin_deps.bzl | cut -d '"' -f 2 | cut -d ':' -f 3`
+DEPLOYMENT_LOCATION=$(mktemp -d || $(echo >&2 "Could not create temp dir" && exit 1))
+MULTISITE_LIB_LOCATION=${MULTISITE_LIB_LOCATION:-${DEF_MULTISITE_LOCATION}}
+BROKER_TYPE=${BROKER_TYPE:-"kafka"}
+GERRIT_IMAGE=${GERRIT_IMAGE:-${DEF_GERRIT_IMAGE}}
+GERRIT_HEALTHCHECK_START_PERIOD=${GERRIT_HEALTHCHECK_START_PERIOD:-${DEF_GERRIT_HEALTHCHECK_START_PERIOD}}
+GERRIT_HEALTHCHECK_INTERVAL=${GERRIT_HEALTHCHECK_INTERVAL:-${DEF_GERRIT_HEALTHCHECK_INTERVAL}}
+GERRIT_HEALTHCHECK_TIMEOUT=${GERRIT_HEALTHCHECK_TIMEOUT:-${DEF_GERRIT_HEALTHCHECK_TIMEOUT}}
+GERRIT_HEALTHCHECK_RETRIES=${GERRIT_HEALTHCHECK_RETRIES:-${DEF_GERRIT_HEALTHCHECK_RETRIES}}
+
+# Gerrit primary
+GERRIT_1_ETC=${DEPLOYMENT_LOCATION}/etc_1
+GERRIT_1_PLUGINS=${DEPLOYMENT_LOCATION}/plugins_1
+GERRIT_1_LIBS=${DEPLOYMENT_LOCATION}/libs_1
+
+# Gerrit secondary
+GERRIT_2_ETC=${DEPLOYMENT_LOCATION}/etc_2
+GERRIT_2_PLUGINS=${DEPLOYMENT_LOCATION}/plugins_2
+GERRIT_2_LIBS=${DEPLOYMENT_LOCATION}/libs_2
+
+echo "Deployment location: [${DEPLOYMENT_LOCATION}]"
+
+echo "Downloading common plugins"
+COMMON_PLUGINS=${DEPLOYMENT_LOCATION}/common_plugins
+mkdir -p ${COMMON_PLUGINS}
+
+echo "plugin location[${MULTISITE_LIB_LOCATION}]"
+cp -f $MULTISITE_LIB_LOCATION $COMMON_PLUGINS/multi-site.jar  >/dev/null 2>&1 || \
+  { echo >&2 "$MULTISITE_LIB_LOCATION: Not able to copy the file. Aborting"; exit 1; }
+
+echo "Downloading websession-broker plugin $GERRIT_BRANCH"
+wget $GERRIT_CI/plugin-websession-broker-bazel-$GERRIT_BRANCH/$LAST_BUILD/websession-broker/websession-broker.jar \
+  -O $COMMON_PLUGINS/websession-broker.jar || { echo >&2 "Cannot download websession-broker plugin: Check internet connection. Aborting"; exit 1; }
+
+echo "Downloading healthcheck plugin $GERRIT_BRANCH"
+wget $GERRIT_CI/plugin-healthcheck-bazel-$GERRIT_BRANCH/$LAST_BUILD/healthcheck/healthcheck.jar \
+  -O $COMMON_PLUGINS/healthcheck.jar || { echo >&2 "Cannot download healthcheck plugin: Check internet connection. Aborting"; exit 1; }
+
+echo "Downloading zookeeper plugin $GERRIT_BRANCH"
+wget $GERRIT_CI/plugin-zookeeper-refdb-bazel-$GERRIT_BRANCH/$LAST_BUILD/zookeeper-refdb/zookeeper-refdb.jar \
+  -O $COMMON_PLUGINS/zookeeper-refdb.jar || { echo >&2 "Cannot download zookeeper plugin: Check internet connection. Aborting"; 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 $COMMON_PLUGINS/events-kafka.jar || { echo >&2 "Cannot download events-kafka plugin: Check internet connection. Aborting"; exit 1; }
+  BROKER_PORT=9092
+  BROKER_HOST=kafka
+  BROKER_PLUGIN=events-kafka
+else
+  #TODO add more broker types handling
+  echo >&2 "Broker type [${BROKER_TYPE}] not supported. Aborting";
+  exit 1;
+fi
+
+echo "Downloading common libs"
+COMMON_LIBS=${DEPLOYMENT_LOCATION}/common_libs
+mkdir -p ${COMMON_LIBS}
+
+echo "Getting replication.jar as a library"
+CONTAINER_NAME=$(docker create -ti --entrypoint /bin/bash gerritcodereview/gerrit:"${GERRIT_IMAGE}") && \
+docker cp ${CONTAINER_NAME}:/var/gerrit/plugins/replication.jar $COMMON_LIBS/
+docker rm -fv ${CONTAINER_NAME}
+
+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 $COMMON_LIBS/global-refdb.jar || { echo >&2 "Cannot download global-refdb library: Check internet connection. Aborting"; 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 $COMMON_LIBS/events-broker.jar || { echo >&2 "Cannot download events-broker library: Check internet connection. Aborting"; exit 1; }
+
+echo "Setting up directories"
+mkdir -p ${GERRIT_1_ETC} ${GERRIT_1_PLUGINS} ${GERRIT_1_LIBS} ${GERRIT_2_ETC} ${GERRIT_2_PLUGINS} ${GERRIT_2_LIBS}
+
+echo "Copying plugins"
+cp -f $COMMON_PLUGINS/* ${GERRIT_1_PLUGINS}
+cp -f $COMMON_PLUGINS/* ${GERRIT_2_PLUGINS}
+
+echo "Copying libs"
+cp -f $COMMON_LIBS/* ${GERRIT_1_LIBS}
+cp -f $COMMON_PLUGINS/multi-site.jar ${GERRIT_1_LIBS}
+cp -f $COMMON_LIBS/* ${GERRIT_2_LIBS}
+cp -f $COMMON_PLUGINS/multi-site.jar ${GERRIT_2_LIBS}
+
+echo "Setting up configuration"
+echo "Setup healthcheck config"
+cp -f ${LOCAL_ENV}/configs/healthcheck.config $GERRIT_1_ETC
+cp -f ${LOCAL_ENV}/configs/healthcheck.config $GERRIT_2_ETC
+
+echo "Setup multi-site config"
+cp -f ${LOCAL_ENV}/configs/multi-site.config $GERRIT_1_ETC
+cp -f ${LOCAL_ENV}/configs/multi-site.config $GERRIT_2_ETC
+
+echo "Setup zookeeper config"
+setup_zookeeper_config "${GERRIT_1_ETC}/zookeeper-refdb.config"
+setup_zookeeper_config "${GERRIT_2_ETC}/zookeeper-refdb.config"
+
+echo "Setup replication config"
+setup_replication_config "${GERRIT_1_ETC}/replication.config" 'file:///var/gerrit/git-instance2/${name}.git'
+setup_replication_config "${GERRIT_2_ETC}/replication.config" 'file:///var/gerrit/git-instance1/${name}.git'
+
+echo "Setup gerrit config"
+setup_gerrit_config "${GERRIT_1_ETC}/gerrit.config" $BROKER_HOST $BROKER_PORT instance-1 29418
+setup_gerrit_config "${GERRIT_2_ETC}/gerrit.config" $BROKER_HOST $BROKER_PORT instance-2 29419
+
+echo "Generating common SSH key for tests"
+COMMON_SSH=${DEPLOYMENT_LOCATION}/common_ssh
+mkdir -p ${COMMON_SSH}
+ssh-keygen -b 2048 -t rsa -f ${COMMON_SSH}/id_rsa -q -N "" || { echo >&2 "Cannot generate common SSH keys. Aborting"; exit 1; }
+
+SCENARIOS="$( cd "${LOCATION}" >/dev/null 2>&1 && pwd )/scenarios.sh"
+
+echo "Starting containers"
+COMPOSE_FILES="-f ${LOCATION}/docker-compose.yaml -f ${LOCATION}/docker-compose-kafka.yaml -f ${LOCATION}/docker-tester.yaml"
+
+# store setup in single file (under ${DEPLOYMENT_LOCATION}) with all variables resolved
+export GERRIT_IMAGE; \
+  export GERRIT_HEALTHCHECK_START_PERIOD; \
+  export GERRIT_HEALTHCHECK_INTERVAL; \
+  export GERRIT_HEALTHCHECK_TIMEOUT; \
+  export GERRIT_HEALTHCHECK_RETRIES; \
+  docker-compose ${COMPOSE_FILES} config > ${DEPLOYMENT_LOCATION}/docker-compose.yaml
+
+trap cleanup_tests_hook EXIT
+docker-compose -f ${DEPLOYMENT_LOCATION}/docker-compose.yaml up -d zookeeper kafka
+docker-compose -f ${DEPLOYMENT_LOCATION}/docker-compose.yaml ps -a
+docker-compose -f ${DEPLOYMENT_LOCATION}/docker-compose.yaml logs -f --no-color -t > ${DEPLOYMENT_LOCATION}/site.log &
+
+docker-compose -f ${DEPLOYMENT_LOCATION}/docker-compose.yaml up --no-start gerrit1 gerrit2
+docker-compose -f ${DEPLOYMENT_LOCATION}/docker-compose.yaml ps -a
+GERRIT1_CONTAINER=$(docker-compose -f ${DEPLOYMENT_LOCATION}/docker-compose.yaml ps -q gerrit1)
+GERRIT2_CONTAINER=$(docker-compose -f ${DEPLOYMENT_LOCATION}/docker-compose.yaml ps -q gerrit2)
+
+#copy files to gerrit containers
+echo "Copying files to Gerrit containers"
+docker cp "${GERRIT_1_ETC}/" "${GERRIT1_CONTAINER}:/var/gerrit/etc"
+docker cp "${GERRIT_1_PLUGINS}/" "${GERRIT1_CONTAINER}:/var/gerrit/plugins"
+docker cp "${GERRIT_1_LIBS}/" "${GERRIT1_CONTAINER}:/var/gerrit/libs"
+docker cp "${COMMON_SSH}/" "${GERRIT1_CONTAINER}:/var/gerrit/.ssh"
+
+docker cp "${GERRIT_2_ETC}/" "${GERRIT2_CONTAINER}:/var/gerrit/etc"
+docker cp "${GERRIT_2_PLUGINS}/" "${GERRIT2_CONTAINER}:/var/gerrit/plugins"
+docker cp "${GERRIT_2_LIBS}/" "${GERRIT2_CONTAINER}:/var/gerrit/libs"
+docker cp "${COMMON_SSH}/" "${GERRIT2_CONTAINER}:/var/gerrit/.ssh"
+
+echo "Starting Gerrit servers"
+docker-compose -f ${DEPLOYMENT_LOCATION}/docker-compose.yaml up -d gerrit1 gerrit2
+
+echo "Waiting for services to start (and being healthy) and calling e2e tests"
+docker-compose -f ${DEPLOYMENT_LOCATION}/docker-compose.yaml up --no-start tester
+docker-compose -f ${DEPLOYMENT_LOCATION}/docker-compose.yaml ps -a
+TEST_CONTAINER=$(docker-compose -f ${DEPLOYMENT_LOCATION}/docker-compose.yaml ps -q tester)
+docker cp "${COMMON_SSH}/" "${TEST_CONTAINER}:/var/gerrit/.ssh"
+docker cp "${SCENARIOS}" "${TEST_CONTAINER}:/var/gerrit/scenarios.sh"
+
+docker-compose -f ${DEPLOYMENT_LOCATION}/docker-compose.yaml up tester
+
+# inspect test container exit code as 'up' always returns '0'
+check_result "${TEST_CONTAINER}" 0
+RES_VAL=$?
+check_result "${GERRIT1_CONTAINER}" ${RES_VAL}
+RES_VAL=$?
+check_result "${GERRIT2_CONTAINER}" ${RES_VAL}
+RES_VAL=$?
+
+exit $RES_VAL
diff --git a/setup_local_env/configs/gerrit.config b/setup_local_env/configs/gerrit.config
index c4df06a..2cd8c9d 100644
--- a/setup_local_env/configs/gerrit.config
+++ b/setup_local_env/configs/gerrit.config
@@ -42,7 +42,7 @@
     directory = $FAKE_NFS
 [plugin "events-kafka"]
     sendAsync = true
-    bootstrapServers = localhost:$BROKER_PORT
+    bootstrapServers = $BROKER_HOST:$BROKER_PORT
     groupId = $GROUP_ID
     numberOfSubscribers = 6
     securityProtocol = PLAINTEXT
diff --git a/setup_local_env/configs/zookeeper-refdb.config b/setup_local_env/configs/zookeeper-refdb.config
index 2c84a05..9eb0789 100644
--- a/setup_local_env/configs/zookeeper-refdb.config
+++ b/setup_local_env/configs/zookeeper-refdb.config
@@ -1,2 +1,2 @@
 [ref-database "zookeeper"]
-	connectString = localhost:$ZK_PORT
\ No newline at end of file
+	connectString = $ZK_HOST:$ZK_PORT
\ No newline at end of file
diff --git a/setup_local_env/setup.sh b/setup_local_env/setup.sh
index b91033a..5342fbf 100755
--- a/setup_local_env/setup.sh
+++ b/setup_local_env/setup.sh
@@ -113,7 +113,11 @@
 }
 
 function deploy_config_files {
+  # broker configuration
+  export BROKER_HOST=localhost
+
   # ZK configuration
+  export ZK_HOST=localhost
   export ZK_PORT=2181
 
   # SITE 1