def test_dispatch_with_args_kwds(self):
        dispatcher = EventDispatcher()

        callback = Mock()
        dispatcher.add_listener(TestEvent, 0, callback, 'hello', 'world', some='kwds', also='here')

        event = TestEvent()
        d = dispatcher.dispatch(event)
        self.assertTrue(d.called)

        callback.assert_called_once_with(event, 'hello', 'world', some='kwds', also='here')
    def test_remove_non_existing_listeners(self):
        dispatcher = EventDispatcher()

        key = dispatcher.add_listener(TestEvent, 0, lambda event: None)

        # Valid key on invalid event type.
        self.assertRaises(KeyError, dispatcher.remove_listener, OtherEvent, key)

        # Invalid key on valid event type.
        self.assertRaises(KeyError, dispatcher.remove_listener, TestEvent, key._replace(priority=99))

        # Really remove listener.
        dispatcher.remove_listener(TestEvent, key)

        # Double removal with valid key on valid event type.
        self.assertRaises(KeyError, dispatcher.remove_listener, TestEvent, key)
    def test_dispatch_with_return_fails(self):
        dispatcher = EventDispatcher()

        test_callback_prio_0_cb_0 = Mock(return_value='hello')
        test_callback_prio_0_cb_1 = Mock(side_effect=RuntimeError('boom!'))
        test_callback_prio_1_cb_0 = Mock(return_value='world')

        dispatcher.add_listener(TestEvent, 0, test_callback_prio_0_cb_0)
        dispatcher.add_listener(TestEvent, 0, test_callback_prio_0_cb_1)
        dispatcher.add_listener(TestEvent, 1, test_callback_prio_1_cb_0)

        event = TestEvent()
        d = dispatcher.dispatch(event, fail_mode=FailMode.RETURN)

        matcher = matchers.MatchesListwise([
            matchers.MatchesListwise([
                matchers.Equals(0), matchers.MatchesListwise([
                    matchers.Equals((True, 'hello')),
                    matchers.MatchesListwise([
                        matchers.Equals(False),
                        matchers.AfterPreprocessing(lambda f: f.value, matchers.IsInstance(HandlerError)),
                    ])
                ]),
            ]),
            matchers.MatchesListwise([
                matchers.Equals(1), matchers.MatchesListwise([
                    matchers.Equals((True, 'world')),
                ]),
            ]),
        ])

        assert_that(d, twistedsupport.succeeded(matcher))
Example #4
0
    def startService(self):
        super(SpreadFlowService, self).startService()

        if self.options['confpath']:
            confpath = self.options['confpath']
        else:
            confpath = os.path.join(os.getcwd(), 'spreadflow.conf')

        stream = config_eval(confpath)

        pipeline = list()
        pipeline.append(AliasResolverPass())
        pipeline.append(PortsValidatorPass())

        if self.options['multiprocess']:
            pipeline.append(PartitionExpanderPass())
            pipeline.append(PartitionBoundsPass())
            if self.options['partition']:
                pipeline.append(PartitionWorkerPass())
                partition = self.options['partition']
                stream.append(AddTokenOp(PartitionSelectToken(partition)))
            else:
                pipeline.append(PartitionControllersPass())

        pipeline.append(ComponentsPurgePass())
        pipeline.append(EventHandlersPass())

        for compiler_step in pipeline:
            stream = compiler_step(stream)

        self._eventdispatcher = EventDispatcher()

        if self.options['oneshot']:
            self._eventdispatcher.add_listener(JobEvent, 0, self._oneshot_job_event_handler)

        connection_parser = ConnectionParser()
        stream = connection_parser.extract(stream)
        self._scheduler = Scheduler(connection_parser.get_portmap(), self._eventdispatcher)

        event_handler_parser = EventHandlerParser()
        stream = event_handler_parser.extract(stream)
        for event_type, priority, callback in event_handler_parser.get_handlers():
            self._eventdispatcher.add_listener(event_type, priority, callback)

        if self.options['queuestatus']:
            statuslog = SpreadFlowQueuestatusLogger(self.options['queuestatus'])
            statuslog.watch(1, self._scheduler)
            globalLogPublisher.addObserver(statuslog.logstatus)

        self._scheduler.run().addBoth(self._stop)
    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_dispatch_with_fails(self):
        dispatcher = EventDispatcher()

        test_callback_prio_0_cb_0 = Mock()
        test_callback_prio_0_cb_1 = Mock(side_effect=RuntimeError('boom!'))
        test_callback_prio_1_cb_0 = Mock()

        dispatcher.add_listener(TestEvent, 0, test_callback_prio_0_cb_0)
        dispatcher.add_listener(TestEvent, 0, test_callback_prio_0_cb_1)
        dispatcher.add_listener(TestEvent, 1, test_callback_prio_1_cb_0)

        event = TestEvent()
        d = dispatcher.dispatch(event)

        matcher = matchers.AfterPreprocessing(lambda f: f.value, matchers.IsInstance(HandlerError))
        assert_that(d, twistedsupport.failed(matcher))
    def test_dispatch_event(self):
        dispatcher = EventDispatcher()

        test_callback_prio_0_cb_0 = Mock()
        test_callback_prio_0_cb_1 = Mock()
        test_callback_prio_1_cb_0 = Mock()
        other_callback_prio_2_cb_0 = Mock()

        dispatcher.add_listener(TestEvent, 0, test_callback_prio_0_cb_0)
        key_prio_0_cb_1 = dispatcher.add_listener(TestEvent, 0, test_callback_prio_0_cb_1)
        dispatcher.add_listener(TestEvent, 1, test_callback_prio_1_cb_0)
        dispatcher.add_listener(OtherEvent, 2, other_callback_prio_2_cb_0)

        event = TestEvent()
        d = dispatcher.dispatch(event)
        self.assertTrue(d.called)

        test_callback_prio_0_cb_0.assert_called_once_with(event)
        test_callback_prio_0_cb_1.assert_called_once_with(event)
        test_callback_prio_1_cb_0.assert_called_once_with(event)
        self.assertEqual(other_callback_prio_2_cb_0.call_count, 0)

        dispatcher.remove_listener(TestEvent, key_prio_0_cb_1)

        test_callback_prio_0_cb_0.reset_mock()
        test_callback_prio_0_cb_1.reset_mock()
        test_callback_prio_1_cb_0.reset_mock()
        other_callback_prio_2_cb_0.reset_mock()

        event = TestEvent()
        d = dispatcher.dispatch(event)
        self.assertTrue(d.called)

        test_callback_prio_0_cb_0.assert_called_once_with(event)
        self.assertEqual(test_callback_prio_0_cb_1.call_count, 0)
        test_callback_prio_1_cb_0.assert_called_once_with(event)
        self.assertEqual(other_callback_prio_2_cb_0.call_count, 0)
    def test_manage_listeners(self):
        dispatcher = EventDispatcher()

        listeners = list(dispatcher.get_listeners(TestEvent))
        self.assertEqual(len(listeners), 0)

        test_callback_prio_0_cb_0 = Mock()
        test_callback_prio_0_cb_1 = Mock()
        test_callback_prio_1_cb_0 = Mock()
        other_callback_prio_2_cb_0 = Mock()

        # Register callbacks, first priority 1 ...
        dispatcher.add_listener(TestEvent, 1, test_callback_prio_1_cb_0)

        # ... aftwerwards priority 0 ...
        key_prio_0_cb_0 = dispatcher.add_listener(TestEvent, 0, test_callback_prio_0_cb_0)
        dispatcher.add_listener(TestEvent, 0, test_callback_prio_0_cb_1)

        # ... and finally priority 2 for another event.
        dispatcher.add_listener(OtherEvent, 2, other_callback_prio_2_cb_0)

        # Collect callbacks from listeners list.
        actual_handlers = [(key.priority, handler.callback) for key, handler in dispatcher.get_listeners(TestEvent)]
        expected_handlers = [
            (0, test_callback_prio_0_cb_0),
            (0, test_callback_prio_0_cb_1),
            (1, test_callback_prio_1_cb_0),
        ]

        self.assertEqual(expected_handlers, actual_handlers)

        # Remove one listener.
        dispatcher.remove_listener(TestEvent, key_prio_0_cb_0)

        # Collect callbacks from listeners list.
        actual_handlers = [(key.priority, handler.callback) for key, handler in dispatcher.get_listeners(TestEvent)]
        expected_handlers = [
            (0, test_callback_prio_0_cb_1),
            (1, test_callback_prio_1_cb_0),
        ]

        self.assertEqual(expected_handlers, actual_handlers)
