#!/bin/bash set -u set -o pipefail fatal() { printf 'harness: %s\n' "$*" >&2 exit 1 } wait_for_docker() { attempts=30 while [ "$attempts" -gt 0 ]; do docker info >/dev/null 2>&1 && return 0 attempts=$((attempts - 1)) sleep 1 done return 1 } cleanup() { docker ps -q --filter ancestor=hw3img | while IFS= read -r container_id; do [ -n "$container_id" ] || continue docker rm --force "$container_id" >/dev/null 2>&1 || true done } run_tests() { local arg local -a original_args=("$@") local -a test_args=(-docker -test.timeout=10m) while (($#)); do arg="$1" shift case "$arg" in -run|-count|-timeout|-parallel|-skip) if (($# == 0)); then fatal "$arg requires a value" fi test_args+=("-test.${arg#-}" "$1") shift ;; -run=*|-count=*|-timeout=*|-parallel=*|-skip=*) test_args+=("-test.${arg#-}") ;; -v|-short|-failfast|-v=*|-short=*|-failfast=*) test_args+=("-test.${arg#-}") ;; -test.*|-docker) test_args+=("$arg") ;; *) # Keep Go's flag handling for less common test and build options. go test --docker -timeout 10m "${original_args[@]}" return $? ;; esac done /usr/local/bin/hw3test "${test_args[@]}" } validate_score_file() { score_lines="$(grep -c '^SCORE:' "$1" || true)" valid_score_lines="$(grep -Ec '^SCORE: [0-9]+([.][0-9]{1,2})?$' "$1" || true)" [ "$score_lines" -eq 1 ] && [ "$valid_score_lines" -eq 1 ] \ || fatal "test command must report exactly one valid SCORE line" } configure_registry_proxy() { proxy_url="${DISTSYS_REGISTRY_PROXY_URL:-}" ca_file="/run/distsys-registry-proxy/ca.crt" [ -n "$proxy_url" ] || return 1 printf '%s' "$proxy_url" | grep -Eq '^http://[A-Za-z0-9.-]+(:[0-9]+)?$' || { printf 'warning: invalid registry proxy URL; using direct Docker pulls\n' >&2 return 1 } [ -f "$ca_file" ] && [ ! -L "$ca_file" ] || { printf 'warning: registry proxy CA is unavailable; using direct Docker pulls\n' >&2 return 1 } downloaded_ca="$(mktemp)" || return 1 if ! wget -q -T 5 -O "$downloaded_ca" "${proxy_url}/ca.crt" \ || ! cmp -s "$ca_file" "$downloaded_ca"; then rm -f "$downloaded_ca" printf 'warning: registry proxy is unavailable or its CA differs; using direct Docker pulls\n' >&2 return 1 fi rm -f "$downloaded_ca" cp "$ca_file" /usr/local/share/ca-certificates/distsys-registry-proxy.crt update-ca-certificates >/dev/null proxy_no_proxy='localhost,127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16' export HTTP_PROXY="$proxy_url" HTTPS_PROXY="$proxy_url" NO_PROXY="$proxy_no_proxy" export http_proxy="$proxy_url" https_proxy="$proxy_url" no_proxy="$proxy_no_proxy" } configure_registry_proxy || unset HTTP_PROXY HTTPS_PROXY NO_PROXY http_proxy https_proxy no_proxy if [ "${HW3_REQUIRE_ZRAM:-0}" = 1 ]; then /usr/local/bin/verify-zram-scratch.sh || fatal "HW3_REQUIRE_ZRAM=1 but /hw/tests/tmp is not mounted from a zram ext4 device" fi # Start docker daemon trap cleanup EXIT dockerd-entrypoint.sh --storage-driver=overlay2 >/var/log/dockerd-entrypoint.log 2>&1 & if ! wait_for_docker; then tail -n 200 /var/log/dockerd-entrypoint.log >&2 || true fatal "inner Docker daemon did not become ready" fi # Build server image docker build solution -t hw3img || fatal "could not build solution image" # Run tests cd tests export NO_COLOR=1 test_status=0 run_tests "$@" 2>&1 | tee tests.log || test_status=$? validate_score_file tests.log # Go reports a non-zero status when some grading groups fail. A valid score is # the grading result; absence of a score remains an infrastructure failure. if [ "$test_status" -ne 0 ]; then printf 'harness: grading tests exited with status %s after reporting a score\n' \ "$test_status" >&2 fi