Ctrl K
ComunidadGuías…

ci/linux_ci_resume_test.sh

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/bin/sh
# Exercise the real Linux runner without installing packages or running CI workloads.
set -eu
unset VTEST_RESUME_DIR VTEST_RESUME_OWNER V_CI_TASK_PROGRESS V_MACOS_CI_TASK_PROGRESS

repo=$(CDPATH= cd "$(dirname "$0")/.." && pwd -P)
vexe=${VEXE:-"$repo/v"}
work=$(mktemp -d "${TMPDIR:-/tmp}/v-linux-ci-resume.XXXXXX")
work=$(cd "$work" && pwd -P)
checkpoint=
other_checkpoint=
cleanup() {
    [ -z "$checkpoint" ] || rm -rf "$checkpoint" "$checkpoint.d"
    [ -z "$other_checkpoint" ] || rm -rf "$other_checkpoint" "$other_checkpoint.d"
    rm -rf "$work"
}
trap cleanup EXIT
trap 'exit 130' INT
trap 'exit 143' TERM

fail() {
    echo "FAIL: $*" >&2
    [ ! -f "$work/output" ] || cat "$work/output" >&2
    exit 1
}

# Guard against accidentally omitting or reordering any workflow script task.
sed -n '/^const ci_tasks = \[/,/^\]/p' "$repo/ci/linux_ci.vsh" |
    sed -n "s/^[[:space:]]*'\([^']*\)',$/\1/p" > "$work/tasks"
sed -n 's/^[[:space:]]*run: v run ci\/linux_ci.vsh \([^ ]*\)$/\1/p' \
    "$repo/.github/workflows/linux_ci.yml" > "$work/workflow-tasks"
[ -s "$work/tasks" ] || fail 'could not read the CI task list'
cmp "$work/tasks" "$work/workflow-tasks" || fail 'CI task plan differs from the workflow'

# Direct workflow tasks inherit their compiler from the job, while aggregate CI
# selects it in ci_vflags. Keep both paths on the same compiler for every lane.
for compiler in tcc gcc clang; do
    flags=$(awk -v job="$compiler-linux:" '
        /^  [^ ]/ { selected = $1 == job }
        selected && /^      VFLAGS:/ {
            sub(/^      VFLAGS:[[:space:]]*/, "")
            print
            exit
        }
    ' "$repo/.github/workflows/linux_ci.yml")
    expected="-cc $compiler"
    [ "$compiler" != tcc ] || expected="$expected -no-retry-compilation"
    [ "$flags" = "$expected" ] || fail "$compiler workflow compiler flags differ from aggregate CI"
done

runner="$work/runner"
"$vexe" -o "$runner" "$repo/ci/linux_ci.vsh"
checkout="$work/checkout with spaces"
mkdir "$checkout"
fake_v="$work/fake v"
cat > "$fake_v" <<'MOCK'
#!/bin/sh
set -eu
if [ "$1" = doctor ]; then
    [ "${VTEST_FAIL_FAST:-}" = 0 ] && [ "${VJOBS:-}" = 8 ] || exit 94
    [ -z "${V_CI_TASK_PROGRESS:-}" ] && [ -z "${VTEST_RESUME_DIR:-}" ] || exit 95
    [ "${VTEST_SKIP_OWNERSHIP:-}" = 0 ] || exit 95
    [ "$VFLAGS" = '-cc inherited' ] || exit 98
    echo doctor >> direct.log
    exit 0
fi
[ "$1" = run ] && [ "$2" = ci/linux_ci.vsh ] || exit 90
[ "$CI" = true ] && [ "$GITHUB_ACTIONS" = true ] && [ "$RUNNER_OS" = Linux ] || exit 91
[ "$V_MACOS_V3_NO_FALLBACK" = 1 ] || exit 92
[ "${VTEST_FAIL_FAST:-}" = 1 ] && [ "${VJOBS:-}" = 8 ] || exit 93
[ "${VTEST_SKIP_OWNERSHIP:-}" = 1 ] || exit 93
[ -z "${VTEST_RESUME_OWNER:-}" ] || exit 99
case "$3" in
    *_gcc) compiler=gcc; flags='-cc gcc' ;;
    *_clang) compiler=clang; flags='-cc clang' ;;
    *) compiler=tcc; flags='-cc tcc -no-retry-compilation' ;;
