Esempio n. 1
0
    def test_retry_on_timeout_no_retry_since_no_timeout_reached(self):
        # Verify initial state
        self.assertSequenceEqual(LiveAction.get_all(), [])
        self.assertSequenceEqual(ActionExecution.get_all(), [])

        # Start a mock action which succeeds
        liveaction = LiveActionDB(action='wolfpack.action-1',
                                  parameters={'actionstr': 'foo'})
        live_action_db, execution_db = action_service.request(liveaction)

        live_action_db.status = LIVEACTION_STATUS_SUCCEEDED
        execution_db.status = LIVEACTION_STATUS_SUCCEEDED
        LiveAction.add_or_update(live_action_db)
        ActionExecution.add_or_update(execution_db)

        # Simulate policy "apply_after" run
        self.policy.apply_after(target=live_action_db)

        # There should only be 1 object since the action didn't timeout and therefore it wasn't
        # retried
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), 1)
        self.assertEqual(len(action_execution_dbs), 1)
        self.assertEqual(action_execution_dbs[0].status,
                         LIVEACTION_STATUS_SUCCEEDED)
Esempio n. 2
0
    def test_retry_on_timeout_max_retries_reached(self):
        # Verify initial state
        self.assertSequenceEqual(LiveAction.get_all(), [])
        self.assertSequenceEqual(ActionExecution.get_all(), [])

        # Start a mock action which times out
        liveaction = LiveActionDB(action='wolfpack.action-1',
                                  parameters={'actionstr': 'foo'})
        live_action_db, execution_db = action_service.request(liveaction)

        live_action_db.status = LIVEACTION_STATUS_TIMED_OUT
        live_action_db.context['policies'] = {}
        live_action_db.context['policies']['retry'] = {'retry_count': 2}
        execution_db.status = LIVEACTION_STATUS_TIMED_OUT
        LiveAction.add_or_update(live_action_db)
        ActionExecution.add_or_update(execution_db)

        # Simulate policy "apply_after" run
        self.policy.apply_after(target=live_action_db)

        # Note: There should be no new objects since max retries has been reached
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), 1)
        self.assertEqual(len(action_execution_dbs), 1)
        self.assertEqual(action_execution_dbs[0].status,
                         LIVEACTION_STATUS_TIMED_OUT)
Esempio n. 3
0
    def test_no_retry_on_workflow_task(self):
        # Verify initial state
        self.assertSequenceEqual(LiveAction.get_all(), [])
        self.assertSequenceEqual(ActionExecution.get_all(), [])

        # Start a mock action which times out
        live_action_db = LiveActionDB(
            action='wolfpack.action-1',
            parameters={'actionstr': 'foo'},
            context={'parent': {
                'execution_id': 'abcde'
            }})

        live_action_db, execution_db = action_service.request(live_action_db)
        live_action_db = LiveAction.get_by_id(str(live_action_db.id))
        self.assertEqual(live_action_db.status, LIVEACTION_STATUS_REQUESTED)

        # Expire the workflow instance.
        live_action_db.status = LIVEACTION_STATUS_TIMED_OUT
        live_action_db.context['policies'] = {}
        execution_db.status = LIVEACTION_STATUS_TIMED_OUT
        LiveAction.add_or_update(live_action_db)
        ActionExecution.add_or_update(execution_db)

        # Simulate policy "apply_after" run
        self.policy.apply_after(target=live_action_db)

        # Note: There should be no new objects since live action is under the context of a workflow.
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), 1)
        self.assertEqual(len(action_execution_dbs), 1)
        self.assertEqual(action_execution_dbs[0].status,
                         LIVEACTION_STATUS_TIMED_OUT)
Esempio n. 4
0
    def test_no_retry_on_non_applicable_statuses(self):
        # Verify initial state
        self.assertSequenceEqual(LiveAction.get_all(), [])
        self.assertSequenceEqual(ActionExecution.get_all(), [])

        # Start a mock action in various statuses in which we shouldn't retry
        non_retry_statuses = [
            LIVEACTION_STATUS_REQUESTED,
            LIVEACTION_STATUS_SCHEDULED,
            LIVEACTION_STATUS_DELAYED,
            LIVEACTION_STATUS_CANCELING,
            LIVEACTION_STATUS_CANCELED,
        ]

        action_ref = 'wolfpack.action-1'

        for status in non_retry_statuses:
            liveaction = LiveActionDB(action=action_ref,
                                      parameters={'actionstr': 'foo'})
            live_action_db, execution_db = action_service.request(liveaction)

            live_action_db.status = status
            execution_db.status = status
            LiveAction.add_or_update(live_action_db)
            ActionExecution.add_or_update(execution_db)

            # Simulate policy "apply_after" run
            self.policy.apply_after(target=live_action_db)

        # None of the actions should have been retried
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), len(non_retry_statuses))
        self.assertEqual(len(action_execution_dbs), len(non_retry_statuses))
Esempio n. 5
0
    def test_no_retry_on_workflow_task(self):
        # Verify initial state
        self.assertSequenceEqual(LiveAction.get_all(), [])
        self.assertSequenceEqual(ActionExecution.get_all(), [])

        # Start a mock action which times out
        live_action_db = LiveActionDB(
            action='wolfpack.action-1',
            parameters={'actionstr': 'foo'},
            context={'parent': {'execution_id': 'abcde'}}
        )

        live_action_db, execution_db = action_service.request(live_action_db)
        live_action_db = LiveAction.get_by_id(str(live_action_db.id))
        self.assertEqual(live_action_db.status, LIVEACTION_STATUS_REQUESTED)

        # Expire the workflow instance.
        live_action_db.status = LIVEACTION_STATUS_TIMED_OUT
        live_action_db.context['policies'] = {}
        execution_db.status = LIVEACTION_STATUS_TIMED_OUT
        LiveAction.add_or_update(live_action_db)
        ActionExecution.add_or_update(execution_db)

        # Simulate policy "apply_after" run
        self.policy.apply_after(target=live_action_db)

        # Note: There should be no new objects since live action is under the context of a workflow.
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), 1)
        self.assertEqual(len(action_execution_dbs), 1)
        self.assertEqual(action_execution_dbs[0].status, LIVEACTION_STATUS_TIMED_OUT)
Esempio n. 6
0
    def test_no_retry_on_non_applicable_statuses(self):
        # Verify initial state
        self.assertSequenceEqual(LiveAction.get_all(), [])
        self.assertSequenceEqual(ActionExecution.get_all(), [])

        # Start a mock action in various statuses in which we shouldn't retry
        non_retry_statuses = [
            LIVEACTION_STATUS_REQUESTED,
            LIVEACTION_STATUS_SCHEDULED,
            LIVEACTION_STATUS_DELAYED,
            LIVEACTION_STATUS_CANCELING,
            LIVEACTION_STATUS_CANCELED,
        ]

        action_ref = 'wolfpack.action-1'

        for status in non_retry_statuses:
            liveaction = LiveActionDB(action=action_ref, parameters={'actionstr': 'foo'})
            live_action_db, execution_db = action_service.request(liveaction)

            live_action_db.status = status
            execution_db.status = status
            LiveAction.add_or_update(live_action_db)
            ActionExecution.add_or_update(execution_db)

            # Simulate policy "apply_after" run
            self.policy.apply_after(target=live_action_db)

        # None of the actions should have been retried
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), len(non_retry_statuses))
        self.assertEqual(len(action_execution_dbs), len(non_retry_statuses))
Esempio n. 7
0
    def test_retry_on_timeout_max_retries_reached(self):
        # Verify initial state
        self.assertSequenceEqual(LiveAction.get_all(), [])
        self.assertSequenceEqual(ActionExecution.get_all(), [])

        # Start a mock action which times out
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
        live_action_db, execution_db = action_service.request(liveaction)

        live_action_db.status = LIVEACTION_STATUS_TIMED_OUT
        live_action_db.context['policies'] = {}
        live_action_db.context['policies']['retry'] = {'retry_count': 2}
        execution_db.status = LIVEACTION_STATUS_TIMED_OUT
        LiveAction.add_or_update(live_action_db)
        ActionExecution.add_or_update(execution_db)

        # Simulate policy "apply_after" run
        self.policy.apply_after(target=live_action_db)

        # Note: There should be no new objects since max retries has been reached
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), 1)
        self.assertEqual(len(action_execution_dbs), 1)
        self.assertEqual(action_execution_dbs[0].status, LIVEACTION_STATUS_TIMED_OUT)
