def test_exception(self, _print): """ Test a simulated exception leak. """ # Since the weak refs are cleaned up lazily, grab strong references to # any that are currently alive to prevent our baseline from changing # under us. refs_at_start = set( [ref() for ref in actor._tracked_refs_by_idx.values()]) num_refs_at_start = len(refs_at_start) # Now do our test: leak a result with an exception attached. ar = actor.TrackedAsyncResult("foo") ar.set_exception(Exception()) self.assertEqual(num_refs_at_start + 1, len(actor._tracked_refs_by_idx)) del ar # Enough to trigger cleanup in CPython, with exact ref counts. gc.collect() # For PyPy, we have to force a cleanup self._m_exit.assert_called_once_with(1) self.assertTrue(_print.called) self.assertTrue("foo" in _print.call_args[0][0]) self._m_exit.reset_mock() # Re-grab the set of references for comparison refs_at_end = set( [ref() for ref in actor._tracked_refs_by_idx.values()]) num_refs_at_end = len(refs_at_end) self.assertEqual( refs_at_start, refs_at_end, "%s exceptions may have been leaked: %s" % (num_refs_at_end - num_refs_at_start, actor._tracked_refs_by_idx))
def test_no_exception(self, m_print): gc.collect() # Make sure that all leaked refs are cleaned up num_refs_at_start = len(actor._tracked_refs_by_idx) ar = actor.TrackedAsyncResult("foo") ar.set("foo") del ar # Enough to trigger cleanup in CPython, with exact ref counts. gc.collect() # For PyPy, we have to force a cleanup self.assertFalse(self._m_exit.called) self.assertFalse(m_print.called) num_refs_at_end = len(actor._tracked_refs_by_idx) self.assertEqual(num_refs_at_start, num_refs_at_end)
def test_no_exception(self): ar = actor.TrackedAsyncResult("foo") ar.set("foo") del ar # Enough to trigger cleanup in CPython, with exact ref counts. self.assertFalse(self._m_exit.called)
def test_exception(self): ar = actor.TrackedAsyncResult("foo") ar.set_exception(Exception()) del ar # Enough to trigger cleanup in CPython, with exact ref counts. self._m_exit.assert_called_once_with(1) self._m_exit.reset_mock()