Exemple #1
0
    def test_handling_message_for_faulthandler_by_faulthandler(self):
        """Test that message for a handler is handled by the handler."""

        self.seq.state = 'aborting'
        self.seq.faults.state = 'active'
        self.seq.context.throw(code='TestError', message='Some error message')
        with patch('bureaucrat.flowexpression.Message') as MockMsg:
            msg = Message(name='start',
                          target='fake-id_0_faults_2',
                          origin='fake-id_0_faults')
            result = self.seq.handle_message(self.ch, msg)
            self.assertEqual(result, 'consumed')
            MockMsg.assert_called_once_with(name='start',
                                            target='fake-id_0_faults_2_0',
                                            origin='fake-id_0_faults_2')
            self.assertEqual(self.seq.state, 'aborting')

        msg = Message(name='start',
                      target='fake-id_0_faults_2_0',
                      origin='fake-id_0_faults_2')
        result = self.seq.handle_message(self.ch, msg)
        self.assertEqual(result, 'consumed')
        self.ch.elaborate.assert_called_once_with(
            "test2", "fake-id_0_faults_2_0", {
                'status': 'done',
                'inst:fault': {
                    'message': 'Some error message',
                    'code': 'TestError'
                }
            })
        self.assertEqual(self.seq.state, 'aborting')
    def test_handle_message_canceled_all_final(self):
        """Test FlowExpression.handle_message() with last canceled message.

        When a complex activity in the 'aborting' state recieves a 'canceled'
        or 'aborted' message, all its children are in a final state and
        there are no fault handlers registered for the fault signal the
        activity is supposed to send a 'fault' message to its parent.
        """

        msg_canceled = Message(name='canceled', target='fake-id',
                             origin='fake-id_3')
        self.root.state = 'aborting'
        self.root.children[0].state = 'aborted'
        self.root.children[1].state = 'canceled'
        self.root.children[2].state = 'aborted'
        self.root.children[3].state = 'canceled'
        self.root.context.throw()
        with patch('bureaucrat.flowexpression.Message') as MockMsg:
            newmsg = Message(name='fault', target='', origin='fake-id')
            MockMsg.return_value = newmsg
            result = self.root.handle_message(self.ch, msg_canceled)
            self.assertEqual(result, 'consumed')
            MockMsg.assert_called_once_with(name='fault', target='',
                                            origin='fake-id',
                                            payload={
                                                'code': 'GenericError',
                                                'message': ''
                                            })
            self.ch.send.assert_called_once_with(newmsg)
            self.assertEqual(self.root.state, 'aborted')
Exemple #3
0
    def test_starting_particular_handler(self):
        """Test correct fault handler is triggered."""

        msg = Message(name='start',
                      target='fake-id_0_faults',
                      origin='fake-id_0')
        self.seq.state = 'aborting'
        self.seq.children[0].state = 'aborted'
        self.seq.children[1].state = 'canceled'
        with patch('bureaucrat.flowexpression.Message') as MockMsg:
            # last handler should be triggered for 'TestError'
            self.seq.context.throw(code='TestError',
                                   message='Some error message')
            newmsg = Message(name='start',
                             target='fake-id_0_faults_2',
                             origin='fake-id_0_faults')
            MockMsg.return_value = newmsg
            result = self.seq.handle_message(self.ch, msg)
            self.assertEqual(result, 'consumed')
            MockMsg.assert_called_once_with(name='start',
                                            target='fake-id_0_faults_2',
                                            origin='fake-id_0_faults')
            self.ch.send.assert_called_once_with(newmsg)
            self.assertEqual(self.seq.state, 'aborting')
            self.assertEqual(self.seq.faults.state, 'active')
