class TestBackgroundIteration(TestAssistant, BackgroundIterationTests, unittest.TestCase): def setUp(self): TestAssistant.setUp(self) self._context = MultithreadingContext() self.executor = TraitsExecutor( context=self._context, event_loop=self._event_loop, ) def tearDown(self): self.halt_executor() self._context.close() TestAssistant.tearDown(self) @contextlib.contextmanager def block_worker_pool(self): """ Context manager to temporarily block the workers in the worker pool. """ worker_pool = self.executor._worker_pool max_workers = worker_pool._max_workers event = self._context.event() futures = [] for _ in range(max_workers): futures.append(worker_pool.submit(event.wait)) try: yield finally: event.set() concurrent.futures.wait(futures, timeout=TIMEOUT)
def setUp(self): TestAssistant.setUp(self) self._context = MultithreadingContext() self.executor = TraitsExecutor( context=self._context, event_loop=self._event_loop, )
def setUp(self): TestAssistant.setUp(self) self._context = MultithreadingContext() self._worker_pool = self._context.worker_pool() self.executor = TraitsExecutor( context=self._context, event_loop=self._event_loop, worker_pool=self._worker_pool, ) self.listener = ExecutorListener(executor=self.executor)
def test_externally_supplied_context(self): context = MultithreadingContext() try: with self.temporary_executor( context=context, event_loop=self._event_loop ) as executor: self.assertIs(executor._context, context) self.assertFalse(context.closed) finally: context.close()
class TestTraitsExecutor( TestAssistant, TraitsExecutorTests, unittest.TestCase ): def setUp(self): TestAssistant.setUp(self) self._context = MultithreadingContext() self.executor = TraitsExecutor( context=self._context, event_loop=self._event_loop, ) self.listener = ExecutorListener(executor=self.executor) def tearDown(self): del self.listener self.executor.shutdown(timeout=SAFETY_TIMEOUT) del self.executor self._context.close() del self._context TestAssistant.tearDown(self)
def test_run_until_timeout_trait_fired(self): # Trait fired, but condition still never true. executor = TraitsExecutor( context=MultithreadingContext(), event_loop=self._event_loop, ) future = submit_call(executor, int, "111") start_time = time.monotonic() with self.assertRaises(RuntimeError): self.run_until( future, "state", condition=lambda future: future.state == CANCELLED, timeout=0.1, ) actual_timeout = time.monotonic() - start_time executor.shutdown(timeout=SAFETY_TIMEOUT) self.assertLess(actual_timeout, 1.0)
def test_run_until_success(self): # Trait fired, condition starts false but becomes true. executor = TraitsExecutor( context=MultithreadingContext(), event_loop=self._event_loop, ) # Case 1: condition true on second trait change event. future = submit_call(executor, slow_return) self.run_until( future, "state", condition=lambda future: future.done, ) self.assertTrue(future.done) # Case 2: condition true on the first trait firing. executor.stop() self.run_until( executor, "stopped", condition=lambda executor: executor.stopped, ) self.assertTrue(executor.stopped)
def setUp(self): TestAssistant.setUp(self) self._context = MultithreadingContext()
class TestTraitsExecutorCreation(TestAssistant, unittest.TestCase): def setUp(self): TestAssistant.setUp(self) self._context = MultithreadingContext() def tearDown(self): self._context.close() TestAssistant.tearDown(self) def test_max_workers(self): executor = TraitsExecutor( max_workers=11, context=self._context, event_loop=self._event_loop, ) self.assertEqual(executor._worker_pool._max_workers, 11) executor.shutdown(timeout=SAFETY_TIMEOUT) def test_max_workers_mutually_exclusive_with_worker_pool(self): with self.temporary_worker_pool() as worker_pool: with self.assertRaises(TypeError): TraitsExecutor( worker_pool=worker_pool, max_workers=11, context=self._context, event_loop=self._event_loop, ) def test_default_context(self): with self.temporary_executor(event_loop=self._event_loop) as executor: self.assertIsInstance(executor._context, MultithreadingContext) def test_default_event_loop(self): with self.temporary_executor() as executor: self.assertIsInstance(executor._event_loop, ETSEventLoop) def test_externally_supplied_context(self): context = MultithreadingContext() try: with self.temporary_executor( context=context, event_loop=self._event_loop ) as executor: self.assertIs(executor._context, context) self.assertFalse(context.closed) finally: context.close() def test_owned_context_closed_at_executor_stop(self): with self.temporary_executor(event_loop=self._event_loop) as executor: context = executor._context self.assertFalse(context.closed) self.assertTrue(context.closed) def test_owned_worker_pool(self): executor = TraitsExecutor( context=self._context, event_loop=self._event_loop, ) worker_pool = executor._worker_pool executor.shutdown(timeout=SAFETY_TIMEOUT) # Check that the internally-created worker pool has been shut down. with self.assertRaises(RuntimeError): worker_pool.submit(int) def test_thread_pool_argument_deprecated(self): with self.temporary_worker_pool() as worker_pool: with self.assertWarns(DeprecationWarning) as warning_info: executor = TraitsExecutor( thread_pool=worker_pool, context=self._context, event_loop=self._event_loop, ) executor.shutdown(timeout=SAFETY_TIMEOUT) # Check we're using the right stack level in the warning. _, _, this_module = __name__.rpartition(".") self.assertIn(this_module, warning_info.filename) def test_shared_worker_pool_stop(self): with self.temporary_worker_pool() as worker_pool: executor = TraitsExecutor( worker_pool=worker_pool, context=self._context, event_loop=self._event_loop, ) executor.stop() self.wait_until_stopped(executor) # Check that the the shared worker pool is still usable. cf_future = worker_pool.submit(int) self.assertEqual(cf_future.result(), 0) def test_shared_worker_pool_shutdown(self): with self.temporary_worker_pool() as worker_pool: executor = TraitsExecutor( worker_pool=worker_pool, context=self._context, event_loop=self._event_loop, ) executor.shutdown(timeout=SAFETY_TIMEOUT) # Check that the the shared worker pool is still usable. cf_future = worker_pool.submit(int) self.assertEqual(cf_future.result(), 0) def test_no_objects_created_at_stop(self): # An executor that has no jobs submitted to it should not # need to instantiate either the context or the message router. with self.temporary_worker_pool() as worker_pool: executor = TrackingTraitsExecutor( worker_pool=worker_pool, event_loop=self._event_loop ) executor.stop() self.wait_until_stopped(executor) self.assertFalse( executor._message_router_created, msg="Message router unexpectedly created", ) self.assertFalse( executor._context_created, msg="Context unexpectedly created", ) def test_no_objects_created_at_shutdown(self): # An executor that has no jobs submitted to it should not # need to instantiate either the context or the message router. with self.temporary_worker_pool() as worker_pool: executor = TrackingTraitsExecutor( worker_pool=worker_pool, event_loop=self._event_loop ) executor.shutdown(timeout=SAFETY_TIMEOUT) self.assertFalse( executor._message_router_created, msg="Message router unexpectedly created", ) self.assertFalse( executor._context_created, msg="Context unexpectedly created", ) def wait_until_stopped(self, executor): """ Wait for the executor to reach STOPPED state. """ self.run_until(executor, "stopped", lambda executor: executor.stopped) @contextlib.contextmanager def temporary_worker_pool(self): """ Create a worker pool that's shut down at the end of the with block. """ worker_pool = self._context.worker_pool(max_workers=4) try: yield worker_pool finally: worker_pool.shutdown() @contextlib.contextmanager def temporary_executor(self, **kwds): """ Create a temporary TraitsExecutor, and shut it down properly after use. """ executor = TraitsExecutor(**kwds) try: yield executor finally: executor.shutdown(timeout=SAFETY_TIMEOUT)