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,
     )
示例#3
0
 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)
示例#4
0
 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()
示例#5
0
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)
示例#8
0
 def setUp(self):
     TestAssistant.setUp(self)
     self._context = MultithreadingContext()
示例#9
0
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)