Esempio n. 8
0
    def test_retry_on_timeout_first_retry_is_successful(self):
        # Verify initial state
        self.assertSequenceEqual(LiveAction.get_all(), [])
        self.assertSequenceEqual(ActionExecution.get_all(), [])

        # Start a mock action which times out
        liveaction = LiveActionDB(action="wolfpack.action-1",
                                  parameters={"actionstr": "foo"})
        live_action_db, execution_db = action_service.request(liveaction)

        live_action_db.status = LIVEACTION_STATUS_TIMED_OUT
        execution_db.status = LIVEACTION_STATUS_TIMED_OUT
        LiveAction.add_or_update(live_action_db)
        ActionExecution.add_or_update(execution_db)

        # Simulate policy "apply_after" run
        self.policy.apply_after(target=live_action_db)

        # There should be two objects - original execution and retried execution
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), 2)
        self.assertEqual(len(action_execution_dbs), 2)
        self.assertEqual(action_execution_dbs[0].status,
                         LIVEACTION_STATUS_TIMED_OUT)
        self.assertEqual(action_execution_dbs[1].status,
                         LIVEACTION_STATUS_REQUESTED)

        # Verify retried execution contains policy related context
        original_liveaction_id = action_execution_dbs[0].liveaction["id"]

        context = action_execution_dbs[1].context
        self.assertIn("policies", context)
        self.assertEqual(context["policies"]["retry"]["retry_count"], 1)
        self.assertEqual(context["policies"]["retry"]["applied_policy"],
                         "test_policy")
        self.assertEqual(
            context["policies"]["retry"]["retried_liveaction_id"],
            original_liveaction_id,
        )

        # Simulate success of second action so no it shouldn't be retried anymore
        live_action_db = live_action_dbs[1]
        live_action_db.status = LIVEACTION_STATUS_SUCCEEDED
        LiveAction.add_or_update(live_action_db)

        # Simulate policy "apply_after" run
        self.policy.apply_after(target=live_action_db)

        # There should be no new object since action succeeds so no retry was attempted
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), 2)
        self.assertEqual(len(action_execution_dbs), 2)
        self.assertEqual(live_action_dbs[0].status,
                         LIVEACTION_STATUS_TIMED_OUT)
        self.assertEqual(live_action_dbs[1].status,
                         LIVEACTION_STATUS_SUCCEEDED)
Esempio n. 9
0
    def test_over_threshold_cancel_executions(self):
        policy_db = Policy.get_by_ref('wolfpack.action-2.concurrency.attr.cancel')
        self.assertEqual(policy_db.parameters['action'], 'cancel')
        self.assertGreater(policy_db.parameters['threshold'], 0)
        self.assertIn('actionstr', policy_db.parameters['attributes'])

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-2', parameters={'actionstr': 'fu'})
            action_service.request(liveaction)

        # Since states are being processed asynchronously, wait for the
        # liveactions to go into scheduled states.
        for i in range(0, 100):
            eventlet.sleep(1)
            scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
            if len(scheduled) == policy_db.parameters['threshold']:
                break

        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # Assert the correct number of published states and action executions. This is to avoid
        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-2', parameters={'actionstr': 'fu'})
        liveaction, _ = action_service.request(liveaction)
        expected_num_exec += 0  # This request will not be scheduled for execution.
        expected_num_pubs += 1  # Tally requested state.

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into cancel state.
        for i in range(0, 100):
            eventlet.sleep(1)
            liveaction = LiveAction.get_by_id(str(liveaction.id))
            if liveaction.status in [
                    action_constants.LIVEACTION_STATUS_CANCELING,
                    action_constants.LIVEACTION_STATUS_CANCELED]:
                break

        # Assert the canceling state is being published.
        calls = [call(liveaction, action_constants.LIVEACTION_STATUS_CANCELING)]
        LiveActionPublisher.publish_state.assert_has_calls(calls)
        expected_num_pubs += 2  # Tally canceling and canceled state changes.

        # Assert the action is canceled.
        canceled = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(canceled.status, action_constants.LIVEACTION_STATUS_CANCELED)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)
    def test_over_threshold_cancel_executions(self):
        policy_db = Policy.get_by_ref('wolfpack.action-2.concurrency.attr.cancel')
        self.assertEqual(policy_db.parameters['action'], 'cancel')
        self.assertGreater(policy_db.parameters['threshold'], 0)
        self.assertIn('actionstr', policy_db.parameters['attributes'])

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-2', parameters={'actionstr': 'fu'})
            action_service.request(liveaction)

        # Since states are being processed asynchronously, wait for the
        # liveactions to go into scheduled states.
        for i in range(0, 100):
            eventlet.sleep(1)
            scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
            if len(scheduled) == policy_db.parameters['threshold']:
                break

        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # Assert the correct number of published states and action executions. This is to avoid
        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-2', parameters={'actionstr': 'fu'})
        liveaction, _ = action_service.request(liveaction)
        expected_num_exec += 0  # This request will not be scheduled for execution.
        expected_num_pubs += 1  # Tally requested state.

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into cancel state.
        for i in range(0, 100):
            eventlet.sleep(1)
            liveaction = LiveAction.get_by_id(str(liveaction.id))
            if liveaction.status in [
                    action_constants.LIVEACTION_STATUS_CANCELING,
                    action_constants.LIVEACTION_STATUS_CANCELED]:
                break

        # Assert the canceling state is being published.
        calls = [call(liveaction, action_constants.LIVEACTION_STATUS_CANCELING)]
        LiveActionPublisher.publish_state.assert_has_calls(calls)
        expected_num_pubs += 2  # Tally canceling and canceled state changes.

        # Assert the action is canceled.
        canceled = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(canceled.status, action_constants.LIVEACTION_STATUS_CANCELED)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)
Esempio n. 11
0
    def test_retry_on_timeout_first_retry_is_successful(self):
        # Verify initial state
        self.assertSequenceEqual(LiveAction.get_all(), [])
        self.assertSequenceEqual(ActionExecution.get_all(), [])

        # Start a mock action which times out
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
        live_action_db, execution_db = action_service.request(liveaction)

        live_action_db.status = LIVEACTION_STATUS_TIMED_OUT
        execution_db.status = LIVEACTION_STATUS_TIMED_OUT
        LiveAction.add_or_update(live_action_db)
        ActionExecution.add_or_update(execution_db)

        # Simulate policy "apply_after" run
        self.policy.apply_after(target=live_action_db)

        # There should be two objects - original execution and retried execution
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), 2)
        self.assertEqual(len(action_execution_dbs), 2)
        self.assertEqual(action_execution_dbs[0].status, LIVEACTION_STATUS_TIMED_OUT)
        self.assertEqual(action_execution_dbs[1].status, LIVEACTION_STATUS_REQUESTED)

        # Verify retried execution contains policy related context
        original_liveaction_id = action_execution_dbs[0].liveaction['id']

        context = action_execution_dbs[1].context
        self.assertTrue('policies' in context)
        self.assertEqual(context['policies']['retry']['retry_count'], 1)
        self.assertEqual(context['policies']['retry']['applied_policy'], 'test_policy')
        self.assertEqual(context['policies']['retry']['retried_liveaction_id'],
                         original_liveaction_id)

        # Simulate success of second action so no it shouldn't be retried anymore
        live_action_db = live_action_dbs[1]
        live_action_db.status = LIVEACTION_STATUS_SUCCEEDED
        LiveAction.add_or_update(live_action_db)

        # Simulate policy "apply_after" run
        self.policy.apply_after(target=live_action_db)

        # There should be no new object since action succeeds so no retry was attempted
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), 2)
        self.assertEqual(len(action_execution_dbs), 2)
        self.assertEqual(live_action_dbs[0].status, LIVEACTION_STATUS_TIMED_OUT)
        self.assertEqual(live_action_dbs[1].status, LIVEACTION_STATUS_SUCCEEDED)
