Files
lean4/tests/elab/async_sleep.lean
Garmelon 08eb78a5b2 chore: switch to new test/bench suite (#12590)
This PR sets up the new integrated test/bench suite. It then migrates
all benchmarks and some related tests to the new suite. There's also
some documentation and some linting.

For now, a lot of the old tests are left alone so this PR doesn't become
even larger than it already is. Eventually, all tests should be migrated
to the new suite though so there isn't a confusing mix of two systems.
2026-02-25 13:51:53 +00:00

394 lines
11 KiB
Lean4
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Std.Internal.UV
open Std.Internal.UV
def assertElapsed (t1 t2 : Nat) (should : Nat) (eps : Nat) : IO Unit := do
let dur := t2 - t1
if (Int.ofNat dur - Int.ofNat should).natAbs > eps then
throw <| .userError s!"elapsed time was too different, measured {dur}, should: {should}, tolerance: {eps}"
def assertDuration (should : Nat) (eps : Nat) (x : IO α) : IO α := do
let t1 IO.monoMsNow
let res x
let t2 IO.monoMsNow
assertElapsed t1 t2 should eps
return res
def BASE_DURATION : Nat := 1000
-- generous tolerance for slow CI systems
def EPS : Nat := 150
def await (x : Task α) : IO α := pure x.get
namespace SleepTest
def oneShotSleep : IO Unit := do
assertDuration BASE_DURATION EPS do
let timer Timer.mk BASE_DURATION.toUInt64 false
let p timer.next
await p.result!
def promiseBehavior1 : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 false
let p timer.next
let r := p.result!
assert! ( IO.getTaskState r) != .finished
IO.sleep (BASE_DURATION + EPS).toUInt32
assert! ( IO.getTaskState r) == .finished
def promiseBehavior2 : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 false
let p1 timer.next
let p2 timer.next
assert! ( IO.getTaskState p1.result!) != .finished
assert! ( IO.getTaskState p2.result!) != .finished
IO.sleep (BASE_DURATION + EPS).toUInt32
assert! ( IO.getTaskState p1.result!) == .finished
assert! ( IO.getTaskState p2.result!) == .finished
def promiseBehavior3 : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 false
let p1 timer.next
assert! ( IO.getTaskState p1.result!) != .finished
IO.sleep (BASE_DURATION + EPS).toUInt32
assert! ( IO.getTaskState p1.result!) == .finished
let p3 timer.next
assert! ( IO.getTaskState p3.result!) == .finished
def resetBehavior : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 false
let p timer.next
assert! ( IO.getTaskState p.result!) != .finished
IO.sleep (BASE_DURATION / 2).toUInt32
assert! ( IO.getTaskState p.result!) != .finished
timer.reset
IO.sleep (BASE_DURATION / 2).toUInt32
assert! ( IO.getTaskState p.result!) != .finished
IO.sleep ((BASE_DURATION / 2) + EPS).toUInt32
assert! ( IO.getTaskState p.result!) == .finished
def cancelBehaviorNoRepeat : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 false
let prom timer.next
assert! ( IO.getTaskState prom.result?) != IO.TaskState.finished
timer.cancel
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
def stopBehaviorNoRepeat : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 false
let prom timer.next
assert! ( IO.getTaskState prom.result?) != IO.TaskState.finished
timer.stop
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
assert! prom.result?.get == none
let prom timer.next
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
assert! prom.result?.get == none
let prom timer.next
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
assert! prom.result?.get == none
let prom timer.next
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
assert! prom.result?.get == none
let prom timer.next
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
assert! prom.result?.get == none
def stopCancelNoRepeat : IO Unit := do
let timer Timer.mk 1000 false
let prom timer.next
timer.stop
timer.cancel
timer.stop
timer.cancel
timer.stop
timer.cancel
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
assert! prom.result?.get == none
def cancelStopNoRepeat : IO Unit := do
let timer Timer.mk 1000 false
let prom timer.next
timer.cancel
timer.stop
timer.cancel
timer.stop
timer.cancel
timer.stop
timer.cancel
timer.stop
IO.sleep EPS.toUInt32
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
assert! prom.result?.get == none
def stopNoRepeat : IO Unit := do
let timer Timer.mk 1000 false
let prom timer.next
timer.stop
assert! prom.result?.get == none
let prom timer.next
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
assert! prom.result?.get == none
def cancelNoRepeat : IO Unit := do
let timer Timer.mk 1000 false
timer.cancel
let prom timer.next
assert! prom.result?.get == some ()
#eval cancelBehaviorNoRepeat
#eval stopBehaviorNoRepeat
#eval stopCancelNoRepeat
#eval cancelStopNoRepeat
#eval stopNoRepeat
#eval cancelNoRepeat
#eval oneShotSleep
#eval promiseBehavior1
#eval promiseBehavior2
#eval promiseBehavior3
#eval resetBehavior
#eval oneShotSleep
end SleepTest
namespace IntervalTest
def sleepFirst : IO Unit := do
assertDuration 0 EPS go
where
go : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 true
let prom timer.next
await prom.result!
timer.stop
def sleepSecond : IO Unit := do
discard <| assertDuration BASE_DURATION EPS go
where
go : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 true
let task
IO.bindTask ( timer.next).result! fun _ => do
IO.bindTask ( timer.next).result! fun _ => pure (Task.pure (.ok 2))
discard <| await task
timer.stop
def promiseBehavior1 : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 true
let p1 timer.next
IO.sleep EPS.toUInt32
assert! ( IO.getTaskState p1.result!) == .finished
let p2 timer.next
assert! ( IO.getTaskState p2.result!) != .finished
IO.sleep (BASE_DURATION + EPS).toUInt32
assert! ( IO.getTaskState p2.result!) == .finished
timer.stop
def promiseBehavior2 : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 true
let p1 timer.next
IO.sleep EPS.toUInt32
assert! ( IO.getTaskState p1.result!) == .finished
let prom1 timer.next
let prom2 timer.next
assert! ( IO.getTaskState prom1.result!) != .finished
assert! ( IO.getTaskState prom2.result!) != .finished
IO.sleep (BASE_DURATION + EPS).toUInt32
assert! ( IO.getTaskState prom1.result!) == .finished
assert! ( IO.getTaskState prom2.result!) == .finished
timer.stop
def promiseBehavior3 : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 true
let p1 timer.next
IO.sleep EPS.toUInt32
assert! ( IO.getTaskState p1.result!) == .finished
let prom1 timer.next
assert! ( IO.getTaskState prom1.result!) != .finished
IO.sleep (BASE_DURATION + EPS).toUInt32
assert! ( IO.getTaskState prom1.result!) == .finished
let prom2 timer.next
assert! ( IO.getTaskState prom2.result!) != .finished
IO.sleep (BASE_DURATION + EPS).toUInt32
assert! ( IO.getTaskState prom2.result!) == .finished
timer.stop
def delayedTickBehavior : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 true
let p1 timer.next
IO.sleep EPS.toUInt32
assert! ( IO.getTaskState p1.result!) == .finished
IO.sleep (BASE_DURATION / 2).toUInt32
let p2 timer.next
assert! ( IO.getTaskState p2.result!) != .finished
IO.sleep ((BASE_DURATION / 2) + EPS).toUInt32
assert! ( IO.getTaskState p2.result!) == .finished
timer.stop
def skippedTickBehavior : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 true
let p1 timer.next
IO.sleep EPS.toUInt32
assert! ( IO.getTaskState p1.result!) == .finished
IO.sleep (2 * BASE_DURATION + BASE_DURATION / 2).toUInt32
let p2 timer.next
assert! ( IO.getTaskState p2.result!) != .finished
IO.sleep ((BASE_DURATION / 2) + EPS).toUInt32
assert! ( IO.getTaskState p2.result!) == .finished
timer.stop
def resetBehavior : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 true
let p1 timer.next
IO.sleep EPS.toUInt32
assert! ( IO.getTaskState p1.result!) == .finished
let prom timer.next
assert! ( IO.getTaskState prom.result!) != .finished
IO.sleep (BASE_DURATION / 2).toUInt32
assert! ( IO.getTaskState prom.result!) != .finished
timer.reset
IO.sleep (BASE_DURATION / 2).toUInt32
assert! ( IO.getTaskState prom.result!) != .finished
IO.sleep ((BASE_DURATION / 2) + EPS).toUInt32
assert! ( IO.getTaskState prom.result!) == .finished
timer.stop
def sequentialSleep : IO Unit := do
discard <| assertDuration BASE_DURATION EPS go
where
go : IO Unit := do
let timer Timer.mk (BASE_DURATION / 2).toUInt64 true
-- 0th interval ticks instantly
let task
IO.bindTask ( timer.next).result! fun _ => do
IO.bindTask ( timer.next).result! fun _ => do
IO.bindTask ( timer.next).result! fun _ => pure (Task.pure (.ok 2))
discard <| await task
timer.stop
def cancelBehaviorRepeat : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 true
let prom timer.next
IO.sleep EPS.toUInt32
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
let prom timer.next
IO.sleep EPS.toUInt32
assert! ( IO.getTaskState prom.result?) != IO.TaskState.finished
timer.cancel
IO.sleep EPS.toUInt32
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
let prom timer.next
IO.sleep EPS.toUInt32
assert! ( IO.getTaskState prom.result?) != IO.TaskState.finished
timer.cancel
IO.sleep EPS.toUInt32
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
assert! prom.result?.get == none
def stopBehaviorRepeat : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 true
let prom timer.next
IO.sleep EPS.toUInt32
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
let prom timer.next
IO.sleep EPS.toUInt32
assert! ( IO.getTaskState prom.result?) != IO.TaskState.finished
timer.stop
IO.sleep EPS.toUInt32
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
assert! prom.result?.get == none
def stopCancelRepeat : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 true
let prom timer.next
assert! prom.result?.get == some ()
let prom timer.next
timer.stop
timer.cancel
timer.stop
timer.cancel
timer.stop
timer.cancel
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
assert! prom.result?.get == none
def cancelStopRepeat : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 true
let prom timer.next
assert! prom.result?.get == some ()
let prom timer.next
timer.cancel
timer.stop
timer.cancel
timer.stop
timer.cancel
timer.stop
timer.cancel
timer.stop
IO.sleep EPS.toUInt32
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
assert! prom.result?.get == none
def stopRepeat : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 true
let prom timer.next
assert! prom.result?.get == some ()
timer.stop
let prom timer.next
assert! ( IO.getTaskState prom.result?) == IO.TaskState.finished
assert! prom.result?.get == none
def cancelRepeat : IO Unit := do
let timer Timer.mk BASE_DURATION.toUInt64 true
timer.cancel
let prom timer.next
assert! prom.result?.get == some ()
#eval cancelBehaviorRepeat
#eval stopBehaviorRepeat
#eval stopCancelRepeat
#eval cancelStopRepeat
#eval stopRepeat
#eval cancelRepeat
#eval sleepFirst
#eval sleepSecond
#eval promiseBehavior1
#eval promiseBehavior2
#eval promiseBehavior3
#eval delayedTickBehavior
#eval skippedTickBehavior
#eval resetBehavior
#eval sequentialSleep
end IntervalTest