esac
[ "$GITHUB_JOB" = "$compiler-linux" ] && [ "$VFLAGS" = "$flags" ] || exit 92
case "$V_CI_TASK_PROGRESS" in */"$3") ;; *) exit 96 ;; esac
case "$VTEST_RESUME_DIR" in "$V_CI_TASK_PROGRESS"/tests/*) ;; *) exit 97 ;; esac
# The failing/interrupted task must already be durable before it starts.
progress_dir=${V_CI_TASK_PROGRESS%/*}
[ "$(sed -n '2p' "${progress_dir%.d}")" = "$3" ] || exit 98
mkdir -p "$V_CI_TASK_PROGRESS"
printf '%s\n' "$3" >> tasks.log
if [ -f fail-task ] && [ "$3" = "$(cat fail-task)" ]; then
    exit 7
fi
MOCK
chmod +x "$fake_v"

run_ci() {
    expected_status=$1
    shift
    : > "$checkout/tasks.log"
    status=0
    # Aggregate CI must select the workflow compiler without changing parallelism.
    (cd "$checkout" && VTEST_FAIL_FAST=0 VJOBS=8 VFLAGS='-cc inherited' \
        VTEST_SKIP_OWNERSHIP=0 VTEST_RESUME_OWNER=inherited V_MACOS_V3_NO_FALLBACK=0 \
        XDG_CACHE_HOME="$work/cache" \
        V_CI_VEXE="$fake_v" "$runner" "$@") > "$work/output" 2>&1 || status=$?
    [ "$status" -eq "$expected_status" ] || fail "exit $status, expected $expected_status"
}

failed_task=verify_v_test_works_tcc
failed_line=$(grep -n "^$failed_task$" "$work/tasks" | cut -d: -f1)
printf '%s\n' "$failed_task" > "$checkout/fail-task"
head -n "$failed_line" "$work/tasks" > "$work/prefix"
tail -n "+$failed_line" "$work/tasks" > "$work/suffix"

run_ci 7 ci
checkpoint=$(sed -n 's/^CI progress: //p' "$work/output")
[ -f "$checkpoint" ] || fail 'failure did not leave a checkpoint'
case "$checkpoint" in "$work/cache"/v-linux-ci-*.progress) ;; *) fail 'wrong checkpoint namespace' ;; esac
[ "$(sed -n '2p' "$checkpoint")" = "$failed_task" ] || fail 'saved the wrong task'
cmp "$work/prefix" "$checkout/tasks.log"
cp "$checkpoint" "$work/saved"
touch "$checkpoint.d/retained"

run_ci 7 ci
printf '%s\n' "$failed_task" > "$work/one"
cmp "$work/one" "$checkout/tasks.log"
cmp "$work/saved" "$checkpoint"
[ -f "$checkpoint.d/retained" ] || fail 'retry discarded per-test progress'

# A fix resumes at the failure and then switches compiler/job for GCC and Clang.
rm "$checkout/fail-task"
run_ci 0 ci
cmp "$work/suffix" "$checkout/tasks.log"
[ ! -e "$checkpoint" ] && [ ! -e "$checkpoint.d" ] || fail 'success retained progress'
run_ci 0 ci
cmp "$work/tasks" "$checkout/tasks.log"

# Invalid arguments must leave progress untouched and execute no tasks.
cp "$work/saved" "$checkpoint"
printf '%s\n' "$failed_task" > "$checkout/fail-task"
mkdir -p "$checkpoint.d"
touch "$checkpoint.d/stale"
for args in 'ci --typo' 'ci --reset extra'; do
    # Intentional splitting: these are fixed argument fixtures, not user input.
    run_ci 1 $args
    [ ! -s "$checkout/tasks.log" ] || fail 'invalid arguments ran tasks'
    cmp "$work/saved" "$checkpoint"
    [ -f "$checkpoint.d/stale" ] || fail 'invalid arguments changed progress'
done
run_ci 7 ci --reset
[ ! -e "$checkpoint.d/stale" ] || fail 'reset retained per-test progress'
cmp "$work/prefix" "$checkout/tasks.log"

# Reject corruption and changes to the ordered plan.
for state in truncated unknown changed; do
    touch "$checkpoint.d/stale"
    case "$state" in
        truncated) printf 'linux-ci-v1\n' > "$checkpoint" ;;
        unknown) sed '2s/.*/no_such_task/' "$work/saved" > "$checkpoint" ;;
        changed) sed 's/build_v_with_prealloc/changed_task/' "$work/saved" > "$checkpoint" ;;
    esac
    run_ci 7 ci
    cmp "$work/prefix" "$checkout/tasks.log"
    grep -q 'Ignoring invalid or outdated CI progress' "$work/output"
    [ ! -e "$checkpoint.d/stale" ] || fail 'invalid cursor retained per-test progress'
done

rm "$checkpoint"
touch "$checkpoint.d/stale"
run_ci 7 ci
cmp "$work/prefix" "$checkout/tasks.log"
[ ! -e "$checkpoint.d/stale" ] || fail 'missing cursor retained per-test progress'

# Direct workflow tasks must not adopt aggregate CI settings or consume its cursor.
run_ci 0 v_doctor_tcc
cmp "$work/saved" "$checkpoint"
[ "$(cat "$checkout/direct.log")" = doctor ] || fail 'individual task did not run'

first_checkout=$checkout
checkout="$work/other checkout"
mkdir "$checkout"
printf '%s\n' "$failed_task" > "$checkout/fail-task"
run_ci 7 ci
other_checkpoint=$(sed -n 's/^CI progress: //p' "$work/output")
[ "$checkpoint" != "$other_checkpoint" ] || fail 'checkouts share a checkpoint'
cmp "$work/prefix" "$checkout/tasks.log"
cmp "$work/saved" "$checkpoint"
checkout=$first_checkout

# Resume directly into each later backend, including a failure in the final task.
last_task=$(tail -n 1 "$work/tasks")
for task in verify_v_test_works_gcc verify_v_test_works_clang "$last_task"; do
    printf '%s\n' "$task" > "$checkout/fail-task"
    run_ci 7 ci
    [ "$(sed -n '2p' "$checkpoint")" = "$task" ] || fail 'saved wrong backend task'
    run_ci 7 ci
    printf '%s\n' "$task" > "$work/one"
    cmp "$work/one" "$checkout/tasks.log"
done
rm "$checkout/fail-task"
run_ci 0 ci
cmp "$work/one" "$checkout/tasks.log"
[ ! -e "$checkpoint" ] && [ ! -e "$checkpoint.d" ] || fail 'final retry retained progress'

# An unreadable cursor or failed atomic replacement must stop before running tasks.
mkdir "$checkpoint"
run_ci 1 ci
[ ! -s "$checkout/tasks.log" ] || fail 'tasks ran despite a checkpoint read failure'
run_ci 1 ci --reset
[ ! -s "$checkout/tasks.log" ] || fail 'tasks ran despite a checkpoint write failure'
rmdir "$checkpoint"

echo 'PASS: Linux CI task checkpoint/resume integration tests'