Exemple #4
0
    def _was_sequence_completed(self,
                                channel,
                                msg,
                                guard=lambda: True,
                                compensate=lambda: None):
        """Check if all children in sequence were completed."""

        res = ''
        if self._is_complete_message(msg):
            for index, child in zip(range(0, len(self.children)),
                                    self.children):
                if child.id == msg.origin:
                    if (index + 1) < len(self.children):
                        channel.send(
                            Message(name='start',
                                    origin=self.id,
                                    target="%s_%d" % (self.id, index + 1)))
                    else:
                        if guard():
                            self.state = 'completed'
                            channel.send(
                                Message(name='completed',
                                        origin=self.id,
                                        target=self.parent_id))
                        else:
                            compensate()
                    res = 'consumed'
                    break
        return res
Exemple #5
0
    def _was_activated(self, channel, msg, guard=lambda: True):
        """Check if it's activation message."""

        if self._is_start_message(msg):

            if not guard():
                LOG.debug("Conditions for %r don't hold", self)
                self.state = 'completed'
                channel.send(
                    Message(name='completed',
                            origin=self.id,
                            target=self.parent_id))
                return 'consumed'

            if len(self.children) > 0:
                self.state = 'active'
                channel.send(
                    Message(name='start',
                            origin=self.id,
                            target=self.children[0].id))
            else:
                self.state = 'completed'
                channel.send(
                    Message(name='completed',
                            origin=self.id,
                            target=self.parent_id))
            return 'consumed'
        else:
            return ''
Exemple #6
0
    def test_handle_message_completed_from_non_last_child(self):
        """Test Foreach.handle_message() with complete msg from non last child.
        """

        msg = Message(name='completed',
                      target='fake-id_0',
                      origin='fake-id_0_0')
        self.root.state = 'active'
        self.foreach.state = 'active'
        self.foreach.context._props["inst:iteration"] = 1
        self.foreach.context._props["inst:selection"] = ["one", "two"]
        with patch('bureaucrat.flowexpression.Message') as MockMessage:
            newmsg = Message(name='start',
                             target='fake-id_0_1',
                             origin='fake-id_0')
            MockMessage.return_value = newmsg
            result = self.root.handle_message(self.ch, msg)
            self.assertEqual(result, 'consumed')
            self.assertEqual(self.foreach.state, 'active')
            MockMessage.assert_called_once_with(name='start',
                                                target='fake-id_0_1',
                                                origin='fake-id_0')
            self.ch.send.assert_called_once_with(newmsg)
            self.assertEqual(self.foreach.context.get('inst:iteration'), 1)
            self.assertEqual(self.root.context.get("prop2"),
                             {"subkey": ["one", "two"]})
            self.assertEqual(self.foreach.context.get("prop2"), 2)
    def test_handle_message_canceled_complex_in_canceling_state_2(self):
        """Test canceling complex activity when last 'canceled' msg received.

        When a complex activity in the 'canceling' state recieves a 'canceled'
        or 'aborted' message, all its children are in a final state the
        activity is supposed to change its state to 'canceled' and to send
        a 'canceled' message to its parent.
        """

        msg_canceled = Message(name='canceled', target='fake-id',
                             origin='fake-id_3')
        self.root.state = 'canceling'
        self.root.children[0].state = 'canceled'
        self.root.children[1].state = 'canceled'
        self.root.children[2].state = 'canceled'
        self.root.children[3].state = 'canceled'
        with patch('bureaucrat.flowexpression.Message') as MockMsg:
            newmsg = Message(name='canceled', target='', origin='fake-id')
            MockMsg.return_value = newmsg
            result = self.root.handle_message(self.ch, msg_canceled)
            self.assertEqual(result, 'consumed')
            MockMsg.assert_called_once_with(name='canceled', target='',
                                            origin='fake-id')
            self.ch.send.assert_called_once_with(newmsg)
            self.assertEqual(self.root.state, 'canceled')
    def test_handle_message_terminate_complex_in_active_state(self):
        """Test active complex FlowExpression.handle_message() with terminate msg.

        When a complex activity in 'active' state receives 'terminate' message
        it's supposed to
            1. send 'terminate' message to all its children which are not in
               a final state,
            2. transition to 'aborting' state.
        """

        msg = Message(name='terminate', target='fake-id_2', origin='fake-id')
        self.root.children[2].state = 'active'
        with patch('bureaucrat.flowexpression.Message') as MockMsg:
            msg0 = Message(name='terminate', target='fake-id_2_0',
                           origin='fake-id_2')
            msg1 = Message(name='terminate', target='fake-id_2_1',
                           origin='fake-id_2')
            MockMsg.side_effect = [msg0, msg1]
            result = self.root.children[2].handle_message(self.ch, msg)
            self.assertEqual(self.root.children[2].state, 'aborting')
            self.assertEqual(result, 'consumed')

            expected = [
                call(name='terminate', target='fake-id_2_0',
                     origin='fake-id_2'),
                call(name='terminate', target='fake-id_2_1',
                     origin='fake-id_2'),
            ]
            self.assertEqual(MockMsg.call_args_list, expected)

            expected = [call(msg0), call(msg1)]
            self.assertEqual(self.ch.send.call_args_list, expected)
