from math import inf import time import pytest from trio import sleep from ... import _core from .. import wait_all_tasks_blocked from .._mock_clock import MockClock from .tutil import slow def test_mock_clock(): REAL_NOW = 123.0 c = MockClock() c._real_clock = lambda: REAL_NOW repr(c) # smoke test assert c.rate == 0 assert c.current_time() == 0 c.jump(1.2) assert c.current_time() == 1.2 with pytest.raises(ValueError): c.jump(-1) assert c.current_time() == 1.2 assert c.deadline_to_sleep_time(1.1) == 0 assert c.deadline_to_sleep_time(1.2) == 0 assert c.deadline_to_sleep_time(1.3) > 999999 with pytest.raises(ValueError): c.rate = -1 assert c.rate == 0 c.rate = 2 assert c.current_time() == 1.2 REAL_NOW += 1 assert c.current_time() == 3.2 assert c.deadline_to_sleep_time(3.1) == 0 assert c.deadline_to_sleep_time(3.2) == 0 assert c.deadline_to_sleep_time(4.2) == 0.5 c.rate = 0.5 assert c.current_time() == 3.2 assert c.deadline_to_sleep_time(3.1) == 0 assert c.deadline_to_sleep_time(3.2) == 0 assert c.deadline_to_sleep_time(4.2) == 2.0 c.jump(0.8) assert c.current_time() == 4.0 REAL_NOW += 1 assert c.current_time() == 4.5 c2 = MockClock(rate=3) assert c2.rate == 3 assert c2.current_time() < 10 async def test_mock_clock_autojump(mock_clock): assert mock_clock.autojump_threshold == inf mock_clock.autojump_threshold = 0 assert mock_clock.autojump_threshold == 0 real_start = time.perf_counter() virtual_start = _core.current_time() for i in range(10): print("sleeping {} seconds".format(10 * i)) await sleep(10 * i) print("woke up!") assert virtual_start + 10 * i == _core.current_time() virtual_start = _core.current_time() real_duration = time.perf_counter() - real_start print("Slept {} seconds in {} seconds".format(10 * sum(range(10)), real_duration)) assert real_duration < 1 mock_clock.autojump_threshold = 0.02 t = _core.current_time() # this should wake up before the autojump threshold triggers, so time # shouldn't change await wait_all_tasks_blocked() assert t == _core.current_time() # this should too await wait_all_tasks_blocked(0.01) assert t == _core.current_time() # set up a situation where the autojump task is blocked for a long long # time, to make sure that cancel-and-adjust-threshold logic is working mock_clock.autojump_threshold = 10000 await wait_all_tasks_blocked() mock_clock.autojump_threshold = 0 # if the above line didn't take affect immediately, then this would be # bad: await sleep(100000) async def test_mock_clock_autojump_interference(mock_clock): mock_clock.autojump_threshold = 0.02 mock_clock2 = MockClock() # messing with the autojump threshold of a clock that isn't actually # installed in the run loop shouldn't do anything. mock_clock2.autojump_threshold = 0.01 # if the autojump_threshold of 0.01 were in effect, then the next line # would block forever, as the autojump task kept waking up to try to # jump the clock. await wait_all_tasks_blocked(0.015) # but the 0.02 limit does apply await sleep(100000) def test_mock_clock_autojump_preset(): # Check that we can set the autojump_threshold before the clock is # actually in use, and it gets picked up mock_clock = MockClock(autojump_threshold=0.1) mock_clock.autojump_threshold = 0.01 real_start = time.perf_counter() _core.run(sleep, 10000, clock=mock_clock) assert time.perf_counter() - real_start < 1 async def test_mock_clock_autojump_0_and_wait_all_tasks_blocked_0(mock_clock): # Checks that autojump_threshold=0 doesn't interfere with # calling wait_all_tasks_blocked with the default cushion=0. mock_clock.autojump_threshold = 0 record = [] async def sleeper(): await sleep(100) record.append("yawn") async def waiter(): await wait_all_tasks_blocked() record.append("waiter woke") await sleep(1000) record.append("waiter done") async with _core.open_nursery() as nursery: nursery.start_soon(sleeper) nursery.start_soon(waiter) assert record == ["waiter woke", "yawn", "waiter done"] @slow async def test_mock_clock_autojump_0_and_wait_all_tasks_blocked_nonzero(mock_clock): # Checks that autojump_threshold=0 doesn't interfere with # calling wait_all_tasks_blocked with a non-zero cushion. mock_clock.autojump_threshold = 0 record = [] async def sleeper(): await sleep(100) record.append("yawn") async def waiter(): await wait_all_tasks_blocked(1) record.append("waiter done") async with _core.open_nursery() as nursery: nursery.start_soon(sleeper) nursery.start_soon(waiter) assert record == ["waiter done", "yawn"]