63 lines
3.5 KiB
Bash
Executable file
63 lines
3.5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# P8-REVIEW axis 3 — the six mutations of the report, planted and restored one at a time.
|
|
# Run ONLY against a COPY of the platform tree.
|
|
#
|
|
# PLATFORM=/path/to/copy/platform TM_PLATFORM_TEST_DSN=... ./mutations.sh M1|M2|M3|M4|M5|M6|restore
|
|
set -euo pipefail
|
|
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
PLATFORM="${PLATFORM:-$HERE/../platform}"
|
|
BAK="${BAK:-$HERE/.mutation-backup}"
|
|
# ⚠ Дописано при сдаче пака: гард против живого репозитория, по образцу axis2/mutations-axis2.sh.
|
|
case "$PLATFORM" in *projects/textmachine*) echo "refusing to mutate the live repository"; exit 2;; esac
|
|
|
|
mkdir -p "$BAK"
|
|
save() { for f in "$@"; do mkdir -p "$BAK/$(dirname "$f")"; [ -f "$BAK/$f" ] || cp "$PLATFORM/$f" "$BAK/$f"; done; }
|
|
case "${1:?M1|M2|M3|M4|M5|M6|restore}" in
|
|
M1) # the two phases stop having separate shares of the pass (mechanism 1)
|
|
save internal/runs/reconcile.go
|
|
sed -i 's#return context.WithTimeout(ctx, time.Until(deadline)/2)#return context.WithTimeout(ctx, time.Until(deadline)) // MUTATION M1#' \
|
|
"$PLATFORM/internal/runs/reconcile.go" ;;
|
|
M2) # the sweep's list stops honouring the deferral (mechanism 2, read side)
|
|
save internal/pgstore/runs.go
|
|
python3 - "$PLATFORM" <<'PY'
|
|
import sys
|
|
p=sys.argv[1]+'/internal/pgstore/runs.go'; L=open(p).read().split('\n')
|
|
i=[n for n,l in enumerate(L) if 'a.reconcile_after is null or a.reconcile_after <= $1' in l][0]
|
|
L[i]="\t\t and ($1::timestamptz is not null) -- MUTATION M2"; L[i+1]="\t\t and true"
|
|
open(p,'w').write('\n'.join(L))
|
|
PY
|
|
;;
|
|
M3) # the settlement phase stops deferring an item that spent its budget (mechanism 2, write side)
|
|
save internal/runs/reconcile.go
|
|
python3 - "$PLATFORM" <<'PY'
|
|
import sys
|
|
p=sys.argv[1]+'/internal/runs/reconcile.go'; s=open(p).read()
|
|
old='\tc, cancel := context.WithTimeout(context.WithoutCancel(ctx), recordBudget)\n\tdefer cancel()\n\ts.deferItem(c, u, "the settlement took its whole budget without finishing")\n}'
|
|
assert old in s
|
|
open(p,'w').write(s.replace(old,'\t_ = recordBudget // MUTATION M3\n}'))
|
|
PY
|
|
;;
|
|
M4) # the readmodel pass's budget drops below ONE book's budget (the unpinned pair)
|
|
save cmd/tmplatformd/runner.go
|
|
sed -i 's#const refreshSweepBudget = 10 \* time.Minute#const refreshSweepBudget = 1 * time.Minute // MUTATION M4#' \
|
|
"$PLATFORM/cmd/tmplatformd/runner.go" ;;
|
|
M5) # the reading-surface lease becomes a tenth of the work it covers
|
|
save internal/readmodel/readmodel.go
|
|
sed -i 's#ClaimReadModelDebt(ctx, b.ID, b.OwedAt, MaterializeBudget)#ClaimReadModelDebt(ctx, b.ID, b.OwedAt, MaterializeBudget/10) // MUTATION M5#' \
|
|
"$PLATFORM/internal/readmodel/readmodel.go" ;;
|
|
M6) # the runs pass is no longer FIRST in the tick
|
|
save cmd/tmplatformd/runner.go
|
|
python3 - "$PLATFORM" <<'PY'
|
|
import sys
|
|
p=sys.argv[1]+'/cmd/tmplatformd/runner.go'; s=open(p).read()
|
|
a='\tone := func() {\n\t\tpass("runs", sweepBudget, s.runs.Sweep)\n'
|
|
assert a in s; s=s.replace(a,'\tone := func() { // MUTATION M6: the runs pass is last\n')
|
|
b='\t\tc, cancel := context.WithTimeout(ctx, sweepBudget)\n\t\tdefer cancel()\n\t\tobserve(c, s, log)'
|
|
assert b in s
|
|
open(p,'w').write(s.replace(b,'\t\tpass("runs", sweepBudget, s.runs.Sweep) // MUTATION M6\n'+b))
|
|
PY
|
|
;;
|
|
restore) cd "$BAK" && find . -name '*.go' -exec cp --parents {} "$PLATFORM/" \; && rm -rf "$BAK" && echo restored; exit 0 ;;
|
|
esac
|
|
cd "$PLATFORM" && gofmt -w $(cd "$BAK" && find . -name '*.go') 2>/dev/null || true
|
|
go build ./... && echo "$1 planted"
|