Exemple #9
0
    def handle_message(self, channel, msg):
        """Handle message."""

        res = ''
        if self.state == 'active' and msg.name == 'fault' and \
           msg.target == self.id:
            self.state = 'aborted'
            channel.send(
                Message(name='fault',
                        target=self.parent_id,
                        origin=self.id,
                        payload=msg.payload))
            res = 'consumed'
        if res:
            return res

        # TODO: check why there is double 'start' message
        res = ''
        if self._is_start_message(msg):
            code = self.context.get('inst:fault')["code"]
            default = None
            for child in self.children:
                if code in child.codes:
                    channel.send(
                        Message(name='start', target=child.id, origin=self.id))
                    self.state = 'active'
                    res = "consumed"
                    break
                if not child.codes:
                    default = child
            else:
                if not default is None:
                    channel.send(
                        Message(name='start',
                                target=default.id,
                                origin=self.id))
                    self.state = 'active'
                    res = "consumed"
                else:
                    pass
                    # TODO: throw fault again for the last time
        if res:
            return res

        if self._is_complete_message(msg):
            channel.send(
                Message(name='completed',
                        target=self.parent_id,
                        origin=self.id))
            self.state = 'completed'
            res = 'consumed'
        if res:
            return res

        res = self._was_consumed_by_child(channel, msg)
        if res:
            return res

        return "ignored"
Exemple #10
0
    def handle_message(self, channel, msg):
        """Handle message."""

        res = FlowExpression.handle_message(self, channel, msg)
        if res:
            return res

        result = 'ignore'
        if self._is_start_message(msg):
            LOG.debug("Activate participant %s", self.participant)
            self.state = 'active'
            context = self.context.as_dictionary()
            context[
                "status"] = "done"  # FIXME: consider setting status in task queue
            channel.elaborate(self.participant, self.id, context)
            result = 'consumed'
        elif self.state == 'active' and msg.name == 'response':
            LOG.debug("Got response for action %s. Payload: %s", self.id,
                      msg.payload)
            if 'status' in msg.payload:
                status = msg.payload["status"]
                if status == 'critical':
                    LOG.warning("Got critical error: %s. Aborting...",
                                msg.payload["error"])
                    self.state = 'aborting'
                    payload = {
                        "code": "ActionError",
                        "error": msg.payload["error"]
                    }
                    channel.send(
                        Message(name='fault',
                                origin=self.id,
                                target=self.parent_id,
                                payload=payload))
                elif status == 'error':
                    LOG.error("Got recoverable error: %s. Suspending...",
                              msg.payload["error"])
                elif status == 'done':
                    del msg.payload["status"]
                    self.context.update(msg.payload)
                    self.state = 'completed'
                    # reply to parent that the child is done
                    channel.send(
                        Message(name='completed',
                                origin=self.id,
                                target=self.parent_id))
                else:
                    LOG.error("Unknown status: %s", status)
            else:
                LOG.error("No status received")
            result = 'consumed'
        else:
            LOG.debug("%r ignores %r", self, msg)

        return result
