#!/bin/bash
#
# Usage: ./run-all-tests <Kafka versions separated by ':'>...
#
# This script will automatically set up the Docker environment for Kafka, and then
# run all cargo tests, including integration tests, for each Kafka version specified.
# For example, running:
#
# ./run-all-tests 3.8.1:3.9.1
#
# will run the tests against Kafka versions 3.8.1 and 3.9.1. The arguments
# should correspond to a Docker tag of the `apache/kafka` image, so any valid
# tag will do.
#
# If there are no versions specified, it runs the tests on a default matrix.

set -e 

stop_docker() {
  docker compose down -v
}

start_docker() {
  docker compose pull kafka
  docker compose up -d kafka

  KAFKA_BIN="$(docker compose exec -T kafka sh -lc 'if [ -x /opt/kafka/bin/kafka-topics.sh ]; then echo /opt/kafka/bin; elif [ -x /kafka/bin/kafka-topics.sh ]; then echo /kafka/bin; else echo ""; fi')"
  if [[ -z "${KAFKA_BIN}" ]]; then
    echo >&2 "Could not find kafka scripts in container (expected /opt/kafka/bin or /kafka/bin)"
    exit 1
  fi

  # wait for Kafka to be ready
  ./do_until_success "docker compose exec -T kafka ${KAFKA_BIN}/kafka-broker-api-versions.sh --bootstrap-server kafka:19092 >/dev/null 2>&1"

  # create test topics (idempotent)
  docker compose exec -T kafka ${KAFKA_BIN}/kafka-topics.sh --bootstrap-server kafka:19092 --create --if-not-exists --topic kafka-rust-test --partitions 2 --replication-factor 1
  docker compose exec -T kafka ${KAFKA_BIN}/kafka-topics.sh --bootstrap-server kafka:19092 --create --if-not-exists --topic kafka-rust-test2 --partitions 2 --replication-factor 1
}

setup() {
  # use a subshell so the working directory changes back after it exits
  (
    cd "$(dirname $0)"
    stop_docker # just in case something went wrong with a previous shutdown

    # Generate binary TLS artifacts from the PEM fixtures (keystore/truststore).
    TLS_DIR="./fixtures/tls"
    TLS_GEN_DIR="${TLS_DIR}/generated"
    mkdir -p "${TLS_GEN_DIR}"

    # The Kafka image reads `KAFKA_SSL_*` env vars and maps them to `ssl.*` properties.
    KAFKA_SSL_STORE_PASSWORD="${KAFKA_SSL_STORE_PASSWORD:-kafka-rust-test}"
    export KAFKA_SSL_STORE_PASSWORD

    rm -f "${TLS_GEN_DIR}/server.keystore.p12" "${TLS_GEN_DIR}/server.truststore.p12"
    openssl pkcs12 -export \
      -in "${TLS_DIR}/server.crt.pem" \
      -inkey "${TLS_DIR}/server.key.pem" \
      -certfile "${TLS_DIR}/ca.crt.pem" \
      -name "kafka-rust-test-server" \
      -out "${TLS_GEN_DIR}/server.keystore.p12" \
      -passout "pass:${KAFKA_SSL_STORE_PASSWORD}"

    keytool -importcert \
      -alias "kafka-rust-test-ca" \
      -file "${TLS_DIR}/ca.crt.pem" \
      -keystore "${TLS_GEN_DIR}/server.truststore.p12" \
      -storetype PKCS12 \
      -storepass "${KAFKA_SSL_STORE_PASSWORD}" \
      -noprompt

    start_docker
  )
}

teardown() {
  # use a subshell so the working directory changes back after it exits
  (
    cd "$(dirname $0)"
    stop_docker
  )
}

### START TEST ###

# need to run tests serially to avoid the tests stepping on each others' toes
export RUST_TEST_THREADS=1
DEFAULT_VERS='3.8.1:3.9.1:4.0.1:4.1.0'
DEFAULT_COMPRESSIONS='NONE'
DEFAULT_SECURES=':tls:mtls:sasl_plaintext'

vers=$@

if [[ -z "${vers}" ]]; then
  vers=$DEFAULT_VERS
fi

# we want to tell the difference between explicitly set to empty vs
# unset, so we do the +x expansion. See
# https://stackoverflow.com/questions/3601515/how-to-check-if-a-variable-is-set-in-bash
if [[ -z "${COMPRESSIONS+x}" ]]; then
  COMPRESSIONS=$DEFAULT_COMPRESSIONS
fi

# if completely unset, set defaults
if [[ -z "${SECURES+x}" ]]; then
  SECURES=$DEFAULT_SECURES

# if it is explicitly set to empty, set it to just : so the for loop will
# yield once with the empty string
elif [[ -z "${SECURES}" ]]; then
  SECURES=':'
fi

IFS=':'
for ver in $vers; do
  for compression in $COMPRESSIONS; do
    for secure in $SECURES; do
      export KAFKA_VER=$ver
      export KAFKA_CLIENT_COMPRESSION=$compression
      export KAFKA_CLIENT_SECURE=$secure
      if [[ "${secure}" == "mtls" ]]; then
        export KAFKA_SSL_CLIENT_AUTH="required"
      else
        export KAFKA_SSL_CLIENT_AUTH="none"
      fi

      echo -n "Running tests with KAFKA_VER=$KAFKA_VER, "
      echo -n "KAFKA_CLIENT_COMPRESSION=$compression, "
      echo "KAFKA_CLIENT_SECURE=$secure"

      setup || {
        teardown
        exit 1
      }

      cargo test --all-features || {
        teardown
        exit 1
      }

      teardown
    done
  done
done
