Ejemplo n.º 1
0
def raise_event(event_name, device=None, shelf=None):
  """Raises an Event, running its sync and async Actions.

  This function runs async Actions as tasks, but sync ones serially,
  accumulating changes from each action. Supply either a device or shelf arg,
  but not both.

  Args:
    event_name: str, the name of the Event.
    device: a Device model.
    shelf: a Shelf model.

  Returns:
    The original model, optionally modified by sync actions.

  Raises:
    base_action.MissingModelError: if this method is called with neither device
        nor shelf.
    base_action.RedundantModelError: if this method is called with both device
        and shelf.
  """
  event_actions = get_actions_for_event(event_name)
  actions_dict = action_loader.load_actions()
  model = device or shelf
  if not event_actions:
    logging.warn(_NO_ACTIONS_MSG, event_name)
  else:
    action_kwargs = {}
    if device:
      action_kwargs['device'] = device
    if shelf:
      action_kwargs['shelf'] = shelf

    if not action_kwargs:
      raise base_action.MissingModelError(
          'No model passed to raise_event. You must supply either a device or '
          'shelf arg.')
    if len(action_kwargs) > 1:
      raise base_action.RedundantModelError(
          'Redundant models passed to raise_event. You must supply either a '
          'device or a shelf, but not both.')

    for action in event_actions:
      if action in actions_dict[base_action.ActionType.SYNC]:
        try:
          model = actions_dict[base_action.ActionType.SYNC][action].run(
              **action_kwargs)
        except base_action.Error as error:
          logging.error(
              'Skipping Action "%s" because it raised an exception: %s',
              action, str(error))
      if action in actions_dict[base_action.ActionType.ASYNC]:
        action_kwargs['action_name'] = action
        taskqueue.add(
            queue_name='process-action',
            payload=pickle.dumps(action_kwargs),
            target='default')

  return model
Ejemplo n.º 2
0
  def initialize(self, *args, **kwargs):  # pylint: disable=arguments-differ
    """Overridden initializer that imports all available Actions."""
    super(ProcessActionHandler, self).initialize(*args, **kwargs)

    self.actions = action_loader.load_actions()
    logging.info(
        'ProcessActionHandler loaded %d actions: %s',
        len(self.actions), str(self.actions.keys()))
Ejemplo n.º 3
0
  def test_import(
      self, mock_impimporter, mock_getmembers, mock_logwarning):
    """Tests importing modules and actions with success."""
    mock_action_loader = mock.Mock()
    mock_impimporter.return_value = mock_action_loader
    mock_module_loader = mock.Mock()
    mock_action_loader.find_module = mock_module_loader

    mock_action_loader.iter_modules.return_value = [
        ('module1', 'fake_module'),
        ('module2', 'fake_module'),
        ('module3', 'fake_module'),
        ('module4', 'fake_module'),
        ('module5', 'fake_module'),
        ('module6', 'fake_module'),
        ('module1_test', 'fake_module'),  # Skipped test module.
        ('base_action', 'fake_module'),  # Skipped base_action module.
        ('module7', 'fake_module')
    ]
    mock_getmembers.side_effect = [
        (('WorkingActionClass1', WorkingActionClass1),
         ('NonClassObject', 'not-a-class')),
        (('WorkingActionClass2', WorkingActionClass2),
         ('NonClassObject', 'not-a-class')),
        (('NonWorkingActionClass3', NonWorkingActionClass3),),
        (('ActionClassWithoutActionName4', ActionClassWithoutActionName4),),
        (('ActionClassWithoutFriendlyName5', ActionClassWithoutFriendlyName5),),
        (('ActionClassWithoutRunMethod6', ActionClassWithoutRunMethod6),),
        (('DuplicateActionClass', DuplicateActionClass),),
    ]
    test_action_dict = action_loader.load_actions()
    test_device = device_model.Device()
    self.assertEqual(
        test_action_dict[base_action.ActionType.SYNC]['action1'].run(
            device=test_device),
        test_device)
    self.assertIsNone(
        test_action_dict[base_action.ActionType.ASYNC]['action2'].run())
    mock_logwarning.assert_has_calls([
        mock.call(action_loader._INSTANTIATION_ERROR_MSG % (
            'ActionClassWithoutActionName4', 'module4',
            base_action._NO_ACTION_NAME_MSG % (
                'ActionClassWithoutActionName4'))),
        mock.call(action_loader._INSTANTIATION_ERROR_MSG % (
            'ActionClassWithoutFriendlyName5', 'module5',
            base_action._NO_FRIENDLY_NAME_MSG % (
                'ActionClassWithoutFriendlyName5'))),
        mock.call(action_loader._INSTANTIATION_ERROR_MSG % (
            'ActionClassWithoutRunMethod6', 'module6',
            base_action._NO_RUN_METHOD_MSG % (
                'ActionClassWithoutRunMethod6'))),
    ])