Exemple #11
0
    def test_handle_message_start(self):
        """Test Process.handle_message() with start message."""

        msg = Message(name='start', target='fake-id', origin='')
        newmsg = Message(name='start', target='fake-id_0', origin='fake-id')
        self.fexpr.state = 'ready'
        with patch('bureaucrat.flowexpression.Message') as MockMessage:
            MockMessage.return_value = newmsg
            result = self.fexpr.handle_message(self.ch, msg)
            self.assertEqual(result, 'consumed')
            self.assertEqual(self.fexpr.state, 'active')
            MockMessage.assert_called_once_with(name='start',
                                                target='fake-id_0',
                                                origin='fake-id')
            self.ch.send.assert_called_once_with(newmsg)
    def test_handle_message_terminate_simple_in_aborting_state(self):
        """Test terminating a simple activity in aborting state."""

        msg = Message(name='terminate', target='fake-id_0', origin='fake-id')
        self.root.children[0].state = 'aborting'
        with patch('bureaucrat.flowexpression.Message') as MockMsg:
            newmsg = Message(name='aborted', target='fake-id',
                             origin='fake-id_0')
            MockMsg.return_value = newmsg
            result = self.root.children[0].handle_message(self.ch, msg)
            self.assertEqual(result, 'consumed')
            MockMsg.assert_called_once_with(name='aborted', target='fake-id',
                                            origin='fake-id_0')
            self.ch.send.assert_called_once_with(newmsg)
            self.assertEqual(self.root.children[0].state, 'aborted')
Exemple #13
0
    def test_handle_message_completed2(self):
        """Test Process.handle_message() with completed msg from last child."""

        msg = Message(name='completed', target='fake-id', origin='fake-id_1')
        self.fexpr.state = 'active'
        newmsg = Message(name='completed', target='', origin='fake-id')
        with patch('bureaucrat.flowexpression.Message') as MockMessage:
            MockMessage.return_value = newmsg
            result = self.fexpr.handle_message(self.ch, msg)
            self.assertEqual(result, 'consumed')
            self.assertEqual(self.fexpr.state, 'completed')
            MockMessage.assert_called_once_with(name='completed',
                                                target='',
                                                origin='fake-id')
            self.ch.send.assert_called_once_with(newmsg)
Exemple #14
0
 def test_handle_message_start(self):
     """Test handling message 'start'."""
     msg = Message(name='start', target='fake-id_0', origin='fake-id')
     with patch('bureaucrat.flowexpression.Message') as MockMsg:
         newmsg = Message(name='completed',
                          target='fake-id',
                          origin='fake-id_0')
         MockMsg.return_value = newmsg
         result = self.root.handle_message(self.ch, msg)
         self.assertEqual(result, 'consumed')
         MockMsg.assert_called_once_with(name='completed',
                                         target='fake-id',
                                         origin='fake-id_0')
         self.ch.send.assert_called_once_with(newmsg)
         self.assertEqual(self.root.children[0].state, "completed")
         self.assertEqual(self.root.context.get("prop1"), 7)
Exemple #15
0
    def handle_message(self, channel, method, header, body):
        """Handle message."""

        LOG.debug("Method: %r", method)
        LOG.debug("Header: %r", header)
        LOG.debug("Handling message with Body: %r", body)
        try:
            msg = Message.loads(body)
        except (ValueError, KeyError) as err:
            # Report error and accept message
            LOG.error("%s", err)
            channel.basic_ack(method.delivery_tag)
            return

        if msg.target != '':
            wflow = Workflow.load(msg.target_pid)
            wflow.process.handle_message(ChannelWrapper(channel), msg)
            wflow.save()

        if msg.origin == msg.origin_pid and msg.name == 'completed':
            LOG.debug("The process %s has finished", msg.origin)
            Workflow.load(msg.origin).delete()
        elif msg.origin == msg.origin_pid and msg.name == 'fault':
            LOG.error("The process %s has faulted with %s. " + \
                      "The state is preserved.", msg.origin, msg.payload)

        channel.basic_ack(method.delivery_tag)