Esempio n. 12
0
    def test_over_threshold(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency')
        self.assertGreater(policy_db.parameters['threshold'], 0)

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
            eventlet.spawn(action_service.request, liveaction)

        # Sleep here to let the threads above schedule the action execution.
        eventlet.sleep(1)

        scheduled = LiveAction.get_all()
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])
        for liveaction in scheduled:
            self.assertIn(liveaction.status, SCHEDULED_STATES)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
        liveaction, _ = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_DELAYED)

        # Sleep here to let the threads above complete the action execution.
        eventlet.sleep(RUN_DELAY + 1)

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
Esempio n. 13
0
    def test_over_threshold(self):
        policy_db = Policy.get_by_ref("wolfpack.action-1.concurrency.attr")
        self.assertGreater(policy_db.parameters["threshold"], 0)
        self.assertIn("actionstr", policy_db.parameters["attributes"])

        for i in range(0, policy_db.parameters["threshold"]):
            liveaction = LiveActionDB(action="wolfpack.action-1", parameters={"actionstr": "fu"})
            action_service.request(liveaction)

        scheduled = LiveAction.get_all()
        self.assertEqual(len(scheduled), policy_db.parameters["threshold"])
        for liveaction in scheduled:
            self.assertIn(liveaction.status, SCHEDULED_STATES)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action="wolfpack.action-1", parameters={"actionstr": "fu"})
        liveaction, _ = action_service.request(liveaction)
        delayed = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(delayed.status, action_constants.LIVEACTION_STATUS_DELAYED)

        # Execution is expected to be scheduled since concurrency threshold is not reached.
        # The execution with actionstr "fu" is over the threshold but actionstr "bar" is not.
        liveaction = LiveActionDB(action="wolfpack.action-1", parameters={"actionstr": "bar"})
        liveaction, _ = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)

        # Mark one of the execution as completed.
        action_service.update_status(scheduled[0], action_constants.LIVEACTION_STATUS_SUCCEEDED, publish=True)

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(delayed.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
Esempio n. 14
0
    def test_over_threshold(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency.attr')
        self.assertGreater(policy_db.parameters['threshold'], 0)
        self.assertIn('actionstr', policy_db.parameters['attributes'])

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'fu'})
            action_service.request(liveaction)

        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'fu'})
        liveaction, _ = action_service.request(liveaction)
        delayed = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(delayed.status, action_constants.LIVEACTION_STATUS_DELAYED)

        # Execution is expected to be scheduled since concurrency threshold is not reached.
        # The execution with actionstr "fu" is over the threshold but actionstr "bar" is not.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'bar'})
        liveaction, _ = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)

        # Mark one of the execution as completed.
        action_service.update_status(
            scheduled[0], action_constants.LIVEACTION_STATUS_SUCCEEDED, publish=True)

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(delayed.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
Esempio n. 15
0
    def test_over_threshold_cancel_executions(self):
        policy_db = Policy.get_by_ref("wolfpack.action-2.concurrency.cancel")
        self.assertEqual(policy_db.parameters["action"], "cancel")
        self.assertGreater(policy_db.parameters["threshold"], 0)

        # Launch action executions until the expected threshold is reached.
        for i in range(0, policy_db.parameters["threshold"]):
            parameters = {"actionstr": "foo-" + str(i)}
            liveaction = LiveActionDB(action="wolfpack.action-2", parameters=parameters)
            action_service.request(liveaction)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Check the number of action executions in scheduled state.
        scheduled = [
            item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES
        ]
        self.assertEqual(len(scheduled), policy_db.parameters["threshold"])

        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(
            expected_num_pubs, LiveActionPublisher.publish_state.call_count
        )
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be canceled since concurrency threshold is reached.
        liveaction = LiveActionDB(
            action="wolfpack.action-2", parameters={"actionstr": "foo"}
        )
        liveaction, _ = action_service.request(liveaction)

        expected_num_pubs += 1  # Tally requested state.
        self.assertEqual(
            expected_num_pubs, LiveActionPublisher.publish_state.call_count
        )

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Assert the canceling state is being published.
        calls = [call(liveaction, action_constants.LIVEACTION_STATUS_CANCELING)]
        LiveActionPublisher.publish_state.assert_has_calls(calls)
        expected_num_pubs += 2  # Tally canceling and canceled state changes.
        expected_num_exec += 0  # This request will not be scheduled for execution.
        self.assertEqual(
            expected_num_pubs, LiveActionPublisher.publish_state.call_count
        )
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Assert the action is canceled.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_CANCELED)
        self.assertEqual(
            expected_num_pubs, LiveActionPublisher.publish_state.call_count
        )
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)
Esempio n. 16
0
    def test_over_threshold_delay_executions(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency.attr')
        self.assertGreater(policy_db.parameters['threshold'], 0)
        self.assertIn('actionstr', policy_db.parameters['attributes'])

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'fu'})
            action_service.request(liveaction)

        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'fu'})
        liveaction, _ = action_service.request(liveaction)
        delayed = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(delayed.status, action_constants.LIVEACTION_STATUS_DELAYED)

        # Execution is expected to be scheduled since concurrency threshold is not reached.
        # The execution with actionstr "fu" is over the threshold but actionstr "bar" is not.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'bar'})
        liveaction, _ = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)

        # Mark one of the execution as completed.
        action_service.update_status(
            scheduled[0], action_constants.LIVEACTION_STATUS_SUCCEEDED, publish=True)

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(delayed.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
Esempio n. 17
0
    def test_over_threshold_cancel_executions(self):
        policy_db = Policy.get_by_ref(
            'wolfpack.action-2.concurrency.attr.cancel')
        self.assertEqual(policy_db.parameters['action'], 'cancel')
        self.assertGreater(policy_db.parameters['threshold'], 0)
        self.assertIn('actionstr', policy_db.parameters['attributes'])

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-2',
                                      parameters={'actionstr': 'fu'})
            action_service.request(liveaction)

        scheduled = [
            item for item in LiveAction.get_all()
            if item.status in SCHEDULED_STATES
        ]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-2',
                                  parameters={'actionstr': 'fu'})
        liveaction, _ = action_service.request(liveaction)
        delayed = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(delayed.status,
                         action_constants.LIVEACTION_STATUS_CANCELED)
Esempio n. 18
0
    def test_over_threshold_cancel_executions(self):
        policy_db = Policy.get_by_ref('wolfpack.action-2.concurrency.cancel')
        self.assertEqual(policy_db.parameters['action'], 'cancel')
        self.assertGreater(policy_db.parameters['threshold'], 0)

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-2',
                                      parameters={'actionstr': 'foo'})
            action_service.request(liveaction)

        scheduled = [
            item for item in LiveAction.get_all()
            if item.status in SCHEDULED_STATES
        ]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # Execution is expected to be canceled since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-2',
                                  parameters={'actionstr': 'foo'})
        liveaction, _ = action_service.request(liveaction)

        # Assert the canceling state is being published.
        calls = [
            call(liveaction, action_constants.LIVEACTION_STATUS_CANCELING)
        ]
        LiveActionPublisher.publish_state.assert_has_calls(calls)

        # Assert the action is canceled.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_CANCELED)
Esempio n. 19
0
    def test_over_threshold(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency')
        self.assertGreater(policy_db.parameters['threshold'], 0)

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-1',
                                      parameters={'actionstr': 'foo'})
            action_service.request(liveaction)

        scheduled = LiveAction.get_all()
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])
        for liveaction in scheduled:
            self.assertIn(liveaction.status, SCHEDULED_STATES)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1',
                                  parameters={'actionstr': 'foo'})
        liveaction, _ = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_DELAYED)

        # Mark one of the execution as completed.
        action_service.update_status(
            scheduled[0],
            action_constants.LIVEACTION_STATUS_SUCCEEDED,
            publish=True)

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
Esempio n. 20
0
    def test_over_threshold_cancel_executions(self):
        policy_db = Policy.get_by_ref('wolfpack.action-2.concurrency.cancel')
        self.assertEqual(policy_db.parameters['action'], 'cancel')
        self.assertGreater(policy_db.parameters['threshold'], 0)

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-2', parameters={'actionstr': 'foo'})
            action_service.request(liveaction)

        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be canceled since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-2', parameters={'actionstr': 'foo'})
        liveaction, _ = action_service.request(liveaction)
        expected_num_exec += 0  # This request will not be scheduled for execution.
        expected_num_pubs += 1  # Tally requested state.

        # Assert the canceling state is being published.
        calls = [call(liveaction, action_constants.LIVEACTION_STATUS_CANCELING)]
        LiveActionPublisher.publish_state.assert_has_calls(calls)
        expected_num_pubs += 2  # Tally canceling and canceled state changes.

        # Assert the action is canceled.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_CANCELED)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)
