#!/usr/bin/env bash set -euo pipefail project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" compose_file="$project_root/compose.test.yml" wait_seconds="${TREE_FELLER_START_TIMEOUT:-900}" if ! command -v docker >/dev/null 2>&1; then echo "Required command not found: docker" >&2 exit 1 fi if ! docker info >/dev/null 2>&1; then echo "Docker is not running or is not accessible." >&2 exit 1 fi if ! docker compose version >/dev/null 2>&1; then echo "Docker Compose v2 is required." >&2 exit 1 fi cd "$project_root" ./gradlew clean check jar mkdir -p .docker/minecraft # Recreate the container so the image installs the newly built read-only plugin JAR. docker compose -f "$compose_file" up -d --force-recreate container_id="$(docker compose -f "$compose_file" ps -q minecraft)" if [[ -z "$container_id" ]]; then echo "The Tree Feller test container was not created." >&2 exit 1 fi echo "Waiting up to ${wait_seconds}s for Spigot 26.2..." deadline=$((SECONDS + wait_seconds)) while (( SECONDS < deadline )); do container_state="$(docker inspect --format '{{.State.Status}}' "$container_id")" health_state="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container_id")" if [[ "$health_state" == "healthy" ]]; then break fi if [[ "$container_state" == "exited" || "$container_state" == "dead" ]]; then docker compose -f "$compose_file" logs --tail=150 minecraft >&2 echo "The Minecraft server exited during startup." >&2 exit 1 fi sleep 5 done health_state="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container_id")" if [[ "$health_state" != "healthy" ]]; then docker compose -f "$compose_file" logs --tail=150 minecraft >&2 echo "Timed out waiting for Spigot 26.2 (status: $health_state)." >&2 exit 1 fi plugins="$(docker compose -f "$compose_file" exec -T minecraft rcon-cli plugins)" if [[ "$plugins" != *"TreeFeller"* ]]; then echo "$plugins" >&2 echo "TreeFeller was not reported by the running server." >&2 exit 1 fi # Offline mode assigns a deterministic UUID that differs from the account's online UUID. # Verify the exact identity instead of issuing `op WindMagi`, which can resolve online identity. offline_uuid="6a3b6e9f-1a2f-380c-8a75-7a7ca6392c0e" ops_json="$(docker compose -f "$compose_file" exec -T minecraft sh -lc 'cat /data/ops.json')" if [[ "$ops_json" != *'"name": "WindMagi"'* || "$ops_json" != *"\"uuid\": \"${offline_uuid}\""* ]]; then echo "$ops_json" >&2 echo "WindMagi's offline-mode UUID was not installed as an operator." >&2 exit 1 fi cat <<'MESSAGE' Tree Feller test server is ready at localhost:25565. Operator: WindMagi View logs: docker compose -f compose.test.yml logs -f minecraft Stop: docker compose -f compose.test.yml down Reset: docker compose -f compose.test.yml down && rm -rf .docker/minecraft MESSAGE