Exemple #16
0
    def test_handle_message_completed_state(self):
        """Test While.handle_message() when While is completed."""

        msg = Message(name='start', target='fake-id_0', origin='fake-id')
        self.fexpr.state = 'completed'
        result = self.fexpr.handle_message(self.ch, msg)
        self.assertEqual(result, 'ignored')
Exemple #17
0
    def handle_message(self, channel, msg):
        """Handle msg."""

        res = FlowExpression.handle_message(self, channel, msg)
        if res:
            return res

        result = 'ignore'
        if self._is_start_message(msg):
            LOG.debug("Wait for %s", self.duration)
            self.state = 'active'
            instant = int(time.time()) + self.duration
            channel.schedule_event(target=self.id,
                                   code="timeout",
                                   instant=instant)
            result = 'consumed'
        elif self.state == 'active' and msg.name == 'timeout':
            LOG.debug("Time is out for %s", self.id)
            self.state = 'completed'
            # reply to parent that the child is done
            channel.send(
                Message(name='completed',
                        origin=self.id,
                        target=self.parent_id))
            result = 'consumed'
        else:
            LOG.debug("%r ignores %r", self, msg)

        return result
Exemple #18
0
    def handle_message(self, channel, msg):
        """Handle message."""

        res = FlowExpression.handle_message(self, channel, msg)
        if res:
            return res

        result = 'ignore'
        if self._is_start_message(msg):
            LOG.debug("Wait for %s", self.event)
            self.state = 'active'
            _subscribe(event=self.event, target=self.id)
            result = 'consumed'
        elif self.state == 'active' and msg.name == 'triggered':
            LOG.debug("Event '%s' triggered for %s", self.event, self.id)

            if not self.evaluate():
                LOG.debug("Conditions for %r don't hold", self)
                return 'ignored'

            self.state = 'completed'
            # reply to parent that the child is done
            channel.send(
                Message(name='completed',
                        origin=self.id,
                        target=self.parent_id))
            result = 'consumed'
        else:
            LOG.debug("%r ignores %r", self, msg)

        return result
Exemple #19
0
    def handle_message(self, channel, method, header, body):
        """Handle message."""

        LOG.debug("Method: %r", method)
        LOG.debug("Header: %r", header)
        LOG.debug("Handling message with Body: %r", body)
        try:
            msg = Message.loads(body)
        except (ValueError, KeyError) as err:
            # Report error and accept message
            LOG.error("%s", err)
            channel.basic_ack(method.delivery_tag)
            return

        if msg.target != '':
            wflow = Workflow.load(msg.target_pid)
            wflow.process.handle_message(ChannelWrapper(channel), msg)
            wflow.save()

        if msg.origin == msg.origin_pid and msg.name == 'completed':
            LOG.debug("The process %s has finished", msg.origin)
            Workflow.load(msg.origin).delete()
        elif msg.origin == msg.origin_pid and msg.name == 'fault':
            LOG.error("The process %s has faulted with %s. " + \
                      "The state is preserved.", msg.origin, msg.payload)

        channel.basic_ack(method.delivery_tag)
Exemple #20
0
    def test_handle_message_wrong_target(self):
        """Test While.handle_message() when message targeted not to it."""

        msg = Message(name='start', target='fake-id_10', origin='fake-id')
        self.fexpr.state = 'active'
        result = self.fexpr.handle_message(self.ch, msg)
        self.assertEqual(result, 'ignored')
