#!/bin/bash
set -o errexit
set -o errtrace
set -o pipefail
set -o nounset

testsuite=$1
shift

if [ -z "${AUTOPKGTEST_TMP+x}" ] || [ -z "${AUTOPKGTEST_ARTIFACTS+x}" ]; then
  echo "Environment variables AUTOPKGTEST_TMP and AUTOPKGTEST_ARTIFACTS must be set" >&2
  exit 1
fi

host_arch="${DEB_HOST_ARCH:-$(dpkg --print-architecture)}"

if [ -z "${JDK_TO_TEST+x}" ]; then
  JDK_TO_TEST=$(echo /usr/lib/jvm/java-23-openjdk-amd64 | sed "s/-[^-]*$/-$host_arch/")
fi

if [ -z "${BOOTJDK_HOME+x}" ]; then
  BOOTJDK_HOME=${JDK_TO_TEST}
fi

jtreg_version="$(dpkg-query -W jtreg7 | cut -f2)"

# set additional jtreg options
jt_options="${JTREG_OPTIONS:-}"
if [[ "armel" == *"${host_arch}"* ]]; then
  jt_options+=" -Xmx256M"
fi
if dpkg --compare-versions ${jtreg_version} ge 4.2; then
  jt_options+=" -conc:auto"
fi

# check java binary
if [ ! -x "${JDK_TO_TEST}/bin/java" ]; then
  echo "Error: JDK_TO_TEST: '${JDK_TO_TEST}/bin/java' is not an executable." >&2
  exit 1
fi

if [ ! -x "${BOOTJDK_HOME}/bin/java" ]; then
  echo "Error: BOOTJDK_HOME: '${BOOTJDK_HOME}/bin/java' is not an executable." >&2
  exit 1
fi

# restrict the tests to a few archs (set from debian/rules)
if ! echo "${host_arch}" | grep -qE "^($(echo amd64 i386 arm64 ppc64 ppc64el riscv64 s390x alpha ia64 powerpc ppc64 sh4 x32 armel loong64 mipsel mips64el riscv64 | tr ' ' '|'))$"; then
  echo "Error: ${host_arch} is not on the jtreg_archs list, ignoring it."
  exit 77
fi

jtreg_processes() {
  ps x -ww -o pid,ppid,args \
    | awk '$2 == 1 && $3 ~ /^\/scratch/' \
    | sed "s,${JDK_TO_TEST},<sdkimg>,g;s,$(pwd),<pwd>,g"
}

jtreg_pids() {
  ps x --no-headers -ww -o pid,ppid,args \
    | awk "\$2 == 1 && \$3 ~ /^${JDK_TO_TEST//\//\\/}/ {print \$1}"
}

cleanup() {
  # kill testsuite processes still hanging
  pids="$(jtreg_pids)"
  if [ -n "$pids" ]; then
    echo "[$0] killing processes..."
    jtreg_processes
    kill -1 $pids
    sleep 2
    pids="$(jtreg_pids)"
    if [ -n "$pids" ]; then
      echo "[$0] try harder..."
      jtreg_processes
      kill -9 $pids
      sleep 2
    fi
  else
    echo "[$0] nothing to cleanup"
  fi
  pids="$(jtreg_pids)"
  if [ -n "$pids" ]; then
    echo "[$0] leftover processes..."
    $(jtreg_processes)
  fi
}

trap "cleanup" EXIT INT TERM ERR

jtwork_dir="${AUTOPKGTEST_TMP}/${testsuite}/JTwork"
output_dir="${AUTOPKGTEST_ARTIFACTS}/${testsuite}/"

# retry tests with "fail" or "error" status at most 3 times
for i in 0 1 2; do
  # save each try under its own folder to preserve history
  report_path="${i}/JTreport"
  report_dir="${output_dir}/${report_path}"
# see make/RunTests.gmk for a set of good options
  jtreg ${jt_options} \
    -verbose:summary \
    -automatic \
    -retain:none \
    -ignore:quiet \
    -agentvm \
    -timeout:5 \
    -workDir:"${jtwork_dir}" \
    -reportDir:"${report_dir}" \
    -jdk:${JDK_TO_TEST} \
    -vmoption:-Dtest.boot.jdk=${BOOTJDK_HOME} \
    -vmoption:-XX:MaxRAMPercentage=25 \
    -vmoption:-Duser.home=${AUTOPKGTEST_TMP} \
    -vmoption:-Djava.io.tmpdir=${AUTOPKGTEST_TMP} \
    -e:NSS_DEFAULT_DB_TYPE=sql \
    ${on_retry:-} $@ \
      && exit_code=0 || exit_code=$?

  # copy .jtr files from failed tests for latter debugging
  find "${jtwork_dir}" -name '*.jtr' -exec egrep -q '^execStatus=[^Pass]' {} \; -printf "%P\n" \
    | while IF= read -r jtr; do
        jtr_dir=$(dirname "${output_dir}/JTwork/${jtr}")
        mkdir -p "${jtr_dir}"
        cp --update --preserve --backup=numbered "${jtwork_dir}/${jtr}" "${output_dir}/JTwork/${jtr}"
        # copy all generated hs_err_pid log into the jtr's directory to easy debugging
        if grep -qhE 'hs_err_pid[0-9]+\.log' "${output_dir}/JTwork/${jtr}"; then
            grep -hEo '/[^ ]*/hs_err_pid[0-9]+\.log' "${output_dir}/JTwork/${jtr}" \
                | xargs cp --update --preserve --backup=numbered -t "${jtr_dir}" \
                || echo "Warning: unable to find hs_err log for ${jtr}"
        fi
    done

  # break if jtdiff reports no difference from previous run
  # also deletes the just created JTreport
  # DISABLED: don't use it for now as flaky tests could still pass given more retries
  #jtdiff "${output_dir}/JTreport" "$report_dir" >/dev/null 2>&1 \
  #  && rm -rf "${report_dir}" && break

  # link latest JTreport to output_dir
  ln -sf -t "${output_dir}" "${report_path}"

  # if all test passed there is not need for a retry
  if [ "x${exit_code}" == "x0" ]; then break; fi

  # only retry tests with fail/error status
  on_retry="-status:fail,error"
done

exit $exit_code