Esempio n. 21
0
    def test_on_cancellation(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency')
        self.assertGreater(policy_db.parameters['threshold'], 0)

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-1',
                                      parameters={'actionstr': 'foo'})
            action_service.request(liveaction)

        scheduled = [
            item for item in LiveAction.get_all()
            if item.status in SCHEDULED_STATES
        ]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1',
                                  parameters={'actionstr': 'foo'})
        liveaction, _ = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_DELAYED)

        # Cancel execution.
        action_service.request_cancellation(scheduled[0], 'stanley')

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
Esempio n. 22
0
    def test_over_threshold(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency')
        self.assertGreater(policy_db.parameters['threshold'], 0)

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
            action_service.request(liveaction)

        scheduled = LiveAction.get_all()
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])
        for liveaction in scheduled:
            self.assertIn(liveaction.status, SCHEDULED_STATES)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
        liveaction, _ = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_DELAYED)

        # Mark one of the execution as completed.
        action_service.update_status(
            scheduled[0], action_constants.LIVEACTION_STATUS_SUCCEEDED, publish=True)

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
Esempio n. 23
0
    def test_on_cancellation(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency')
        self.assertGreater(policy_db.parameters['threshold'], 0)

        # Launch action executions until the expected threshold is reached.
        for i in range(0, policy_db.parameters['threshold']):
            parameters = {'actionstr': 'foo-' + str(i)}
            liveaction = LiveActionDB(action='wolfpack.action-1', parameters=parameters)
            action_service.request(liveaction)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Check the number of action executions in scheduled state.
        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
        liveaction, _ = action_service.request(liveaction)

        expected_num_pubs += 1  # Tally requested state.
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Since states are being processed async, wait for the liveaction to go into delayed state.
        liveaction = self._wait_on_status(liveaction, action_constants.LIVEACTION_STATUS_DELAYED)

        expected_num_exec += 0  # This request will not be scheduled for execution.
        expected_num_pubs += 0  # The delayed status change should not be published.
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Cancel execution.
        action_service.request_cancellation(scheduled[0], 'stanley')
        expected_num_pubs += 2  # Tally the canceling and canceled states.
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Once capacity freed up, the delayed execution is published as requested again.
        expected_num_exec += 1  # This request is expected to be executed.
        expected_num_pubs += 2  # Tally scheduled and running state.

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)
    def test_retry_on_timeout_first_retry_is_successful(self):
        # Verify initial state
        self.assertSequenceEqual(LiveAction.get_all(), [])
        self.assertSequenceEqual(ActionExecution.get_all(), [])

        # Start a mock action which times out
        liveaction = LiveActionDB(action='wolfpack.action-1',
                                  parameters={'actionstr': 'foo'})
        live_action_db, execution_db = action_service.request(liveaction)

        live_action_db.status = LIVEACTION_STATUS_TIMED_OUT
        execution_db.status = LIVEACTION_STATUS_TIMED_OUT
        LiveAction.add_or_update(live_action_db)
        ActionExecution.add_or_update(execution_db)

        # Simulate policy "apply_after" run
        self.policy.apply_after(target=live_action_db)

        # There should be two objects - original execution and retried execution
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), 2)
        self.assertEqual(len(action_execution_dbs), 2)
        self.assertEqual(action_execution_dbs[0].status,
                         LIVEACTION_STATUS_TIMED_OUT)
        self.assertEqual(action_execution_dbs[1].status,
                         LIVEACTION_STATUS_REQUESTED)

        # Simulate success of second action so no it shouldn't be retried anymore
        live_action_db = live_action_dbs[1]
        live_action_db.status = LIVEACTION_STATUS_SUCCEEDED
        LiveAction.add_or_update(live_action_db)

        # Simulate policy "apply_after" run
        self.policy.apply_after(target=live_action_db)

        # There should be no new object since action succeeds so no retry was attempted
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), 2)
        self.assertEqual(len(action_execution_dbs), 2)
        self.assertEqual(live_action_dbs[0].status,
                         LIVEACTION_STATUS_TIMED_OUT)
        self.assertEqual(live_action_dbs[1].status,
                         LIVEACTION_STATUS_SUCCEEDED)
Esempio n. 25
0
    def test_over_threshold_delay_executions(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency.attr')
        self.assertGreater(policy_db.parameters['threshold'], 0)
        self.assertIn('actionstr', policy_db.parameters['attributes'])

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'fu'})
            action_service.request(liveaction)

        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # Assert the correct number of published states and action executions. This is to avoid
        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'fu'})
        liveaction, _ = action_service.request(liveaction)
        expected_num_pubs += 1  # Tally requested state.

        # Assert the action is delayed.
        delayed = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(delayed.status, action_constants.LIVEACTION_STATUS_DELAYED)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be scheduled since concurrency threshold is not reached.
        # The execution with actionstr "fu" is over the threshold but actionstr "bar" is not.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'bar'})
        liveaction, _ = action_service.request(liveaction)
        expected_num_exec += 1  # This request is expected to be executed.
        expected_num_pubs += 3  # Tally requested, scheduled, and running states.

        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Mark one of the execution as completed.
        action_service.update_status(
            scheduled[0], action_constants.LIVEACTION_STATUS_SUCCEEDED, publish=True)
        expected_num_pubs += 1  # Tally succeeded state.

        # Once capacity freed up, the delayed execution is published as requested again.
        expected_num_exec += 1  # The delayed request is expected to be executed.
        expected_num_pubs += 3  # Tally requested, scheduled, and running state.

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(delayed.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)
Esempio n. 26
0
    def test_retry_on_timeout_no_retry_since_no_timeout_reached(self):
        # Verify initial state
        self.assertSequenceEqual(LiveAction.get_all(), [])
        self.assertSequenceEqual(ActionExecution.get_all(), [])

        # Start a mock action which succeeds
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
        live_action_db, execution_db = action_service.request(liveaction)

        live_action_db.status = LIVEACTION_STATUS_SUCCEEDED
        execution_db.status = LIVEACTION_STATUS_SUCCEEDED
        LiveAction.add_or_update(live_action_db)
        ActionExecution.add_or_update(execution_db)

        # Simulate policy "apply_after" run
        self.policy.apply_after(target=live_action_db)

        # There should only be 1 object since the action didn't timeout and therefore it wasn't
        # retried
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), 1)
        self.assertEqual(len(action_execution_dbs), 1)
        self.assertEqual(action_execution_dbs[0].status, LIVEACTION_STATUS_SUCCEEDED)
Esempio n. 27
0
    def test_over_threshold_cancel_executions(self):
        policy_db = Policy.get_by_ref('wolfpack.action-2.concurrency.cancel')
        self.assertEqual(policy_db.parameters['action'], 'cancel')
        self.assertGreater(policy_db.parameters['threshold'], 0)

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-2', parameters={'actionstr': 'foo'})
            action_service.request(liveaction)

        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # Execution is expected to be canceled since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-2', parameters={'actionstr': 'foo'})
        liveaction, _ = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_CANCELED)