Exemple #21
0
    def test_handle_message_start(self):
        """Test Await.handle_message() with 'start' message."""
        confparser = ConfigParser()
        confparser.add_section('bureaucrat')
        confparser.set('bureaucrat', 'storage_dir', STORAGE_DIR)
        Configs.instance(confparser)
        subscriptions = [{"target": "some-id"}]
        Storage.instance().save("subscriptions", "test_event",
                                json.dumps(subscriptions))

        msg = Message(name='start', target='fake-id_0', origin='fake-id')
        self.fexpr.state = 'ready'
        result = self.fexpr.handle_message(self.ch, msg)
        self.assertEqual(result, 'consumed')
        self.assertEqual(self.fexpr.state, 'active')
        filename = os.path.join(STORAGE_DIR, "subscriptions/test_event")
        with open(filename) as fhdl:
            subscriptions.append({'target': 'fake-id_0'})
            self.assertEqual(json.load(fhdl), subscriptions)

        Configs._instance = None
        Storage._instance = None
        os.unlink(filename)
        os.rmdir(os.path.join(STORAGE_DIR, "subscriptions"))
        os.removedirs(STORAGE_DIR)
Exemple #22
0
    def test_handle_message_completed_state(self):
        """Test All.handle_message() when While is completed."""

        self.fexpr.state = 'completed'
        result = self.fexpr.handle_message(
            self.ch, Message(name='fake', target='fake-id_0',
                             origin='fake-id'))
        self.assertTrue(result == 'ignored')
Exemple #23
0
    def test_handle_message_start(self):
        """Test All.handle_message() with start event."""

        msg = Message(name='start', target='fake-id_0', origin='fake-id')
        self.fexpr.state = 'ready'
        msg1 = Message(name='start', target='fake-id_0_0', origin='fake-id_0')
        msg2 = Message(name='start', target='fake-id_0_1', origin='fake-id_0')
        with patch('bureaucrat.flowexpression.Message') as MockMessage:
            MockMessage.side_effect = [msg1, msg2]
            result = self.fexpr.handle_message(self.ch, msg)
            self.assertTrue(result == 'consumed')
            self.assertTrue(self.fexpr.state == 'active')
            expected = [
                call(msg1),
                call(msg2),
            ]
            self.assertEqual(self.ch.send.call_args_list, expected)
Exemple #24
0
    def test_handle_message_timeout(self):
        """Test Await.handle_message() with 'triggered' message."""

        msg = Message(name='triggered', target='fake-id_0', origin='fake-id_0')
        newmsg = Message(name='completed',
                         target='fake-id',
                         origin='fake-id_0')
        self.fexpr.state = 'active'
        with patch('bureaucrat.flowexpression.Message') as MockMessage:
            MockMessage.return_value = newmsg
            result = self.fexpr.handle_message(self.ch, msg)
            self.assertEqual(result, 'consumed')
            self.assertEqual(self.fexpr.state, 'completed')
            MockMessage.assert_called_once_with(name='completed',
                                                target='fake-id',
                                                origin='fake-id_0')
            self.ch.send.assert_called_once_with(newmsg)
Exemple #25
0
    def test_handle_message_completed_state(self):
        """Test Foreach.handle_message() when Foreach is completed."""

        msg = Message(name='start', target='fake-id_0', origin='fake-id')
        self.root.state = 'active'
        self.foreach.state = 'completed'
        result = self.root.handle_message(self.ch, msg)
        self.assertEqual(result, 'ignored')
Exemple #26
0
    def test_handle_message_wrong_target(self):
        """Test All.handle_message() when message targeted not to it."""

        self.fexpr.state = 'active'
        result = self.fexpr.handle_message(
            self.ch, Message(name='start',
                             target='fake-id_1',
                             origin='fake-id'))
        self.assertTrue(result == 'ignored')
