def test_pinger_picks_up_on_interval_change(self): interval = get_timeout(0.1) interval2 = get_timeout(0.3) self.p.ping_interval = timedelta(seconds=interval) with contextlib.ExitStack() as stack: ping = stack.enter_context( unittest.mock.patch( "aioxmpp.ping.ping", new=CoroutineMock(), )) self.p.start() run_coroutine(asyncio.sleep(interval / 2)) self._require_task_running() ping.assert_called_once_with(self.cc, unittest.mock.sentinel.ping_address) ping.reset_mock() self.p.ping_interval = timedelta(seconds=interval2) import time run_coroutine(asyncio.sleep(interval2)) self._require_task_running() print(time.monotonic(), "slept") ping.assert_called_once_with( self.cc, unittest.mock.sentinel.ping_address, ) ping.reset_mock()
def test_pinger_skips_ping_emission_if_client_is_suspended(self): timeout = get_timeout(0.1) self.assertFalse(self.cc.suspended) self.p.ping_interval = timedelta(seconds=timeout) with contextlib.ExitStack() as stack: ping = stack.enter_context( unittest.mock.patch( "aioxmpp.ping.ping", new=CoroutineMock(), )) self.p.start() run_coroutine(asyncio.sleep(timeout / 2)) for i in range(2): self._require_task_running() ping.assert_called_once_with( self.cc, unittest.mock.sentinel.ping_address) ping.reset_mock() # we need to change the suspended flag here, because the next # sleep covers the next ping sending if i == 1: self.cc.suspended = True run_coroutine(asyncio.sleep(timeout)) for i in range(2): print(i) self._require_task_running() ping.assert_not_called() if i == 1: self.cc.suspended = False
def test_pinger_uses_jitter_to_calculate_next(self): timeout = get_timeout(0.1) self.p.ping_interval = timedelta(seconds=timeout) self.jitter_mock.return_value = timeout * 2 self.jitter_mock.side_effect = None with contextlib.ExitStack() as stack: ping = stack.enter_context( unittest.mock.patch( "aioxmpp.ping.ping", new=CoroutineMock(), )) self.p.start() run_coroutine(asyncio.sleep(timeout / 2)) self._require_task_running() ping.assert_called_once_with(self.cc, unittest.mock.sentinel.ping_address) ping.reset_mock() run_coroutine(asyncio.sleep(timeout * 2)) self._require_task_running() ping.assert_called_once_with(self.cc, unittest.mock.sentinel.ping_address) ping.reset_mock()
def test_pinger_cancels_futures_on_cancel(self): interval = get_timeout(0.1) futures = [] def ping(*args, **kwargs): fut = asyncio.Future() futures.append(fut) return fut self.p.ping_interval = timedelta(seconds=interval) self.p.ping_timeout = timedelta(seconds=interval * 10) with contextlib.ExitStack() as stack: ping = stack.enter_context( unittest.mock.patch( "aioxmpp.ping.ping", new=unittest.mock.Mock(side_effect=ping, ), )) self.p.start() run_coroutine(asyncio.sleep(interval / 2)) # we check that, at any time, at most four futures # (timeout/interval) are not cancelled for i in range(5): self._require_task_running() run_coroutine(asyncio.sleep(interval)) self.p.stop() run_coroutine(asyncio.sleep(interval / 2)) self.assertTrue(all(fut.done() for fut in futures))
def test_pinger_picks_up_on_timeout_change(self): interval = get_timeout(0.3) timeout = get_timeout(0.3) futures = [] def ping_func(*args, **kwargs): fut = asyncio.Future() futures.append(fut) return fut self.p.ping_interval = timedelta(seconds=interval) self.p.ping_timeout = timedelta(seconds=interval * 10) with contextlib.ExitStack() as stack: ping = stack.enter_context( unittest.mock.patch( "aioxmpp.ping.ping", new=unittest.mock.Mock(side_effect=ping_func, ), )) self.p.start() run_coroutine(asyncio.sleep(interval / 2)) self._require_task_running() ping.assert_called_once_with(self.cc, unittest.mock.sentinel.ping_address) ping.reset_mock() self.p.ping_timeout = timedelta(seconds=timeout) run_coroutine(asyncio.sleep(interval)) self._require_task_running() self.assertEqual(len(futures), 2) run_coroutine(asyncio.sleep(interval)) self._require_task_running() self.assertEqual(len(futures), 3) run_coroutine(asyncio.sleep(interval / 2)) self.assertFalse(futures[0].done()) self.assertTrue(futures[1].done()) self.assertTrue(futures[2].done())
def test_changing_soft_limit_may_emit_limit_immediately(self): dt = get_timeout(timedelta(seconds=0.1)) self.am.notify_received() run_coroutine(asyncio.sleep((dt*1.1).total_seconds())) self.listener.on_deadtime_soft_limit_tripped.assert_not_called() self.am.deadtime_soft_limit = dt run_coroutine(asyncio.sleep(0)) self.listener.on_deadtime_soft_limit_tripped.assert_called_once_with()
def test_hard_timer_fires_even_without_any_reception(self): dt = get_timeout(timedelta(seconds=0.1)) self.am.deadtime_hard_limit = dt run_coroutine(asyncio.sleep((dt * 0.9).total_seconds())) self.listener.on_deadtime_hard_limit_tripped.assert_not_called() run_coroutine(asyncio.sleep((dt * 0.2).total_seconds())) self.listener.on_deadtime_hard_limit_tripped.assert_called_once_with()
def test_hard_limit_trips(self): dt = get_timeout(timedelta(seconds=0.1)) self.am.deadtime_hard_limit = dt self.am.notify_received() run_coroutine(asyncio.sleep((dt * 0.9).total_seconds())) self.listener.on_deadtime_hard_limit_tripped.assert_not_called() run_coroutine(asyncio.sleep((dt * 0.2).total_seconds())) self.listener.on_deadtime_hard_limit_tripped.assert_called_once_with()
def test_hard_limit_can_reemit_after_reception(self): dt = get_timeout(timedelta(seconds=0.1)) self.am.deadtime_hard_limit = dt self.am.notify_received() run_coroutine(asyncio.sleep((dt*1.1).total_seconds())) self.listener.on_deadtime_hard_limit_tripped.assert_called_once_with() self.am.notify_received() self.listener.on_deadtime_hard_limit_tripped.reset_mock() run_coroutine(asyncio.sleep((dt*1.1).total_seconds())) self.listener.on_deadtime_hard_limit_tripped.assert_called_once_with()
def test_pinger_cancels_after_ping_timeout(self): interval = get_timeout(0.1) timeout = get_timeout(0.4) futures = [] def ping_func(*args, **kwargs): fut = asyncio.Future() futures.append(fut) return fut self.p.ping_interval = timedelta(seconds=interval) self.p.ping_timeout = timedelta(seconds=timeout) with contextlib.ExitStack() as stack: ping = stack.enter_context( unittest.mock.patch( "aioxmpp.ping.ping", new=unittest.mock.Mock(side_effect=ping_func, ), )) self.p.start() run_coroutine(asyncio.sleep(interval / 2)) # we check that, at any time, at most four futures # (timeout/interval) are not cancelled for i in range(10): self._require_task_running() ping.assert_called_once_with( self.cc, unittest.mock.sentinel.ping_address) ping.reset_mock() self.assertLessEqual( sum(not fut.done() for fut in futures), 4, ) run_coroutine(asyncio.sleep(interval))
def test_changing_soft_limit_recaluclates_timer(self): dt = get_timeout(timedelta(seconds=0.1)) self.am.deadtime_soft_limit = dt self.am.notify_received() run_coroutine(asyncio.sleep((dt * 0.9).total_seconds())) self.listener.on_deadtime_soft_limit_tripped.assert_not_called() self.am.deadtime_soft_limit = dt*1.5 run_coroutine(asyncio.sleep((dt * 0.5).total_seconds())) self.listener.on_deadtime_soft_limit_tripped.assert_not_called() run_coroutine(asyncio.sleep((dt * 0.2).total_seconds())) self.listener.on_deadtime_soft_limit_tripped.assert_called_once_with()
def test_pinger_emits_ping_every_ping_interval(self): timeout = get_timeout(0.1) self.p.ping_interval = timedelta(seconds=timeout) with contextlib.ExitStack() as stack: ping = stack.enter_context( unittest.mock.patch( "aioxmpp.ping.ping", new=CoroutineMock(), )) self.p.start() run_coroutine(asyncio.sleep(timeout / 2)) for i in range(5): self._require_task_running() ping.assert_called_once_with( self.cc, unittest.mock.sentinel.ping_address) ping.reset_mock() run_coroutine(asyncio.sleep(timeout))
def test_pinger_calls__interpret_result_for_finished_pings(self): interval = get_timeout(0.1) timeout = get_timeout(0.16) modes = [ False, None, RuntimeError(), ] futures = [] mode_i = 0 def ping_func(*args, **kwargs): def make_fut(): fut = asyncio.Future() futures.append(fut) return fut nonlocal mode_i mode = modes[mode_i] mode_i += 1 fut = make_fut() if mode is None: fut.set_result(unittest.mock.sentinel.some_result) elif mode is False: pass else: fut.set_exception(mode) return fut self.p.ping_interval = timedelta(seconds=interval) self.p.ping_timeout = timedelta(seconds=timeout) with contextlib.ExitStack() as stack: ping = stack.enter_context( unittest.mock.patch( "aioxmpp.ping.ping", new=unittest.mock.Mock(side_effect=ping_func, ), )) _interpret_result = stack.enter_context( unittest.mock.patch.object(self.p, "_interpret_result")) self.p.start() logging.debug("test: sleeping for %s", interval / 2) run_coroutine(asyncio.sleep(interval / 2)) # t_interval = 0.025 / 0.05, t_timeout = 0.025 / 0.08 self.assertEqual(len(futures), 1) self.assertFalse(futures[0].done()) logging.debug("test: sleeping for %s", interval * 0.6) run_coroutine(asyncio.sleep(interval * 0.6)) # t_interval = 0.005 / 0.05, t_timeout = 0.055 / 0.08 self.assertEqual(len(futures), 2) self.assertFalse(futures[0].done()) self.assertTrue(futures[1].done()) logging.debug("test: verifying") _interpret_result.assert_called_once_with(unittest.mock.ANY) _, (fut, ), _ = _interpret_result.mock_calls[0] self.assertEqual(fut.result(), futures[1].result()) _interpret_result.reset_mock() logging.debug("test: sleeping for %s", interval * 0.6) run_coroutine(asyncio.sleep(interval * 0.6)) # t_interval = 0.035 / 0.05, t_timeout = 0.085 / 0.08 self.assertEqual(len(futures), 2) self.assertTrue(futures[0].done()) self.assertTrue(futures[1].done()) _interpret_result.assert_called_once_with(unittest.mock.ANY) _, (fut, ), _ = _interpret_result.mock_calls[0] self.assertEqual(len(futures), 2) self.assertTrue(futures[0].cancelled()) self.assertTrue(futures[0].done()) self.assertIsInstance(fut.exception(), asyncio.TimeoutError) _interpret_result.reset_mock() run_coroutine(asyncio.sleep(interval * 0.8)) # t_interval = 0.025 / 0.05 self.assertEqual(len(futures), 3) self.assertTrue(futures[2].done()) _interpret_result.assert_called_once_with(unittest.mock.ANY) _, (fut, ), _ = _interpret_result.mock_calls[0] self.assertIs(fut.exception(), futures[2].exception()) self.assertIsNotNone(fut.exception()) _interpret_result.reset_mock()