lean4-htt/tests/server_interactive/cancellation_par.lean
Joachim Breitner 0c6785c68f
test: simplify cancellation_par test infrastructure (#13663)
This PR replaces the `check_cancel` two-way coordination protocol used
by
`tests/server_interactive/cancellation_par.lean` with a single tactic
`block_until_cancelled "<label>"`. The first invocation for a label
registers
a promise, prints `<label>: blocked`, and loops on
`Core.checkInterrupted`
until the cancel token fires (then `finally` resolves the promise). Any
later
invocation for the same label waits on that promise — so the test only
terminates if the first invocation actually exited the loop. If
cancellation
fails to propagate, the second invocation's `IO.wait` blocks forever and
the
test hangs (timeout = failure), with no false-success path.

The test was disabled in `tests/CMakeLists.txt` due to flakiness in the
old
two-way protocol; this PR re-enables it. Verified that reverting #13428
makes the test deadlock as expected.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 19:10:35 +00:00

65 lines
1.8 KiB
Text

import Lean.Server.Test.Cancel
open Lean.Server.Test.Cancel
/-!
Test that cancellation propagates into parallel tactic combinators (`attempt_all_par`,
`first_par`).
Each section's first elaboration runs `block_until_cancelled "<label>"`, which loops on
`Core.checkInterrupted`. The test driver edits the preceding `example` to trigger
re-elaboration; the second elaboration's invocation no-ops (label already seen) so the test can
terminate. If cancellation reaches the (possibly subtask) tactic, the loop throws and the test
completes; if not, the test hangs and the runner times out.
Section 1 uses sequential `first` (cancellation has always worked here — runs on the main
elaboration thread). Sections 2 and 3 use `attempt_all_par` and `first_par`, which spawn the
tactic on a fresh `asTask` cancel token; before the propagation fix in `CoreM.asTask`, those
tasks would not see the parent's cancellation and the test would hang.
-/
/-! ## Sequential `first` -/
example : True := by
trivial
--^ waitFor: blocked
--^ insert: "; skip"
--^ sync
theorem t : True := by
wait_for_cancel_once_async
try? => first
| block_until_cancelled "first"
-- RESET
import Lean.Server.Test.Cancel
open Lean.Server.Test.Cancel
/-! ## Parallel `attempt_all_par` -/
example : True := by
trivial
--^ waitFor: blocked
--^ insert: "; skip"
--^ sync
theorem t : True := by
wait_for_cancel_once_async
try? => attempt_all_par
| block_until_cancelled "attempt_all_par"
-- RESET
import Lean.Server.Test.Cancel
open Lean.Server.Test.Cancel
/-! ## Parallel `first_par` -/
example : True := by
trivial
--^ waitFor: blocked
--^ insert: "; skip"
--^ sync
theorem t : True := by
wait_for_cancel_once_async
try? => first_par
| block_until_cancelled "first_par"