Exemple #27
0
    def test_handle_message_start_with_empty_select(self):
        """Test Foreach.handle_message() with start msg and empty select."""

        msg = Message(name='start', target='fake-id_0', origin='fake-id')
        self.root.state = 'active'
        self.root.context.set('prop2', {"subkey": []})
        with patch('bureaucrat.flowexpression.Message') as MockMessage:
            newmsg = Message(name='completed',
                             target='fake-id',
                             origin='fake-id_0')
            MockMessage.return_value = newmsg
            result = self.root.handle_message(self.ch, msg)
            self.assertEqual(result, 'consumed')
            self.assertEqual(self.foreach.state, 'completed')
            MockMessage.assert_called_once_with(name='completed',
                                                target='fake-id',
                                                origin='fake-id_0')
            self.ch.send.assert_called_once_with(newmsg)
    def test_handle_message_terminate_simple_in_ready_state(self):
        """Test ready simple FlowExpression.handle_message() with terminate msg.

        When a simple activity in 'ready' state receives 'terminate' message
        it's supposed to get canceled and to notify its parent about that.
        """

        msg = Message(name='terminate', target='fake-id_0', origin='fake-id')
        with patch('bureaucrat.flowexpression.Message') as MockMsg:
            newmsg = Message(name='canceled', target='fake-id',
                             origin='fake-id_0')
            MockMsg.return_value = newmsg
            result = self.root.children[0].handle_message(self.ch, msg)
            self.assertEqual(result, 'consumed')
            MockMsg.assert_called_once_with(name='canceled', target='fake-id',
                                            origin='fake-id_0')
            self.ch.send.assert_called_once_with(newmsg)
            self.assertEqual(self.root.children[0].state, 'canceled')
Exemple #29
0
    def test_handle_message_response(self):
        """Test While.handle_message() with response message."""

        msg = Message(name='response',
                      target='fake-id_0_0',
                      origin='fake-id_0_0')
        self.fexpr.state = 'active'
        self.fexpr.children[0].state = 'active'
        result = self.fexpr.handle_message(self.ch, msg)
        self.assertEqual(result, 'consumed')
Exemple #30
0
    def test_handle_message_start(self):
        """Test Foreach.handle_message() with start msg."""

        msg = Message(name='start', target='fake-id_0', origin='fake-id')
        self.root.state = 'active'
        with patch('bureaucrat.flowexpression.Message') as MockMessage:
            newmsg = Message(name='start',
                             target='fake-id_0_0',
                             origin='fake-id_0')
            MockMessage.return_value = newmsg
            result = self.root.handle_message(self.ch, msg)
            self.assertEqual(result, 'consumed')
            self.assertEqual(self.foreach.state, 'active')
            MockMessage.assert_called_once_with(name='start',
                                                target='fake-id_0_0',
                                                origin='fake-id_0')
            self.ch.send.assert_called_once_with(newmsg)
            self.assertEqual(self.foreach.context.get('inst:iteration'), 1)
            self.assertEqual(self.foreach.context.get('inst:current'), 'one')
    def test_handle_message_fault_received(self):
        """Test FlowExpression.handle_message() with fault message.

        The 'fault' message is received from the first child which is
        in the 'active' state. The root activity is supposed to
        send 'terminate' message to all its children which are not in
        a final state.

        Also the activity is supposed to raise the 'inst:fault' singal
        in its context.
        """

        msg = Message(name='fault', target='fake-id', origin='fake-id_0',
                      payload={'code': 'GenericError'})
        self.root.state = 'active'
        self.root.children[0].state = 'aborted'
        with patch('bureaucrat.flowexpression.Message') as MockMsg:
            msg1 = Message(name='terminate', target='fake-id_1',
                           origin='fake-id')
            msg2 = Message(name='terminate', target='fake-id_2',
                           origin='fake-id')
            msg3 = Message(name='terminate', target='fake-id_3',
                           origin='fake-id')
            MockMsg.side_effect = [msg1, msg2, msg3]
            result = self.root.handle_message(self.ch, msg)
            self.assertEqual(self.root.state, 'aborting')
            self.assertEqual(result, 'consumed')

            expected = [
                call(name='terminate', target='fake-id_1', origin='fake-id'),
                call(name='terminate', target='fake-id_2', origin='fake-id'),
                call(name='terminate', target='fake-id_3', origin='fake-id')
            ]
            self.assertEqual(MockMsg.call_args_list, expected)

            expected = [call(msg1), call(msg2), call(msg3)]
            self.assertEqual(self.ch.send.call_args_list, expected)

            self.assertEqual(self.root.context.get('inst:fault'),
                             {
                                 'code': 'GenericError',
                                 'message': ''
                             })