Ejemplo n.º 4
0
 def setUp(self):
     """Checks imported modules for an action module and includes class."""
     super(ActionTestCase, self).setUp()
     try:
         self.testing_action
     except AttributeError:
         raise EnvironmentError(
             'Create a TestCase setUp method that sets a variable named '
             'self.testing_action containing the name of the action module you '
             'wish to test, then runs the superclass setUp method.')
     actions = action_loader.load_actions([self.testing_action])  # pylint: disable=no-member
     if not actions:
         raise EnvironmentError(
             'The unit test must import at least one valid action module. Verify '
             'that self.testing_action is a string that is the name of a module '
             'in the actions directory.')
     self.action = actions.get(self.testing_action)
Ejemplo n.º 5
0
def raise_event(event_name, device=None, shelf=None):
    """Raises an Event, running its sync and async Actions.

  This function runs sync Actions serially, accumulating changes from each
  action, and then kicks off async Actions via a single task that will spawn
  more tasks for additional actions. Supply either a device or shelf arg, but
  not both.

  Args:
    event_name: str, the name of the Event.
    device: a Device model.
    shelf: a Shelf model.

  Returns:
    The original model, optionally modified by sync actions.

  Raises:
    base_action.MissingModelError: if this method is called with neither device
        nor shelf.
    base_action.RedundantModelError: if this method is called with both device
        and shelf.
    EventActionsError: if the actions raised an error.
  """
    event_actions = get_actions_for_event(event_name)
    event_actions.sort()
    event_async_actions = []
    actions_dict = action_loader.load_actions()
    model = device or shelf
    if not event_actions:
        logging.info(_NO_ACTIONS_MSG, event_name)
    else:
        action_kwargs = {}
        if device:
            action_kwargs['device'] = device
        if shelf:
            action_kwargs['shelf'] = shelf

        if not action_kwargs:
            raise base_action.MissingModelError(
                'No model passed to raise_event. You must supply either a device or '
                'shelf arg.')
        if len(action_kwargs) > 1:
            raise base_action.RedundantModelError(
                'Redundant models passed to raise_event. You must supply either a '
                'device or a shelf, but not both.')
        errors = []
        for action in event_actions:
            if action in actions_dict[base_action.ActionType.SYNC]:
                try:
                    model = actions_dict[base_action.ActionType.
                                         SYNC][action].run(**action_kwargs)
                except base_action.Error as error:
                    errors.append(error)
                    logging.error(
                        'Skipping Action "%s" because it raised an exception: %s',
                        action, str(error))
            elif action in actions_dict[base_action.ActionType.ASYNC]:
                event_async_actions.append(action)
            else:
                logging.error(
                    'Skipping Action %r because it is not loaded in the application.',
                    action)
        if errors:
            raise EventActionsError(errors)
        if event_async_actions:
            action_kwargs['async_actions'] = event_async_actions
            taskqueue.add(queue_name='process-action',
                          payload=pickle.dumps(action_kwargs),
                          target='default')

    return model