Esempio n. 28
0
    def test_over_threshold_delay_executions(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency')
        self.assertGreater(policy_db.parameters['threshold'], 0)

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
            action_service.request(liveaction)

        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # Assert the correct number of published states and action executions. This is to avoid
        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
        liveaction, _ = action_service.request(liveaction)
        expected_num_exec += 1  # This request is expected to be executed.
        expected_num_pubs += 1  # Tally requested state.

        # Assert the action is delayed.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_DELAYED)

        # Mark one of the execution as completed.
        action_service.update_status(
            scheduled[0], action_constants.LIVEACTION_STATUS_SUCCEEDED, publish=True)
        expected_num_pubs += 1  # Tally requested state.

        # Once capacity freed up, the delayed execution is published as requested again.
        expected_num_pubs += 3  # Tally requested, scheduled, and running state.

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)
Esempio n. 29
0
    def test_on_cancellation(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency')
        self.assertGreater(policy_db.parameters['threshold'], 0)

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
            action_service.request(liveaction)

        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
        liveaction, _ = action_service.request(liveaction)
        expected_num_exec += 1  # This request will be scheduled for execution.
        expected_num_pubs += 1  # Tally requested state.

        # Assert the action is delayed.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_DELAYED)

        # Cancel execution.
        action_service.request_cancellation(scheduled[0], 'stanley')
        expected_num_pubs += 2  # Tally the canceling and canceled states.

        # Once capacity freed up, the delayed execution is published as requested again.
        expected_num_pubs += 3  # Tally requested, scheduled, and running state.

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)
Esempio n. 30
0
    def test_on_cancellation(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency')
        self.assertGreater(policy_db.parameters['threshold'], 0)

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
            action_service.request(liveaction)

        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
        liveaction, _ = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_DELAYED)

        # Cancel execution.
        action_service.request_cancellation(scheduled[0], 'stanley')

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
Esempio n. 31
0
    def test_over_threshold_delay_executions(self):
        policy_db = Policy.get_by_ref("wolfpack.action-1.concurrency")
        self.assertGreater(policy_db.parameters["threshold"], 0)

        for i in range(0, policy_db.parameters["threshold"]):
            liveaction = LiveActionDB(action="wolfpack.action-1", parameters={"actionstr": "foo"})
            action_service.request(liveaction)

        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters["threshold"])

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action="wolfpack.action-1", parameters={"actionstr": "foo"})
        liveaction, _ = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_DELAYED)

        # Mark one of the execution as completed.
        action_service.update_status(scheduled[0], action_constants.LIVEACTION_STATUS_SUCCEEDED, publish=True)

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
Esempio n. 32
0
 def tearDown(self):
     # Ensure all liveactions are canceled at end of each test.
     for liveaction in LiveAction.get_all():
         action_service.update_status(
             liveaction, action_constants.LIVEACTION_STATUS_CANCELED)
    def test_over_threshold_delay_executions(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency.attr')
        self.assertGreater(policy_db.parameters['threshold'], 0)
        self.assertIn('actionstr', policy_db.parameters['attributes'])

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'fu'})
            action_service.request(liveaction)

        # Since states are being processed asynchronously, wait for the
        # liveactions to go into scheduled states.
        for i in range(0, 100):
            eventlet.sleep(1)
            scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
            if len(scheduled) == policy_db.parameters['threshold']:
                break

        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # Assert the correct number of published states and action executions. This is to avoid
        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'fu'})
        liveaction, _ = action_service.request(liveaction)
        expected_num_pubs += 1  # Tally requested state.

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into delayed state.
        for i in range(0, 100):
            eventlet.sleep(1)
            liveaction = LiveAction.get_by_id(str(liveaction.id))
            if liveaction.status == action_constants.LIVEACTION_STATUS_DELAYED:
                break

        # Assert the action is delayed.
        delayed = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(delayed.status, action_constants.LIVEACTION_STATUS_DELAYED)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be scheduled since concurrency threshold is not reached.
        # The execution with actionstr "fu" is over the threshold but actionstr "bar" is not.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'bar'})
        liveaction, _ = action_service.request(liveaction)
        expected_num_exec += 1  # This request is expected to be executed.
        expected_num_pubs += 3  # Tally requested, scheduled, and running states.

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into scheduled state.
        for i in range(0, 100):
            eventlet.sleep(1)
            liveaction = LiveAction.get_by_id(str(liveaction.id))
            if liveaction.status in SCHEDULED_STATES:
                break

        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Mark one of the execution as completed.
        action_service.update_status(
            scheduled[0], action_constants.LIVEACTION_STATUS_SUCCEEDED, publish=True)
        expected_num_pubs += 1  # Tally succeeded state.

        # Once capacity freed up, the delayed execution is published as requested again.
        expected_num_exec += 1  # The delayed request is expected to be executed.
        expected_num_pubs += 3  # Tally requested, scheduled, and running state.

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into scheduled state.
        for i in range(0, 100):
            eventlet.sleep(1)
            liveaction = LiveAction.get_by_id(str(liveaction.id))
            if liveaction.status in SCHEDULED_STATES:
                break

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(delayed.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)
 def tearDown(self):
     for liveaction in LiveAction.get_all():
         action_service.update_status(
             liveaction, action_constants.LIVEACTION_STATUS_CANCELED)