Example #9
0
class SpreadFlowService(service.Service):
    def __init__(self, options):
        self.options = options
        self._scheduler = None
        self._eventdispatcher = None

    def startService(self):
        super(SpreadFlowService, self).startService()

        if self.options['confpath']:
            confpath = self.options['confpath']
        else:
            confpath = os.path.join(os.getcwd(), 'spreadflow.conf')

        stream = config_eval(confpath)

        pipeline = list()
        pipeline.append(AliasResolverPass())
        pipeline.append(PortsValidatorPass())

        if self.options['multiprocess']:
            pipeline.append(PartitionExpanderPass())
            pipeline.append(PartitionBoundsPass())
            if self.options['partition']:
                pipeline.append(PartitionWorkerPass())
                partition = self.options['partition']
                stream.append(AddTokenOp(PartitionSelectToken(partition)))
            else:
                pipeline.append(PartitionControllersPass())

        pipeline.append(ComponentsPurgePass())
        pipeline.append(EventHandlersPass())

        for compiler_step in pipeline:
            stream = compiler_step(stream)

        self._eventdispatcher = EventDispatcher()

        if self.options['oneshot']:
            self._eventdispatcher.add_listener(JobEvent, 0, self._oneshot_job_event_handler)

        connection_parser = ConnectionParser()
        stream = connection_parser.extract(stream)
        self._scheduler = Scheduler(connection_parser.get_portmap(), self._eventdispatcher)

        event_handler_parser = EventHandlerParser()
        stream = event_handler_parser.extract(stream)
        for event_type, priority, callback in event_handler_parser.get_handlers():
            self._eventdispatcher.add_listener(event_type, priority, callback)

        if self.options['queuestatus']:
            statuslog = SpreadFlowQueuestatusLogger(self.options['queuestatus'])
            statuslog.watch(1, self._scheduler)
            globalLogPublisher.addObserver(statuslog.logstatus)

        self._scheduler.run().addBoth(self._stop)

    def stopService(self):
        super(SpreadFlowService, self).stopService()
        return self._scheduler.join()

    def _stop(self, result):
        from twisted.internet import reactor
        try:
            reactor.stop()
        except error.ReactorNotRunning:
            pass
        return result

    def _oneshot_job_event_handler(self, event):
        scheduler = event.scheduler
        completed = event.completed

        def _stop_scheduler_when_done(result):
            if len(scheduler.pending) == 0:
                scheduler.stop(self)
            return result

        completed.addCallback(_stop_scheduler_when_done)
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)