Harden Android deployment and implement dynamic port allocation
- Replace fixed ports with dynamic allocation (port 0) for all Stalwart listeners, including ManageSieve. - Require KVM acceleration for Android integration tests; fail early with setup instructions if /dev/kvm is inaccessible. - Require all ANDROID_APK_SCP environment variables for deployment; fail early if any are missing. - Revert emulator boot timeouts to standard values (120s device / 60s boot) now that software emulation is disabled.
This commit is contained in:
@@ -45,9 +45,19 @@ ADB=$(command -v adb 2>/dev/null || echo "${ANDROID_HOME:-$HOME/Android/Sdk}/pla
|
||||
# Detect a connected Android emulator; auto-start the sharedinbox_test AVD if none is running.
|
||||
EMULATOR_ID=$("$ADB" devices | awk '/^emulator-[0-9]+[[:space:]]+device$/ {print $1; exit}')
|
||||
if [ -z "$EMULATOR_ID" ]; then
|
||||
# Check for KVM before starting.
|
||||
if [ ! -c /dev/kvm ] || [ ! -r /dev/kvm ] || [ ! -w /dev/kvm ]; then
|
||||
echo "ERROR: KVM (/dev/kvm) not accessible. Software emulation is too slow for these tests."
|
||||
echo "Run these commands to fix permissions:"
|
||||
echo " sudo groupadd -r kvm || true"
|
||||
echo " sudo gpasswd -a \$USER kvm"
|
||||
echo " # Then log out and back in."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
EMULATOR_BIN="${ANDROID_HOME:-$HOME/Android/Sdk}/emulator/emulator"
|
||||
ts "no emulator running — booting AVD sharedinbox_test"
|
||||
"$EMULATOR_BIN" -avd sharedinbox_test -no-window -no-audio -no-snapshot-save -accel off -no-boot-anim -gpu swiftshader_indirect > /tmp/emulator.log 2>&1 &
|
||||
"$EMULATOR_BIN" -avd sharedinbox_test -no-window -no-audio -no-snapshot-save > /tmp/emulator.log 2>&1 &
|
||||
EMULATOR_BOOT_PID=$!
|
||||
# Extend cleanup to also kill the emulator we started.
|
||||
cleanup() {
|
||||
@@ -57,21 +67,21 @@ if [ -z "$EMULATOR_ID" ]; then
|
||||
kill "${EMULATOR_BOOT_PID:-}" 2>/dev/null || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
# Wait up to 300 s for the emulator to appear as a fully booted device.
|
||||
for _i in $(seq 1 150); do
|
||||
# Wait up to 120 s for the emulator to appear as a fully booted device.
|
||||
for _i in $(seq 1 60); do
|
||||
EMULATOR_ID=$("$ADB" devices | awk '/^emulator-[0-9]+[[:space:]]+device$/ {print $1; exit}')
|
||||
[ -n "$EMULATOR_ID" ] && break
|
||||
sleep 2
|
||||
done
|
||||
[ -n "$EMULATOR_ID" ] || { echo "Emulator did not become ready within 300 s"; exit 1; }
|
||||
[ -n "$EMULATOR_ID" ] || { echo "Emulator did not become ready within 120 s"; exit 1; }
|
||||
# Wait for the Android system to finish booting (sys.boot_completed=1).
|
||||
"$ADB" -s "$EMULATOR_ID" wait-for-device
|
||||
for _i in $(seq 1 600); do
|
||||
for _i in $(seq 1 30); do
|
||||
BOOT_DONE=$("$ADB" -s "$EMULATOR_ID" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r')
|
||||
[ "$BOOT_DONE" = "1" ] && break
|
||||
sleep 2
|
||||
done
|
||||
[ "${BOOT_DONE:-0}" = "1" ] || { echo "Android boot did not complete within 1200 s"; exit 1; }
|
||||
[ "${BOOT_DONE:-0}" = "1" ] || { echo "Android boot did not complete within 60 s"; exit 1; }
|
||||
fi
|
||||
ts "using emulator: $EMULATOR_ID"
|
||||
|
||||
@@ -110,17 +120,18 @@ curl -s --max-time 1 -o /dev/null "${STALWART_URL}/.well-known/jmap" || {
|
||||
cat "$LOGFILE"; echo "Stalwart did not become ready"; exit 1
|
||||
}
|
||||
|
||||
ts "stalwart ready — IMAP=:${STALWART_IMAP_PORT:-?} SMTP=:${STALWART_SMTP_PORT:-?}"
|
||||
ts "stalwart ready — IMAP=:${STALWART_IMAP_PORT:-?} SMTP=:${STALWART_SMTP_PORT:-?} SIEVE=:${STALWART_SIEVE_PORT:-?}"
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
cd "$ROOT"
|
||||
|
||||
# Platform.environment is empty inside the Android app process, so env vars set
|
||||
# by this script never reach the test code. Instead, use adb reverse to forward
|
||||
# the fixed "template" ports that the test defaults to (1430 IMAP, 1025 SMTP)
|
||||
# the fixed "template" ports that the test defaults to (1430 IMAP, 1025 SMTP, 4190 SIEVE)
|
||||
# on the emulator through to the actual random Stalwart ports on the host.
|
||||
"$ADB" -s "$EMULATOR_ID" reverse tcp:1430 tcp:"$STALWART_IMAP_PORT"
|
||||
"$ADB" -s "$EMULATOR_ID" reverse tcp:1025 tcp:"$STALWART_SMTP_PORT"
|
||||
"$ADB" -s "$EMULATOR_ID" reverse tcp:4190 tcp:"$STALWART_SIEVE_PORT"
|
||||
|
||||
# Clear any leftover app state from previous runs (stale DB, cached APK process).
|
||||
# Only run if the package is installed — that way any failure is a real error.
|
||||
|
||||
@@ -17,22 +17,32 @@ ADB=$(command -v adb 2>/dev/null || echo "${ANDROID_HOME:-$HOME/Android/Sdk}/pla
|
||||
|
||||
EMULATOR_ID=$("$ADB" devices | awk '/^emulator-[0-9]+[[:space:]]+device$/ {print $1; exit}')
|
||||
if [ -z "$EMULATOR_ID" ]; then
|
||||
# Check for KVM before starting.
|
||||
if [ ! -c /dev/kvm ] || [ ! -r /dev/kvm ] || [ ! -w /dev/kvm ]; then
|
||||
echo "ERROR: KVM (/dev/kvm) not accessible. Software emulation is too slow."
|
||||
echo "Run these commands to fix permissions:"
|
||||
echo " sudo groupadd -r kvm || true"
|
||||
echo " sudo gpasswd -a \$USER kvm"
|
||||
echo " # Then log out and back in."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
EMULATOR_BIN="${ANDROID_HOME:-$HOME/Android/Sdk}/emulator/emulator"
|
||||
echo "No emulator running — booting AVD sharedinbox_test..."
|
||||
"$EMULATOR_BIN" -avd sharedinbox_test -no-audio -no-snapshot-save -accel off &
|
||||
for _i in $(seq 1 150); do
|
||||
"$EMULATOR_BIN" -avd sharedinbox_test -no-audio -no-snapshot-save &
|
||||
for _i in $(seq 1 60); do
|
||||
EMULATOR_ID=$("$ADB" devices | awk '/^emulator-[0-9]+[[:space:]]+device$/ {print $1; exit}')
|
||||
[ -n "$EMULATOR_ID" ] && break
|
||||
sleep 2
|
||||
done
|
||||
[ -n "$EMULATOR_ID" ] || { echo "Emulator did not become ready within 300 s"; exit 1; }
|
||||
[ -n "$EMULATOR_ID" ] || { echo "Emulator did not become ready within 120 s"; exit 1; }
|
||||
"$ADB" -s "$EMULATOR_ID" wait-for-device
|
||||
for _i in $(seq 1 450); do
|
||||
for _i in $(seq 1 30); do
|
||||
BOOT_DONE=$("$ADB" -s "$EMULATOR_ID" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r')
|
||||
[ "$BOOT_DONE" = "1" ] && break
|
||||
sleep 2
|
||||
done
|
||||
[ "${BOOT_DONE:-0}" = "1" ] || { echo "Android boot did not complete within 900 s"; exit 1; }
|
||||
[ "${BOOT_DONE:-0}" = "1" ] || { echo "Android boot did not complete within 60 s"; exit 1; }
|
||||
fi
|
||||
|
||||
echo "Using emulator: $EMULATOR_ID"
|
||||
|
||||
+8
-5
@@ -21,11 +21,11 @@ if [ "${STALWART_RANDOM_PORTS:-0}" = "1" ] || [ "${STALWART_PORT:-0}" = "0" ]; t
|
||||
echo "python3 not in PATH — cannot choose random Stalwart ports"
|
||||
exit 1
|
||||
}
|
||||
read -r STALWART_PORT STALWART_IMAP_PORT STALWART_SMTP_PORT < <(
|
||||
read -r STALWART_PORT STALWART_IMAP_PORT STALWART_SMTP_PORT STALWART_SIEVE_PORT < <(
|
||||
python3 - <<'PY'
|
||||
import socket
|
||||
ports = []
|
||||
for _ in range(3):
|
||||
for _ in range(4):
|
||||
sock = socket.socket()
|
||||
sock.bind(("127.0.0.1", 0))
|
||||
ports.append(str(sock.getsockname()[1]))
|
||||
@@ -37,15 +37,16 @@ else
|
||||
: "${STALWART_PORT:?STALWART_PORT is not set — run this inside nix develop}"
|
||||
STALWART_IMAP_PORT="${STALWART_IMAP_PORT:-$((STALWART_PORT + 1))}"
|
||||
STALWART_SMTP_PORT="${STALWART_SMTP_PORT:-$((STALWART_PORT + 2))}"
|
||||
STALWART_SIEVE_PORT="${STALWART_SIEVE_PORT:-$((STALWART_PORT + 3))}"
|
||||
fi
|
||||
|
||||
export STALWART_PORT STALWART_IMAP_PORT STALWART_SMTP_PORT
|
||||
export STALWART_PORT STALWART_IMAP_PORT STALWART_SMTP_PORT STALWART_SIEVE_PORT
|
||||
export STALWART_URL="http://127.0.0.1:${STALWART_PORT}"
|
||||
|
||||
TMPDIR="${STALWART_TMPDIR:-/tmp/stalwart-dev-${STALWART_PORT}}"
|
||||
mkdir -p "$TMPDIR"
|
||||
|
||||
for port in "$STALWART_PORT" "$STALWART_IMAP_PORT" "$STALWART_SMTP_PORT"; do
|
||||
for port in "$STALWART_PORT" "$STALWART_IMAP_PORT" "$STALWART_SMTP_PORT" "$STALWART_SIEVE_PORT"; do
|
||||
ss -ltnH "sport = :$port" | grep -q . && {
|
||||
echo "Stalwart port $port is already in use"
|
||||
exit 1
|
||||
@@ -56,10 +57,11 @@ cat >"${TMPDIR}/ports.env" <<EOF
|
||||
export STALWART_PORT=${STALWART_PORT}
|
||||
export STALWART_IMAP_PORT=${STALWART_IMAP_PORT}
|
||||
export STALWART_SMTP_PORT=${STALWART_SMTP_PORT}
|
||||
export STALWART_SIEVE_PORT=${STALWART_SIEVE_PORT}
|
||||
export STALWART_URL=${STALWART_URL}
|
||||
EOF
|
||||
|
||||
echo "Stalwart ports: JMAP=${STALWART_PORT} IMAP=${STALWART_IMAP_PORT} SMTP=${STALWART_SMTP_PORT}" >&2
|
||||
echo "Stalwart ports: JMAP=${STALWART_PORT} IMAP=${STALWART_IMAP_PORT} SMTP=${STALWART_SMTP_PORT} SIEVE=${STALWART_SIEVE_PORT}" >&2
|
||||
echo "Stalwart is running in the foreground. Press Ctrl+C to stop." >&2
|
||||
echo "Connection info written to ${TMPDIR}/ports.env" >&2
|
||||
|
||||
@@ -68,6 +70,7 @@ REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
sed -e "s|127.0.0.1:8080|127.0.0.1:${STALWART_PORT}|" \
|
||||
-e "s|127.0.0.1:1430|127.0.0.1:${STALWART_IMAP_PORT}|" \
|
||||
-e "s|127.0.0.1:1025|127.0.0.1:${STALWART_SMTP_PORT}|" \
|
||||
-e "s|127.0.0.1:4190|127.0.0.1:${STALWART_SIEVE_PORT}|" \
|
||||
-e "s|/tmp/stalwart-dev|${TMPDIR}|" \
|
||||
"${REPO_ROOT}/stalwart-dev/config.toml" >"${TMPDIR}/config.toml"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user