Ejemplo n.º 1
0
class SchedulerTestCase(TestCase):

    epsilon = task._EPSILON

    def setUp(self):
        super(SchedulerTestCase, self).setUp()

        self.clock = task.Clock()

        self.cooperator = task.Cooperator(
            terminationPredicateFactory=_no_termination_factory,
            scheduler=lambda x: self.clock.callLater(self.epsilon, x)
        )
        self.cooperate = self.cooperator.cooperate

        self.dispatcher = EventDispatcher()
        self.flowmap = dict()

        self.scheduler = Scheduler(self.flowmap, self.dispatcher, self.cooperate)

    def test_run_scheduler(self):
        """
        Tests run(), stop() and join() and ensures that appropriate events are fired.
        """
        job_handler = Mock()
        attach_handler = Mock()
        start_handler = Mock()
        join_handler = Mock()
        detach_handler = Mock()

        self.dispatcher.add_listener(JobEvent, 0, job_handler)
        self.dispatcher.add_listener(AttachEvent, 0, attach_handler)
        self.dispatcher.add_listener(DetachEvent, 0, detach_handler)

        # Start the scheduler.
        run_deferred = self.scheduler.run(self.clock)
        assert_that(run_deferred, twistedsupport.has_no_result())

        self.assertEquals(job_handler.call_count, 0)
        attach_handler.assert_called_once_with(AttachEvent(scheduler=self.scheduler, reactor=self.clock))
        self.assertEquals(join_handler.call_count, 0)
        self.assertEquals(detach_handler.call_count, 0)

        job_handler.reset_mock()
        attach_handler.reset_mock()
        start_handler.reset_mock()
        join_handler.reset_mock()
        detach_handler.reset_mock()

        # Turn a bit on the clock.
        self.clock.advance(self.epsilon)
        assert_that(run_deferred, twistedsupport.has_no_result())

        self.assertEquals(job_handler.call_count, 0)
        self.assertEquals(attach_handler.call_count, 0)
        self.assertEquals(start_handler.call_count, 0)
        self.assertEquals(join_handler.call_count, 0)
        self.assertEquals(detach_handler.call_count, 0)

        job_handler.reset_mock()
        attach_handler.reset_mock()
        start_handler.reset_mock()
        join_handler.reset_mock()
        detach_handler.reset_mock()

        # Stop the scheduler.
        self.scheduler.stop('some reason')
        assert_that(run_deferred, twistedsupport.succeeded(matchers.Equals('some reason')))

        self.assertEquals(job_handler.call_count, 0)
        self.assertEquals(attach_handler.call_count, 0)
        self.assertEquals(start_handler.call_count, 0)
        self.assertEquals(join_handler.call_count, 0)
        self.assertEquals(detach_handler.call_count, 0)

        job_handler.reset_mock()
        attach_handler.reset_mock()
        start_handler.reset_mock()
        join_handler.reset_mock()
        detach_handler.reset_mock()

        # Stop the queue and join processes.
        join_deferred = self.scheduler.join()
        self.clock.advance(self.epsilon)
        assert_that(join_deferred, twistedsupport.succeeded(matchers.Always()))

        self.assertEquals(job_handler.call_count, 0)
        self.assertEquals(attach_handler.call_count, 0)
        self.assertEquals(start_handler.call_count, 0)
        detach_handler.assert_called_once_with(DetachEvent(scheduler=self.scheduler))

    def test_run_job(self):
        """
        Tests send() and ensure that the job-event is fired.
        """
        job_handler = Mock()
        self.dispatcher.add_listener(JobEvent, 0, job_handler)

        port_out = object()
        port_in = Mock(spec=_port_callback)
        self.flowmap[port_out] = port_in

        self.scheduler.run(self.clock)
        self.scheduler.send('some item', port_out)

        expected_job = Job(port_in, 'some item', self.scheduler.send, port_out)
        self.assertEquals(job_handler.call_count, 1)
        assert_that(job_handler.call_args, MatchesInvocation(
            MatchesEvent(JobEvent,
                         scheduler=matchers.Equals(self.scheduler),
                         job=matchers.Equals(expected_job),
                         completed=twistedsupport.has_no_result())
        ))
        self.assertEquals(port_in.call_count, 0)

        self.assertEquals(len(list(self.scheduler.pending)), 1)

        # Trigger queue run.
        self.clock.advance(self.epsilon)

        port_in.assert_called_once_with('some item', self.scheduler.send)

        self.assertEquals(len(list(self.scheduler.pending)), 0)

    def test_fail_job(self):
        """
        Tests that scheduler is stopped whenever a port is failing.
        """
        port_out = object()
        port_in = Mock(spec=_port_callback, side_effect=RuntimeError('failed!'))
        self.flowmap[port_out] = port_in

        run_deferred = self.scheduler.run(self.clock)
        self.scheduler.send('some item', port_out)

        expected_message = 'Job failed on {:s} while processing {:s}'.format(
            str(port_in), 'some item')

        from testtools.twistedsupport._runtest import _NoTwistedLogObservers
        with _NoTwistedLogObservers():
            with twistedsupport.CaptureTwistedLogs() as twisted_logs:
                # Trigger queue run.
                self.clock.advance(self.epsilon)
                assert_that(twisted_logs.getDetails(), matchers.MatchesDict({
                    'twisted-log': matchers.AfterPreprocessing(
                        lambda log: log.as_text(), matchers.Contains(expected_message))
                }))

        port_in.assert_called_once_with('some item', self.scheduler.send)

        matcher = matchers.AfterPreprocessing(lambda f: f.value, matchers.IsInstance(RuntimeError))
        assert_that(run_deferred, twistedsupport.failed(matcher))

    def test_cancel_job(self):
        """
        Tests that scheduler is stopped whenever a port is failing.
        """
        port_out = object()
        port_in = Mock(spec=_port_callback)
        self.flowmap[port_out] = port_in

        run_deferred = self.scheduler.run(self.clock)
        self.scheduler.send('some item', port_out)

        self.assertEquals(len(list(self.scheduler.pending)), 1)

        self.scheduler.stop('bye!')

        self.assertEquals(len(list(self.scheduler.pending)), 1)

        join_deferred = self.scheduler.join()
        self.clock.advance(self.epsilon)
        assert_that(join_deferred, twistedsupport.succeeded(matchers.Always()))
        assert_that(run_deferred, twistedsupport.succeeded(matchers.Equals('bye!')))

        self.assertEquals(len(list(self.scheduler.pending)), 0)

        self.assertEquals(port_in.call_count, 0)