Esempio n. 35
0
    def test_on_cancellation(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency.attr')
        self.assertGreater(policy_db.parameters['threshold'], 0)
        self.assertIn('actionstr', policy_db.parameters['attributes'])

        # Launch action executions until the expected threshold is reached.
        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
            action_service.request(liveaction)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Check the number of action executions in scheduled state.
        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
        liveaction, _ = action_service.request(liveaction)

        expected_num_pubs += 1  # Tally requested state.
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into delayed state.
        liveaction = self._wait_on_status(liveaction, action_constants.LIVEACTION_STATUS_DELAYED)
        delayed = liveaction

        expected_num_exec += 0  # This request will not be scheduled for execution.
        expected_num_pubs += 0  # The delayed status change should not be published.
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be scheduled since concurrency threshold is not reached.
        # The execution with actionstr "fu" is over the threshold but actionstr "bar" is not.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'bar'})
        liveaction, _ = action_service.request(liveaction)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into scheduled state.
        liveaction = self._wait_on_statuses(liveaction, SCHEDULED_STATES)
        expected_num_exec += 1  # This request is expected to be executed.
        expected_num_pubs += 3  # Tally requested, scheduled, and running states.
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Cancel execution.
        action_service.request_cancellation(scheduled[0], 'stanley')
        expected_num_pubs += 2  # Tally the canceling and canceled states.
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Once capacity freed up, the delayed execution is published as requested again.
        expected_num_exec += 1  # The delayed request is expected to be executed.
        expected_num_pubs += 2  # Tally scheduled and running state.
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into scheduled state.
        liveaction = LiveAction.get_by_id(str(delayed.id))
        liveaction = self._wait_on_statuses(liveaction, SCHEDULED_STATES)
Esempio n. 36
0
    def test_on_cancellation(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency')
        self.assertGreater(policy_db.parameters['threshold'], 0)

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
            action_service.request(liveaction)

        # Since states are being processed asynchronously, wait for the
        # liveactions to go into scheduled states.
        for i in range(0, 100):
            eventlet.sleep(1)
            scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
            if len(scheduled) == policy_db.parameters['threshold']:
                break

        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
        liveaction, _ = action_service.request(liveaction)
        expected_num_exec += 1  # This request will be scheduled for execution.
        expected_num_pubs += 1  # Tally requested state.

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into delayed state.
        for i in range(0, 100):
            eventlet.sleep(1)
            liveaction = LiveAction.get_by_id(str(liveaction.id))
            if liveaction.status == action_constants.LIVEACTION_STATUS_DELAYED:
                break

        # Assert the action is delayed.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_DELAYED)

        # Cancel execution.
        action_service.request_cancellation(scheduled[0], 'stanley')
        expected_num_pubs += 2  # Tally the canceling and canceled states.

        # Once capacity freed up, the delayed execution is published as requested again.
        expected_num_pubs += 3  # Tally requested, scheduled, and running state.

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into scheduled state.
        for i in range(0, 100):
            eventlet.sleep(1)
            liveaction = LiveAction.get_by_id(str(liveaction.id))
            if liveaction.status in SCHEDULED_STATES:
                break

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)
Esempio n. 37
0
    def test_on_cancellation(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency.attr')
        self.assertGreater(policy_db.parameters['threshold'], 0)
        self.assertIn('actionstr', policy_db.parameters['attributes'])

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-1',
                                      parameters={'actionstr': 'fu'})
            action_service.request(liveaction)

        scheduled = [
            item for item in LiveAction.get_all()
            if item.status in SCHEDULED_STATES
        ]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs,
                         LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec,
                         runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1',
                                  parameters={'actionstr': 'fu'})
        liveaction, _ = action_service.request(liveaction)
        expected_num_pubs += 1  # Tally requested state.

        # Assert the action is delayed.
        delayed = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(delayed.status,
                         action_constants.LIVEACTION_STATUS_DELAYED)
        self.assertEqual(expected_num_pubs,
                         LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec,
                         runner.MockActionRunner.run.call_count)

        # Execution is expected to be scheduled since concurrency threshold is not reached.
        # The execution with actionstr "fu" is over the threshold but actionstr "bar" is not.
        liveaction = LiveActionDB(action='wolfpack.action-1',
                                  parameters={'actionstr': 'bar'})
        liveaction, _ = action_service.request(liveaction)
        expected_num_exec += 1  # This request is expected to be executed.
        expected_num_pubs += 3  # Tally requested, scheduled, and running states.

        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
        self.assertEqual(expected_num_pubs,
                         LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec,
                         runner.MockActionRunner.run.call_count)

        # Cancel execution.
        action_service.request_cancellation(scheduled[0], 'stanley')
        expected_num_pubs += 2  # Tally the canceling and canceled states.

        # Once capacity freed up, the delayed execution is published as requested again.
        expected_num_exec += 1  # The delayed request is expected to be executed.
        expected_num_pubs += 3  # Tally requested, scheduled, and running state.

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(delayed.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
        self.assertEqual(expected_num_pubs,
                         LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec,
                         runner.MockActionRunner.run.call_count)
Esempio n. 38
0
    def test_retry_on_timeout_policy_is_retried_twice(self):
        # Verify initial state
        self.assertSequenceEqual(LiveAction.get_all(), [])
        self.assertSequenceEqual(ActionExecution.get_all(), [])

        # Start a mock action which times out
        liveaction = LiveActionDB(action='wolfpack.action-1',
                                  parameters={'actionstr': 'foo'})
        live_action_db, execution_db = action_service.request(liveaction)

        live_action_db.status = LIVEACTION_STATUS_TIMED_OUT
        execution_db.status = LIVEACTION_STATUS_TIMED_OUT
        LiveAction.add_or_update(live_action_db)
        ActionExecution.add_or_update(execution_db)

        # Simulate policy "apply_after" run
        self.policy.apply_after(target=live_action_db)

        # There should be two objects - original execution and retried execution
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), 2)
        self.assertEqual(len(action_execution_dbs), 2)
        self.assertEqual(action_execution_dbs[0].status,
                         LIVEACTION_STATUS_TIMED_OUT)
        self.assertEqual(action_execution_dbs[1].status,
                         LIVEACTION_STATUS_REQUESTED)

        # Verify retried execution contains policy related context
        original_liveaction_id = action_execution_dbs[0].liveaction['id']

        context = action_execution_dbs[1].context
        self.assertTrue('policies' in context)
        self.assertEqual(context['policies']['retry']['retry_count'], 1)
        self.assertEqual(context['policies']['retry']['applied_policy'],
                         'test_policy')
        self.assertEqual(context['policies']['retry']['retried_liveaction_id'],
                         original_liveaction_id)

        # Simulate timeout of second action which should cause another retry
        live_action_db = live_action_dbs[1]
        live_action_db.status = LIVEACTION_STATUS_TIMED_OUT
        LiveAction.add_or_update(live_action_db)

        execution_db = action_execution_dbs[1]
        execution_db.status = LIVEACTION_STATUS_TIMED_OUT
        ActionExecution.add_or_update(execution_db)

        # Simulate policy "apply_after" run
        self.policy.apply_after(target=live_action_db)

        # There should be three objects - original execution and 2 retried executions
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), 3)
        self.assertEqual(len(action_execution_dbs), 3)
        self.assertEqual(action_execution_dbs[0].status,
                         LIVEACTION_STATUS_TIMED_OUT)
        self.assertEqual(action_execution_dbs[1].status,
                         LIVEACTION_STATUS_TIMED_OUT)
        self.assertEqual(action_execution_dbs[2].status,
                         LIVEACTION_STATUS_REQUESTED)

        # Verify retried execution contains policy related context
        original_liveaction_id = action_execution_dbs[1].liveaction['id']

        context = action_execution_dbs[2].context
        self.assertTrue('policies' in context)
        self.assertEqual(context['policies']['retry']['retry_count'], 2)
        self.assertEqual(context['policies']['retry']['applied_policy'],
                         'test_policy')
        self.assertEqual(context['policies']['retry']['retried_liveaction_id'],
                         original_liveaction_id)
Esempio n. 39
0
    def test_over_threshold_delay_executions(self):
        # Ensure the concurrency policy is accurate.
        policy_db = Policy.get_by_ref("wolfpack.action-1.concurrency")
        self.assertGreater(policy_db.parameters["threshold"], 0)

        # Launch action executions until the expected threshold is reached.
        for i in range(0, policy_db.parameters["threshold"]):
            parameters = {"actionstr": "foo-" + str(i)}
            liveaction = LiveActionDB(action="wolfpack.action-1",
                                      parameters=parameters)
            action_service.request(liveaction)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Check the number of action executions in scheduled state.
        scheduled = [
            item for item in LiveAction.get_all()
            if item.status in SCHEDULED_STATES
        ]
        self.assertEqual(len(scheduled), policy_db.parameters["threshold"])

        # Assert the correct number of published states and action executions. This is to avoid
        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs,
                         LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec,
                         runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action="wolfpack.action-1",
                                  parameters={"actionstr": "foo-last"})
        liveaction, _ = action_service.request(liveaction)

        expected_num_pubs += 1  # Tally requested state.
        self.assertEqual(expected_num_pubs,
                         LiveActionPublisher.publish_state.call_count)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Since states are being processed async, wait for the liveaction to go into delayed state.
        liveaction = self._wait_on_status(
            liveaction, action_constants.LIVEACTION_STATUS_DELAYED)

        expected_num_exec += 0  # This request will not be scheduled for execution.
        expected_num_pubs += 0  # The delayed status change should not be published.
        self.assertEqual(expected_num_pubs,
                         LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec,
                         runner.MockActionRunner.run.call_count)

        # Mark one of the scheduled/running execution as completed.
        action_service.update_status(
            scheduled[0],
            action_constants.LIVEACTION_STATUS_SUCCEEDED,
            publish=True)

        expected_num_pubs += 1  # Tally succeeded state.
        self.assertEqual(expected_num_pubs,
                         LiveActionPublisher.publish_state.call_count)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Once capacity freed up, the delayed execution is published as scheduled.
        expected_num_exec += 1  # This request is expected to be executed.
        expected_num_pubs += 2  # Tally scheduled and running state.

        # Since states are being processed async, wait for the liveaction to be scheduled.
        liveaction = self._wait_on_statuses(liveaction, SCHEDULED_STATES)
        self.assertEqual(expected_num_pubs,
                         LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec,
                         runner.MockActionRunner.run.call_count)

        # Check the status changes.
        execution = ActionExecution.get(liveaction__id=str(liveaction.id))
        expected_status_changes = [
            "requested",
            "delayed",
            "requested",
            "scheduled",
            "running",
        ]
        actual_status_changes = [entry["status"] for entry in execution.log]
        self.assertListEqual(actual_status_changes, expected_status_changes)
