def fsm_event(self, event, strict=False):
        """Update node_info.state based on a fsm.process_event(event) call.

        An AutomatonException triggers an error event.
        If strict, node_info.finished(istate.Events.error, error=str(exc))
        is called with the AutomatonException instance and a EventError raised.

        :param event: an event to process by the fsm
        :strict: whether to fail the introspection upon an invalid event
        :raises: NodeStateInvalidEvent
        """
        with self._fsm_ctx() as fsm:
            LOG.debug('Executing fsm(%(state)s).process_event(%(event)s)', {
                'state': fsm.current_state,
                'event': event
            },
                      node_info=self)
            try:
                fsm.process_event(event)
            except automaton_errors.NotFound as exc:
                msg = _('Invalid event: %s') % exc
                if strict:
                    LOG.error(msg, node_info=self)
                    # assuming an error event is always possible
                    self.finished(istate.Events.error, error=str(exc))
                else:
                    LOG.warning(msg, node_info=self)
                raise utils.NodeStateInvalidEvent(str(exc), node_info=self)
 def test_node_in_db_invalid_state(self, fsm_event_mock, add_node_mock):
     fsm_event_mock.side_effect = utils.NodeStateInvalidEvent('Oops!')
     six.assertRaisesRegex(self, utils.NodeStateInvalidEvent, 'Oops!',
                           node_cache.start_introspection,
                           self.node_info.uuid)
     self.assertFalse(add_node_mock.called)