def test_cancel_unexpired_timeout_from_another_timeout(self): now = test_now() bucket = [] timer = select_connection._Timer() with mock.patch('pika.compat.time_now', return_value=now): t2 = timer.call_later(10, lambda: bucket.append(2)) t1 = timer.call_later(5, lambda: timer.remove_timeout(t2)) self.assertIs(t1, timer._timeout_heap[0]) # Advance time by 6 seconds and check that t2 is cancelled, but not # removed from timeout heap with mock.patch('pika.compat.time_now', return_value=now + 6): timer.process_timeouts() self.assertIsNone(t2.callback) self.assertEqual(timer.get_remaining_interval(), 4) self.assertIs(t2, timer._timeout_heap[0]) self.assertEqual(timer._num_cancellations, 1) # Advance time by 10 seconds and verify that t2 is removed without # firing with mock.patch('pika.compat.time_now', return_value=now + 10): timer.process_timeouts() self.assertEqual(bucket, []) self.assertIsNone(timer.get_remaining_interval()) self.assertEqual(len(timer._timeout_heap), 0) self.assertEqual(timer._num_cancellations, 0)
def test_gc_of_unexpired_timeouts(self): now = test_now() bucket = [] timer = select_connection._Timer() with mock.patch.multiple(select_connection._Timer, _GC_CANCELLATION_THRESHOLD=1): with mock.patch('pika.compat.time_now', return_value=now): t3 = timer.call_later(10, lambda: bucket.append(3)) t2 = timer.call_later(6, lambda: bucket.append(2)) t1 = timer.call_later(5, lambda: bucket.append(1)) # Cancel t1 and check that it doesn't trigger GC because it's # not greater than half the timeouts timer.remove_timeout(t1) self.assertEqual(timer._num_cancellations, 1) timer.process_timeouts() self.assertEqual(timer._num_cancellations, 1) self.assertEqual(bucket, []) self.assertEqual(len(timer._timeout_heap), 3) self.assertEqual(timer.get_remaining_interval(), 5) # Cancel t3 and verify GC since it's now greater than half of # total timeouts timer.remove_timeout(t3) self.assertEqual(timer._num_cancellations, 2) timer.process_timeouts() self.assertEqual(bucket, []) self.assertEqual(len(timer._timeout_heap), 1) self.assertIs(t2, timer._timeout_heap[0]) self.assertEqual(timer.get_remaining_interval(), 6) self.assertEqual(timer._num_cancellations, 0)
def test_add_timeout_from_another_timeout(self): now = test_now() bucket = [] timer = select_connection._Timer() with mock.patch('pika.compat.time_now', return_value=now): t1 = timer.call_later( 5, lambda: bucket.append( timer.call_later(0, lambda: bucket.append(2)))) # Advance time by 10 seconds and verify that t1 fires and creates t2, # but timer manager defers firing of t2 to next `process_timeouts` in # order to avoid IO starvation with mock.patch('pika.compat.time_now', return_value=now + 10): timer.process_timeouts() t2 = bucket.pop() self.assertIsInstance(t2, select_connection._Timeout) self.assertIsNot(t2, t1) self.assertEqual(bucket, []) self.assertEqual(len(timer._timeout_heap), 1) self.assertIs(t2, timer._timeout_heap[0]) self.assertEqual(timer.get_remaining_interval(), 0) # t2 should now fire timer.process_timeouts() self.assertEqual(bucket, [2]) self.assertEqual(timer.get_remaining_interval(), None)
def test_call_later_multiple_timers(self): now = test_now() bucket = [] timer = select_connection._Timer() with mock.patch('pika.compat.time_now', return_value=now): timer.call_later(5, lambda: bucket.append(1)) timer.call_later(5, lambda: bucket.append(2)) timer.call_later(10, lambda: bucket.append(3)) # Nothing is ready to fire yet self.assertEqual(timer.get_remaining_interval(), 5) timer.process_timeouts() self.assertEqual(bucket, []) self.assertEqual(timer.get_remaining_interval(), 5) # Advance time by 6 seconds and expect first two timers to expire with mock.patch('pika.compat.time_now', return_value=now + 6): self.assertEqual(timer.get_remaining_interval(), 0) timer.process_timeouts() self.assertEqual(bucket, [1, 2]) self.assertEqual(len(timer._timeout_heap), 1) self.assertEqual(timer.get_remaining_interval(), 4) # Advance time by 10 seconds and expect the 3rd timeout to expire with mock.patch('pika.compat.time_now', return_value=now + 10): self.assertEqual(timer.get_remaining_interval(), 0) timer.process_timeouts() self.assertEqual(bucket, [1, 2, 3]) self.assertEqual(len(timer._timeout_heap), 0) self.assertIsNone(timer.get_remaining_interval())
def test_call_later_multiple_timers(self): now = time.time() bucket = [] timer = select_connection._Timer() with mock.patch('time.time', return_value=now): timer.call_later(5, lambda: bucket.append(1)) timer.call_later(5, lambda: bucket.append(2)) timer.call_later(10, lambda: bucket.append(3)) # Nothing is ready to fire yet self.assertEqual(timer.get_remaining_interval(), 5) timer.process_timeouts() self.assertEqual(bucket, []) self.assertEqual(timer.get_remaining_interval(), 5) # Advance time by 6 seconds and expect first two timers to expire with mock.patch('time.time', return_value=now + 6): self.assertEqual(timer.get_remaining_interval(), 0) timer.process_timeouts() self.assertEqual(bucket, [1, 2]) self.assertEqual(len(timer._timeout_heap), 1) self.assertEqual(timer.get_remaining_interval(), 4) # Advance time by 10 seconds and expect the 3rd timeout to expire with mock.patch('time.time', return_value=now + 10): self.assertEqual(timer.get_remaining_interval(), 0) timer.process_timeouts() self.assertEqual(bucket, [1, 2, 3]) self.assertEqual(len(timer._timeout_heap), 0) self.assertIsNone(timer.get_remaining_interval())
def test_add_timeout_from_another_timeout(self): now = time.time() bucket = [] timer = select_connection._Timer() with mock.patch('time.time', return_value=now): t1 = timer.call_later( 5, lambda: bucket.append( timer.call_later(0, lambda: bucket.append(2)))) # Advance time by 10 seconds and verify that t1 fires and creates t2, # but timer manager defers firing of t2 to next `process_timeouts` in # order to avoid IO starvation with mock.patch('time.time', return_value=now + 10): timer.process_timeouts() t2 = bucket.pop() self.assertIsInstance(t2, select_connection._Timeout) self.assertIsNot(t2, t1) self.assertEqual(bucket, []) self.assertEqual(len(timer._timeout_heap), 1) self.assertIs(t2, timer._timeout_heap[0]) self.assertEqual(timer.get_remaining_interval(), 0) # t2 should now fire timer.process_timeouts() self.assertEqual(bucket, [2]) self.assertEqual(timer.get_remaining_interval(), None)
def test_gc_of_unexpired_timeouts(self): now = time.time() bucket = [] timer = select_connection._Timer() with mock.patch.multiple(select_connection._Timer, _GC_CANCELLATION_THRESHOLD=1): with mock.patch('time.time', return_value=now): t3 = timer.call_later(10, lambda: bucket.append(3)) t2 = timer.call_later(6, lambda: bucket.append(2)) t1 = timer.call_later(5, lambda: bucket.append(1)) # Cancel t1 and check that it doesn't trigger GC because it's # not greater than half the timeouts timer.remove_timeout(t1) self.assertEqual(timer._num_cancellations, 1) timer.process_timeouts() self.assertEqual(timer._num_cancellations, 1) self.assertEqual(bucket, []) self.assertEqual(len(timer._timeout_heap), 3) self.assertEqual(timer.get_remaining_interval(), 5) # Cancel t3 and verify GC since it's now greater than half of # total timeouts timer.remove_timeout(t3) self.assertEqual(timer._num_cancellations, 2) timer.process_timeouts() self.assertEqual(bucket, []) self.assertEqual(len(timer._timeout_heap), 1) self.assertIs(t2, timer._timeout_heap[0]) self.assertEqual(timer.get_remaining_interval(), 6) self.assertEqual(timer._num_cancellations, 0)
def test_cancel_unexpired_timeout_from_another_timeout(self): now = time.time() bucket = [] timer = select_connection._Timer() with mock.patch('time.time', return_value=now): t2 = timer.call_later(10, lambda: bucket.append(2)) t1 = timer.call_later(5, lambda: timer.remove_timeout(t2)) self.assertIs(t1, timer._timeout_heap[0]) # Advance time by 6 seconds and check that t2 is cancelled, but not # removed from timeout heap with mock.patch('time.time', return_value=now + 6): timer.process_timeouts() self.assertIsNone(t2.callback) self.assertEqual(timer.get_remaining_interval(), 4) self.assertIs(t2, timer._timeout_heap[0]) self.assertEqual(timer._num_cancellations, 1) # Advance time by 10 seconds and verify that t2 is removed without # firing with mock.patch('time.time', return_value=now + 10): timer.process_timeouts() self.assertEqual(bucket, []) self.assertIsNone(timer.get_remaining_interval()) self.assertEqual(len(timer._timeout_heap), 0) self.assertEqual(timer._num_cancellations, 0)
def start_test(self): timer = select_connection._Timer() poller = select_connection.SelectPoller( get_wait_seconds=timer.get_remaining_interval, process_timeouts=timer.process_timeouts) self.addCleanup(poller.close) timer_call_container = [] timer.call_later(0.00001, lambda: timer_call_container.append(1)) poller.poll() delay = poller._get_wait_seconds() self.assertIsNotNone(delay) deadline = time.time() + delay while True: poller._process_timeouts() if time.time() < deadline: self.assertEqual(timer_call_container, []) else: # One last time in case deadline reached after previous # processing cycle poller._process_timeouts() break self.assertEqual(timer_call_container, [1])
def start_test(self): timer = select_connection._Timer() poller = select_connection.SelectPoller( get_wait_seconds=timer.get_remaining_interval, process_timeouts=timer.process_timeouts) self.addCleanup(poller.close) timer_call_container = [] timer.call_later(0.00001, lambda: timer_call_container.append(1)) poller.poll() delay = poller._get_wait_seconds() self.assertIsNotNone(delay) deadline = pika.compat.time_now() + delay while True: poller._process_timeouts() if pika.compat.time_now() < deadline: self.assertEqual(timer_call_container, []) else: # One last time in case deadline reached after previous # processing cycle poller._process_timeouts() break self.assertEqual(timer_call_container, [1])
def test_close_non_empty(self): timer = select_connection._Timer() t1 = timer.call_later(10, lambda: 10) t2 = timer.call_later(20, lambda: 20) timer.close() self.assertIsNone(timer._timeout_heap) self.assertIsNone(t1.callback) self.assertIsNone(t2.callback)
def setUp(self): select_type_patch = mock.patch.multiple(select_connection, SELECT_TYPE=self.SELECT_POLLER) select_type_patch.start() self.addCleanup(select_type_patch.stop) timer = select_connection._Timer() self.addCleanup(timer.close) self.poller = select_connection.IOLoop._get_poller( timer.get_remaining_interval, timer.process_timeouts) self.addCleanup(self.poller.close)
def setUp(self): select_type_patch = mock.patch.multiple( select_connection, SELECT_TYPE=self.SELECT_POLLER) select_type_patch.start() self.addCleanup(select_type_patch.stop) timer = select_connection._Timer() self.addCleanup(timer.close) self.poller = select_connection.IOLoop._get_poller( timer.get_remaining_interval, timer.process_timeouts) self.addCleanup(self.poller.close)
def test_call_later_non_negative_delay_check(self): now = test_now() # 0 delay is okay with mock.patch('pika.compat.time_now', return_value=now): timer = select_connection._Timer() timer.call_later(0, lambda: None) self.assertEqual(timer._timeout_heap[0].deadline, now) self.assertEqual(timer.get_remaining_interval(), 0) # Positive delay is okay with mock.patch('pika.compat.time_now', return_value=now): timer = select_connection._Timer() timer.call_later(0.5, lambda: None) self.assertEqual(timer._timeout_heap[0].deadline, now + 0.5) self.assertEqual(timer.get_remaining_interval(), 0.5) # Negative delay raises ValueError timer = select_connection._Timer() with self.assertRaises(ValueError) as cm: timer.call_later(-5, lambda: None) self.assertIn('call_later: delay must be non-negative, but got', cm.exception.args[0])
def test_call_later_non_negative_delay_check(self): now = time.time() # 0 delay is okay with mock.patch('time.time', return_value=now): timer = select_connection._Timer() timer.call_later(0, lambda: None) self.assertEqual(timer._timeout_heap[0].deadline, now) self.assertEqual(timer.get_remaining_interval(), 0) # Positive delay is okay with mock.patch('time.time', return_value=now): timer = select_connection._Timer() timer.call_later(0.5, lambda: None) self.assertEqual(timer._timeout_heap[0].deadline, now + 0.5) self.assertEqual(timer.get_remaining_interval(), 0.5) # Negative delay raises ValueError timer = select_connection._Timer() with self.assertRaises(ValueError) as cm: timer.call_later(-5, lambda: None) self.assertIn('call_later: delay must be non-negative, but got', cm.exception.args[0])
def test_add_and_remove_timeout(self): now = time.time() bucket = [] timer = select_connection._Timer() with mock.patch('time.time', return_value=now): timer.call_later(10, lambda: bucket.append(3)) # t3 t2 = timer.call_later(6, lambda: bucket.append(2)) t1 = timer.call_later(5, lambda: bucket.append(1)) # Nothing is ready to fire yet self.assertEqual(timer.get_remaining_interval(), 5) timer.process_timeouts() self.assertEqual(bucket, []) self.assertEqual(timer.get_remaining_interval(), 5) # Cancel t1 and t2 that haven't expired yet timer.remove_timeout(t1) self.assertIsNone(t1.callback) self.assertEqual(timer._num_cancellations, 1) timer.remove_timeout(t2) self.assertIsNone(t2.callback) self.assertEqual(timer._num_cancellations, 2) self.assertEqual(timer.get_remaining_interval(), 5) timer.process_timeouts() self.assertEqual(bucket, []) self.assertEqual(timer._num_cancellations, 2) self.assertEqual(timer.get_remaining_interval(), 5) self.assertEqual(len(timer._timeout_heap), 3) # Advance time by 6 seconds to expire t1 and t2 and verify they don't # fire with mock.patch('time.time', return_value=now + 6): self.assertEqual(timer.get_remaining_interval(), 0) timer.process_timeouts() self.assertEqual(bucket, []) self.assertEqual(timer._num_cancellations, 0) self.assertEqual(len(timer._timeout_heap), 1) self.assertEqual(timer.get_remaining_interval(), 4) # Advance time by 10 seconds to expire t3 and verify it fires with mock.patch('time.time', return_value=now + 10): self.assertEqual(timer.get_remaining_interval(), 0) timer.process_timeouts() self.assertEqual(bucket, [3]) self.assertEqual(len(timer._timeout_heap), 0) self.assertIsNone(timer.get_remaining_interval())
def test_add_and_remove_timeout(self): now = test_now() bucket = [] timer = select_connection._Timer() with mock.patch('pika.compat.time_now', return_value=now): timer.call_later(10, lambda: bucket.append(3)) # t3 t2 = timer.call_later(6, lambda: bucket.append(2)) t1 = timer.call_later(5, lambda: bucket.append(1)) # Nothing is ready to fire yet self.assertEqual(timer.get_remaining_interval(), 5) timer.process_timeouts() self.assertEqual(bucket, []) self.assertEqual(timer.get_remaining_interval(), 5) # Cancel t1 and t2 that haven't expired yet timer.remove_timeout(t1) self.assertIsNone(t1.callback) self.assertEqual(timer._num_cancellations, 1) timer.remove_timeout(t2) self.assertIsNone(t2.callback) self.assertEqual(timer._num_cancellations, 2) self.assertEqual(timer.get_remaining_interval(), 5) timer.process_timeouts() self.assertEqual(bucket, []) self.assertEqual(timer._num_cancellations, 2) self.assertEqual(timer.get_remaining_interval(), 5) self.assertEqual(len(timer._timeout_heap), 3) # Advance time by 6 seconds to expire t1 and t2 and verify they don't # fire with mock.patch('pika.compat.time_now', return_value=now + 6): self.assertEqual(timer.get_remaining_interval(), 0) timer.process_timeouts() self.assertEqual(bucket, []) self.assertEqual(timer._num_cancellations, 0) self.assertEqual(len(timer._timeout_heap), 1) self.assertEqual(timer.get_remaining_interval(), 4) # Advance time by 10 seconds to expire t3 and verify it fires with mock.patch('pika.compat.time_now', return_value=now + 10): self.assertEqual(timer.get_remaining_interval(), 0) timer.process_timeouts() self.assertEqual(bucket, [3]) self.assertEqual(len(timer._timeout_heap), 0) self.assertIsNone(timer.get_remaining_interval())
def test_eintr( self, is_resumable_mock, is_resumable_raw=pika.adapters.select_connection._is_resumable): """Test that poll() is properly restarted after receiving EINTR error. Class of an exception raised to signal the error differs in one implementation of polling mechanism and another.""" is_resumable_mock.side_effect = is_resumable_raw timer = select_connection._Timer() self.poller = self.ioloop._get_poller(timer.get_remaining_interval, timer.process_timeouts) self.addCleanup(self.poller.close) sockpair = self.poller._get_interrupt_pair() self.addCleanup(sockpair[0].close) self.addCleanup(sockpair[1].close) self._eintr_read_handler_is_called = False self.poller.add_handler(sockpair[0].fileno(), self._eintr_read_handler, self.ioloop.READ) self.ioloop.call_later(self.TIMEOUT, self._eintr_test_fail) original_signal_handler = \ signal.signal(signal.SIGUSR1, self.signal_handler) self.addCleanup(signal.signal, signal.SIGUSR1, original_signal_handler) tmr_k = threading.Timer(0.1, lambda: os.kill(os.getpid(), signal.SIGUSR1)) self.addCleanup(tmr_k.cancel) tmr_w = threading.Timer(0.2, lambda: sockpair[1].send(self.MSG_CONTENT)) self.addCleanup(tmr_w.cancel) tmr_k.start() tmr_w.start() self.poller.start() self.assertTrue(self._eintr_read_handler_is_called) if pika.compat.EINTR_IS_EXPOSED: self.assertEqual(is_resumable_mock.call_count, 1) else: self.assertEqual(is_resumable_mock.call_count, 0)
def test_call_later_single_timer_expires(self): now = test_now() with mock.patch('pika.compat.time_now', return_value=now): bucket = [] timer = select_connection._Timer() timer.call_later(5, lambda: bucket.append(1)) # Nothing is ready to expire timer.process_timeouts() self.assertEqual(bucket, []) self.assertEqual(timer.get_remaining_interval(), 5) # Advance time by 5 seconds and expect the timer to expire with mock.patch('pika.compat.time_now', return_value=now + 5): self.assertEqual(timer.get_remaining_interval(), 0) timer.process_timeouts() self.assertEqual(bucket, [1]) self.assertEqual(len(timer._timeout_heap), 0) self.assertIsNone(timer.get_remaining_interval())
def test_call_later_single_timer_expires(self): now = time.time() with mock.patch('time.time', return_value=now): bucket = [] timer = select_connection._Timer() timer.call_later(5, lambda: bucket.append(1)) # Nothing is ready to expire timer.process_timeouts() self.assertEqual(bucket, []) self.assertEqual(timer.get_remaining_interval(), 5) # Advance time by 5 seconds and expect the timer to expire with mock.patch('time.time', return_value=now + 5): self.assertEqual(timer.get_remaining_interval(), 0) timer.process_timeouts() self.assertEqual(bucket, [1]) self.assertEqual(len(timer._timeout_heap), 0) self.assertIsNone(timer.get_remaining_interval())
def test_cancel_expired_timeout_from_another_timeout(self): now = test_now() bucket = [] timer = select_connection._Timer() with mock.patch('pika.compat.time_now', return_value=now): t2 = timer.call_later(10, lambda: bucket.append(2)) t1 = timer.call_later( 5, lambda: (self.assertEqual(timer._num_cancellations, 0), timer.remove_timeout(t2))) self.assertIs(t1, timer._timeout_heap[0]) # Advance time by 10 seconds and check that t2 is cancelled and # removed from timeout heap with mock.patch('pika.compat.time_now', return_value=now + 10): timer.process_timeouts() self.assertEqual(bucket, []) self.assertIsNone(t2.callback) self.assertIsNone(timer.get_remaining_interval()) self.assertEqual(len(timer._timeout_heap), 0) self.assertEqual(timer._num_cancellations, 0)
def test_cancel_expired_timeout_from_another_timeout(self): now = time.time() bucket = [] timer = select_connection._Timer() with mock.patch('time.time', return_value=now): t2 = timer.call_later(10, lambda: bucket.append(2)) t1 = timer.call_later( 5, lambda: (self.assertEqual(timer._num_cancellations, 0), timer.remove_timeout(t2))) self.assertIs(t1, timer._timeout_heap[0]) # Advance time by 10 seconds and check that t2 is cancelled and # removed from timeout heap with mock.patch('time.time', return_value=now + 10): timer.process_timeouts() self.assertEqual(bucket, []) self.assertIsNone(t2.callback) self.assertIsNone(timer.get_remaining_interval()) self.assertEqual(len(timer._timeout_heap), 0) self.assertEqual(timer._num_cancellations, 0)
def test_close_empty(self): timer = select_connection._Timer() timer.close() self.assertIsNone(timer._timeout_heap)
def test_no_timeouts_remaining_interval_is_none(self): timer = select_connection._Timer() self.assertIsNone(timer.get_remaining_interval())