Esempio n. 40
0
    def test_on_cancellation(self):
        policy_db = Policy.get_by_ref("wolfpack.action-1.concurrency")
        self.assertGreater(policy_db.parameters["threshold"], 0)

        # Launch action executions until the expected threshold is reached.
        for i in range(0, policy_db.parameters["threshold"]):
            parameters = {"actionstr": "foo-" + str(i)}
            liveaction = LiveActionDB(action="wolfpack.action-1",
                                      parameters=parameters)
            action_service.request(liveaction)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Check the number of action executions in scheduled state.
        scheduled = [
            item for item in LiveAction.get_all()
            if item.status in SCHEDULED_STATES
        ]
        self.assertEqual(len(scheduled), policy_db.parameters["threshold"])

        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs,
                         LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec,
                         runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action="wolfpack.action-1",
                                  parameters={"actionstr": "foo"})
        liveaction, _ = action_service.request(liveaction)

        expected_num_pubs += 1  # Tally requested state.
        self.assertEqual(expected_num_pubs,
                         LiveActionPublisher.publish_state.call_count)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Since states are being processed async, wait for the liveaction to go into delayed state.
        liveaction = self._wait_on_status(
            liveaction, action_constants.LIVEACTION_STATUS_DELAYED)

        expected_num_exec += 0  # This request will not be scheduled for execution.
        expected_num_pubs += 0  # The delayed status change should not be published.
        self.assertEqual(expected_num_pubs,
                         LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec,
                         runner.MockActionRunner.run.call_count)

        # Cancel execution.
        action_service.request_cancellation(scheduled[0], "stanley")
        expected_num_pubs += 2  # Tally the canceling and canceled states.
        self.assertEqual(expected_num_pubs,
                         LiveActionPublisher.publish_state.call_count)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Once capacity freed up, the delayed execution is published as requested again.
        expected_num_exec += 1  # This request is expected to be executed.
        expected_num_pubs += 2  # Tally scheduled and running state.

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
        self.assertEqual(expected_num_pubs,
                         LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec,
                         runner.MockActionRunner.run.call_count)
Esempio n. 41
0
    def test_over_threshold_delay_executions(self):
        # Ensure the concurrency policy is accurate.
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency')
        self.assertGreater(policy_db.parameters['threshold'], 0)

        # Launch action executions until the expected threshold is reached.
        for i in range(0, policy_db.parameters['threshold']):
            parameters = {'actionstr': 'foo-' + str(i)}
            liveaction = LiveActionDB(action='wolfpack.action-1', parameters=parameters)
            action_service.request(liveaction)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Check the number of action executions in scheduled state.
        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # Assert the correct number of published states and action executions. This is to avoid
        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo-last'})
        liveaction, _ = action_service.request(liveaction)

        expected_num_pubs += 1  # Tally requested state.
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Since states are being processed async, wait for the liveaction to go into delayed state.
        liveaction = self._wait_on_status(liveaction, action_constants.LIVEACTION_STATUS_DELAYED)

        expected_num_exec += 0  # This request will not be scheduled for execution.
        expected_num_pubs += 0  # The delayed status change should not be published.
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Mark one of the scheduled/running execution as completed.
        action_service.update_status(
            scheduled[0],
            action_constants.LIVEACTION_STATUS_SUCCEEDED,
            publish=True
        )

        expected_num_pubs += 1  # Tally succeeded state.
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Once capacity freed up, the delayed execution is published as scheduled.
        expected_num_exec += 1  # This request is expected to be executed.
        expected_num_pubs += 2  # Tally scheduled and running state.

        # Since states are being processed async, wait for the liveaction to be scheduled.
        liveaction = self._wait_on_statuses(liveaction, SCHEDULED_STATES)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Check the status changes.
        execution = ActionExecution.get(liveaction__id=str(liveaction.id))
        expected_status_changes = ['requested', 'delayed', 'requested', 'scheduled', 'running']
        actual_status_changes = [entry['status'] for entry in execution.log]
        self.assertListEqual(actual_status_changes, expected_status_changes)
Esempio n. 42
0
 def tearDown(self):
     # Ensure all liveactions are canceled at end of each test.
     for liveaction in LiveAction.get_all():
         action_service.update_status(
             liveaction, action_constants.LIVEACTION_STATUS_CANCELED)
Esempio n. 43
0
    def test_over_threshold_delay_executions(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency.attr')
        self.assertGreater(policy_db.parameters['threshold'], 0)
        self.assertIn('actionstr', policy_db.parameters['attributes'])

        # Launch action executions until the expected threshold is reached.
        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
            action_service.request(liveaction)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Check the number of action executions in scheduled state.
        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # Assert the correct number of published states and action executions. This is to avoid
        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
        liveaction, _ = action_service.request(liveaction)

        expected_num_pubs += 1  # Tally requested state.
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into delayed state.
        liveaction = self._wait_on_status(liveaction, action_constants.LIVEACTION_STATUS_DELAYED)

        expected_num_exec += 0  # This request will not be scheduled for execution.
        expected_num_pubs += 0  # The delayed status change should not be published.
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be scheduled since concurrency threshold is not reached.
        # The execution with actionstr "fu" is over the threshold but actionstr "bar" is not.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'bar'})
        liveaction, _ = action_service.request(liveaction)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into scheduled state.
        liveaction = self._wait_on_statuses(liveaction, SCHEDULED_STATES)
        expected_num_exec += 1  # This request is expected to be executed.
        expected_num_pubs += 3  # Tally requested, scheduled, and running state.
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Mark one of the execution as completed.
        action_service.update_status(
            scheduled[0],
            action_constants.LIVEACTION_STATUS_SUCCEEDED,
            publish=True
        )

        expected_num_pubs += 1  # Tally succeeded state.
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Once capacity freed up, the delayed execution is published as requested again.
        liveaction = self._wait_on_statuses(liveaction, SCHEDULED_STATES)
        expected_num_exec += 1  # The delayed request is expected to be executed.
        expected_num_pubs += 2  # Tally scheduled and running state.
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)
Esempio n. 44
0
    def test_retry_on_timeout_policy_is_retried_twice(self):
        # Verify initial state
        self.assertSequenceEqual(LiveAction.get_all(), [])
        self.assertSequenceEqual(ActionExecution.get_all(), [])

        # Start a mock action which times out
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'foo'})
        live_action_db, execution_db = action_service.request(liveaction)

        live_action_db.status = LIVEACTION_STATUS_TIMED_OUT
        execution_db.status = LIVEACTION_STATUS_TIMED_OUT
        LiveAction.add_or_update(live_action_db)
        ActionExecution.add_or_update(execution_db)

        # Simulate policy "apply_after" run
        self.policy.apply_after(target=live_action_db)

        # There should be two objects - original execution and retried execution
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), 2)
        self.assertEqual(len(action_execution_dbs), 2)
        self.assertEqual(action_execution_dbs[0].status, LIVEACTION_STATUS_TIMED_OUT)
        self.assertEqual(action_execution_dbs[1].status, LIVEACTION_STATUS_REQUESTED)

        # Verify retried execution contains policy related context
        original_liveaction_id = action_execution_dbs[0].liveaction['id']

        context = action_execution_dbs[1].context
        self.assertTrue('policies' in context)
        self.assertEqual(context['policies']['retry']['retry_count'], 1)
        self.assertEqual(context['policies']['retry']['applied_policy'], 'test_policy')
        self.assertEqual(context['policies']['retry']['retried_liveaction_id'],
                         original_liveaction_id)

        # Simulate timeout of second action which should cause another retry
        live_action_db = live_action_dbs[1]
        live_action_db.status = LIVEACTION_STATUS_TIMED_OUT
        LiveAction.add_or_update(live_action_db)

        execution_db = action_execution_dbs[1]
        execution_db.status = LIVEACTION_STATUS_TIMED_OUT
        ActionExecution.add_or_update(execution_db)

        # Simulate policy "apply_after" run
        self.policy.apply_after(target=live_action_db)

        # There should be three objects - original execution and 2 retried executions
        live_action_dbs = LiveAction.get_all()
        action_execution_dbs = ActionExecution.get_all()
        self.assertEqual(len(live_action_dbs), 3)
        self.assertEqual(len(action_execution_dbs), 3)
        self.assertEqual(action_execution_dbs[0].status, LIVEACTION_STATUS_TIMED_OUT)
        self.assertEqual(action_execution_dbs[1].status, LIVEACTION_STATUS_TIMED_OUT)
        self.assertEqual(action_execution_dbs[2].status, LIVEACTION_STATUS_REQUESTED)

        # Verify retried execution contains policy related context
        original_liveaction_id = action_execution_dbs[1].liveaction['id']

        context = action_execution_dbs[2].context
        self.assertTrue('policies' in context)
        self.assertEqual(context['policies']['retry']['retry_count'], 2)
        self.assertEqual(context['policies']['retry']['applied_policy'], 'test_policy')
        self.assertEqual(context['policies']['retry']['retried_liveaction_id'],
                         original_liveaction_id)
Esempio n. 45
0
 def tearDown(self):
     for liveaction in LiveAction.get_all():
         action_service.update_status(
             liveaction, action_constants.LIVEACTION_STATUS_CANCELED)
Esempio n. 46
0
    def test_over_threshold_delay_executions(self):
        # Ensure the concurrency policy is accurate.
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency')
        self.assertGreater(policy_db.parameters['threshold'], 0)

        # Launch action executions until the expected threshold is reached.
        for i in range(0, policy_db.parameters['threshold']):
            parameters = {'actionstr': 'foo-' + str(i)}
            liveaction = LiveActionDB(action='wolfpack.action-1',
                                      parameters=parameters)
            action_service.request(liveaction)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Check the number of action executions in scheduled state.
        scheduled = [
            item for item in LiveAction.get_all()
            if item.status in SCHEDULED_STATES
        ]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # Assert the correct number of published states and action executions. This is to avoid
        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs,
                         LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec,
                         runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1',
                                  parameters={'actionstr': 'foo-last'})
        liveaction, _ = action_service.request(liveaction)
        expected_num_exec += 1  # This request is expected to be executed.
        expected_num_pubs += 1  # Tally requested state.

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Since states are being processed async, wait for the liveaction to go into delayed state.
        liveaction = self._wait_on_status(
            liveaction, action_constants.LIVEACTION_STATUS_DELAYED)

        # Mark one of the scheduled/running execution as completed.
        action_service.update_status(
            scheduled[0],
            action_constants.LIVEACTION_STATUS_SUCCEEDED,
            publish=True)

        expected_num_pubs += 1  # Tally requested state.

        # Once capacity freed up, the delayed execution is published as requested again.
        expected_num_pubs += 3  # Tally requested, scheduled, and running state.

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Since states are being processed async, wait for the liveaction to be scheduled.
        liveaction = self._wait_on_statuses(liveaction, SCHEDULED_STATES)
        self.assertEqual(expected_num_pubs,
                         LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec,
                         runner.MockActionRunner.run.call_count)
Esempio n. 47
0
    def test_on_cancellation(self):
        policy_db = Policy.get_by_ref('wolfpack.action-1.concurrency.attr')
        self.assertGreater(policy_db.parameters['threshold'], 0)
        self.assertIn('actionstr', policy_db.parameters['attributes'])

        for i in range(0, policy_db.parameters['threshold']):
            liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'fu'})
            action_service.request(liveaction)

        # Since states are being processed asynchronously, wait for the
        # liveactions to go into scheduled states.
        for i in range(0, 100):
            eventlet.sleep(1)
            scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
            if len(scheduled) == policy_db.parameters['threshold']:
                break

        scheduled = [item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES]
        self.assertEqual(len(scheduled), policy_db.parameters['threshold'])

        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'fu'})
        liveaction, _ = action_service.request(liveaction)
        expected_num_pubs += 1  # Tally requested state.

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into delayed state.
        for i in range(0, 100):
            eventlet.sleep(1)
            liveaction = LiveAction.get_by_id(str(liveaction.id))
            if liveaction.status == action_constants.LIVEACTION_STATUS_DELAYED:
                break

        # Assert the action is delayed.
        delayed = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(delayed.status, action_constants.LIVEACTION_STATUS_DELAYED)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be scheduled since concurrency threshold is not reached.
        # The execution with actionstr "fu" is over the threshold but actionstr "bar" is not.
        liveaction = LiveActionDB(action='wolfpack.action-1', parameters={'actionstr': 'bar'})
        liveaction, _ = action_service.request(liveaction)
        expected_num_exec += 1  # This request is expected to be executed.
        expected_num_pubs += 3  # Tally requested, scheduled, and running states.

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into scheduled state.
        for i in range(0, 100):
            eventlet.sleep(1)
            liveaction = LiveAction.get_by_id(str(liveaction.id))
            if liveaction.status in SCHEDULED_STATES:
                break

        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Cancel execution.
        action_service.request_cancellation(scheduled[0], 'stanley')
        expected_num_pubs += 2  # Tally the canceling and canceled states.

        # Once capacity freed up, the delayed execution is published as requested again.
        expected_num_exec += 1  # The delayed request is expected to be executed.
        expected_num_pubs += 3  # Tally requested, scheduled, and running state.

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into scheduled state.
        for i in range(0, 100):
            eventlet.sleep(1)
            liveaction = LiveAction.get_by_id(str(liveaction.id))
            if liveaction.status in SCHEDULED_STATES:
                break

        # Execution is expected to be rescheduled.
        liveaction = LiveAction.get_by_id(str(delayed.id))
        self.assertIn(liveaction.status, SCHEDULED_STATES)
        self.assertEqual(expected_num_pubs, LiveActionPublisher.publish_state.call_count)
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)
Esempio n. 48
0
    def test_over_threshold_delay_executions(self):
        policy_db = Policy.get_by_ref("wolfpack.action-1.concurrency.attr")
        self.assertGreater(policy_db.parameters["threshold"], 0)
        self.assertIn("actionstr", policy_db.parameters["attributes"])

        # Launch action executions until the expected threshold is reached.
        for i in range(0, policy_db.parameters["threshold"]):
            liveaction = LiveActionDB(
                action="wolfpack.action-1", parameters={"actionstr": "foo"}
            )
            action_service.request(liveaction)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Check the number of action executions in scheduled state.
        scheduled = [
            item for item in LiveAction.get_all() if item.status in SCHEDULED_STATES
        ]
        self.assertEqual(len(scheduled), policy_db.parameters["threshold"])

        # Assert the correct number of published states and action executions. This is to avoid
        # duplicate executions caused by accidental publishing of state in the concurrency policies.
        # num_state_changes = len(scheduled) * len(['requested', 'scheduled', 'running'])
        expected_num_exec = len(scheduled)
        expected_num_pubs = expected_num_exec * 3
        self.assertEqual(
            expected_num_pubs, LiveActionPublisher.publish_state.call_count
        )
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be delayed since concurrency threshold is reached.
        liveaction = LiveActionDB(
            action="wolfpack.action-1", parameters={"actionstr": "foo"}
        )
        liveaction, _ = action_service.request(liveaction)

        expected_num_pubs += 1  # Tally requested state.
        self.assertEqual(
            expected_num_pubs, LiveActionPublisher.publish_state.call_count
        )

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into delayed state.
        liveaction = self._wait_on_status(
            liveaction, action_constants.LIVEACTION_STATUS_DELAYED
        )

        expected_num_exec += 0  # This request will not be scheduled for execution.
        expected_num_pubs += 0  # The delayed status change should not be published.
        self.assertEqual(
            expected_num_pubs, LiveActionPublisher.publish_state.call_count
        )
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Execution is expected to be scheduled since concurrency threshold is not reached.
        # The execution with actionstr "fu" is over the threshold but actionstr "bar" is not.
        liveaction = LiveActionDB(
            action="wolfpack.action-1", parameters={"actionstr": "bar"}
        )
        liveaction, _ = action_service.request(liveaction)

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Since states are being processed asynchronously, wait for the
        # liveaction to go into scheduled state.
        liveaction = self._wait_on_statuses(liveaction, SCHEDULED_STATES)
        expected_num_exec += 1  # This request is expected to be executed.
        expected_num_pubs += 3  # Tally requested, scheduled, and running state.
        self.assertEqual(
            expected_num_pubs, LiveActionPublisher.publish_state.call_count
        )
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)

        # Mark one of the execution as completed.
        action_service.update_status(
            scheduled[0], action_constants.LIVEACTION_STATUS_SUCCEEDED, publish=True
        )

        expected_num_pubs += 1  # Tally succeeded state.
        self.assertEqual(
            expected_num_pubs, LiveActionPublisher.publish_state.call_count
        )

        # Run the scheduler to schedule action executions.
        self._process_scheduling_queue()

        # Once capacity freed up, the delayed execution is published as requested again.
        liveaction = self._wait_on_statuses(liveaction, SCHEDULED_STATES)
        expected_num_exec += 1  # The delayed request is expected to be executed.
        expected_num_pubs += 2  # Tally scheduled and running state.
        self.assertEqual(
            expected_num_pubs, LiveActionPublisher.publish_state.call_count
        )
        self.assertEqual(expected_num_exec, runner.MockActionRunner.run.call_count)