예제 #1
0
    def test_stop_workflow_fail(self):
        # Start workflow.
        wf_ex = self.engine.start_workflow(
            'wb.wf', {'param1': 'Hey', 'param2': 'Hi'}, task_name="task2")
        # Re-read execution to access related tasks.
        wf_ex = db_api.get_execution(wf_ex.id)

        self.engine.stop_workflow(wf_ex.id, 'ERROR', "Stop this!")

        # Re-read from DB again
        wf_ex = db_api.get_execution(wf_ex.id)

        self.assertEqual('ERROR', wf_ex.state)
        self.assertEqual("Stop this!", wf_ex.state_info)
예제 #2
0
    def test_stop_workflow_succeed(self):
        # Start workflow.
        wf_ex = self.engine.start_workflow(
            'wb.wf', {'param1': 'Hey', 'param2': 'Hi'}, task_name="task2")
        # Re-read execution to access related tasks.
        wf_ex = db_api.get_execution(wf_ex.id)

        self.engine.stop_workflow(wf_ex.id, 'SUCCESS', "Like this, done")

        # Re-read from DB again
        wf_ex = db_api.get_execution(wf_ex.id)

        self.assertEqual('SUCCESS', wf_ex.state)
        self.assertEqual("Like this, done", wf_ex.state_info)
예제 #3
0
    def test_stop_succeeded(self):
        self.engine.stop_workflow(self.exec_id, states.ERROR, "Failure")

        self._await(lambda: self.is_execution_error(self.exec_id))
        wf_ex = db_api.get_execution(self.exec_id)
        self.assertEqual(states.ERROR, wf_ex.state)
        self.assertEqual("Failure", wf_ex.state_info)
예제 #4
0
    def test_with_items_concurrency_gt_list_length(self):
        wf_definition = """---
        version: "2.0"

        concurrency_test:
          type: direct

          input:
           - names: ["John", "Ivan"]

          tasks:
            task1:
              with-items: name in <% $.names %>
              action: std.echo output=<% $.name %>
              concurrency: 3
        """

        wf_service.create_workflows(wf_definition)

        # Start workflow.
        wf_ex = self.engine.start_workflow('concurrency_test', {})

        self.await_execution_success(wf_ex.id)

        wf_ex = db_api.get_execution(wf_ex.id)

        task_ex = self._assert_single_item(wf_ex.task_executions,
                                           name='task1',
                                           state=states.SUCCESS)

        result = data_flow.get_task_execution_result(task_ex)

        self.assertIsInstance(result, list)
        self.assertIn('John', result)
        self.assertIn('Ivan', result)
예제 #5
0
    def test_with_items_concurrency_gt_list_length(self):
        workflow_definition = """---
        version: "2.0"

        concurrency_test:
          type: direct

          input:
           - names: ["John", "Ivan"]

          tasks:
            task1:
              with-items: name in <% $.names %>
              action: std.echo output=<% $.name %>
              concurrency: 3
        """

        wf_service.create_workflows(workflow_definition)

        # Start workflow.
        wf_ex = self.engine.start_workflow('concurrency_test', {})

        self._await(
            lambda: self.is_execution_success(wf_ex.id),
        )

        wf_ex = db_api.get_execution(wf_ex.id)
        task_ex = self._assert_single_item(wf_ex.task_executions, name='task1')
        result = data_flow.get_task_execution_result(task_ex)

        self.assertEqual(states.SUCCESS, task_ex.state)
        self.assertIsInstance(result, list)
        self.assertIn('John', result)
        self.assertIn('Ivan', result)
예제 #6
0
    def test_full_join_parallel_published_vars_complex(self):
        wfs_tasks_join_complex = """---
        version: "2.0"

        main:
          type: direct
          output:
            var_a: <% $.var_a %>
            var_b: <% $.var_b %>
            var_c: <% $.var_c %>
            var_d: <% $.var_d %>
          tasks:
            init:
              publish:
                var_a: 0
                var_b: 0
                var_c: 0
              on-success:
                - branch1_0
                - branch2_0

            branch1_0:
              publish:
                var_c: 1
              on-success:
                - branch1_1

            branch2_0:
              publish:
                var_a: 1
              on-success:
                - done

            branch1_1:
              publish:
                var_b: 1
              on-success:
                - done

            done:
              join: all
              publish:
                var_d: 1
        """
        wf_service.create_workflows(wfs_tasks_join_complex)

        # Start workflow.
        exec_db = self.engine.start_workflow('main', {})

        self._await(lambda: self.is_execution_success(exec_db.id))

        # Note: We need to reread execution to access related tasks.
        exec_db = db_api.get_execution(exec_db.id)

        self.assertDictEqual({
            'var_a': 1,
            'var_b': 1,
            'var_c': 1,
            'var_d': 1
        }, exec_db.output)
예제 #7
0
    def test_stop_failed(self):
        self.engine.stop_workflow(self.exec_id, states.SUCCESS, "Force stop")

        self._await(lambda: self.is_execution_success(self.exec_id))
        wf_ex = db_api.get_execution(self.exec_id)
        self.assertEqual(states.SUCCESS, wf_ex.state)
        self.assertEqual("Force stop", wf_ex.state_info)
예제 #8
0
    def test_delayed_task_and_correct_finish_workflow(self):
        wf_delayed_state = """---
        version: "2.0"
        wf:
          type: direct
          tasks:

            task1:
              action: std.noop
              wait-before: 1

            task2:
              action: std.noop
        """
        wf_service.create_workflows(wf_delayed_state)

        # Start workflow.
        wf_ex = self.engine.start_workflow('wf', {})

        self._await(lambda: self.is_execution_success(wf_ex.id))

        # Note: We need to reread execution to access related tasks.
        wf_ex = db_api.get_execution(wf_ex.id)

        self.assertEqual(2, len(wf_ex.task_executions))
예제 #9
0
    def test_delayed_task_and_correct_finish_workflow(self):
        wf_delayed_state = """---
        version: "2.0"
        wf:
          type: direct
          tasks:

            task1:
              action: std.noop
              wait-before: 1

            task2:
              action: std.noop
        """
        wf_service.create_workflows(wf_delayed_state)

        # Start workflow.
        wf_ex = self.engine.start_workflow('wf', {})

        self.await_execution_success(wf_ex.id)

        # Note: We need to reread execution to access related tasks.
        wf_ex = db_api.get_execution(wf_ex.id)

        self.assertEqual(2, len(wf_ex.task_executions))
예제 #10
0
    def test_with_items_concurrency_2_fail(self):
        wf_with_concurrency_2_fail = """---
        version: "2.0"

        concurrency_test_fail:
          type: direct

          tasks:
            task1:
              with-items: i in [1, 2, 3, 4]
              action: std.fail
              concurrency: 2
              on-error: task2

            task2:
              action: std.echo output="With-items failed"

        """
        wf_service.create_workflows(wf_with_concurrency_2_fail)

        # Start workflow.
        wf_ex = self.engine.start_workflow('concurrency_test_fail', {})

        self.await_execution_success(wf_ex.id)

        wf_ex = db_api.get_execution(wf_ex.id)

        task_exs = wf_ex.task_executions

        self.assertEqual(2, len(task_exs))

        task_2 = self._assert_single_item(task_exs, name='task2')

        self.assertEqual('With-items failed',
                         data_flow.get_task_execution_result(task_2))
예제 #11
0
    def test_stop_workflow_succeed(self):
        # Start workflow.
        wf_ex = self.engine.start_workflow('wb.wf', {
            'param1': 'Hey',
            'param2': 'Hi'
        },
                                           task_name="task2")
        # Re-read execution to access related tasks.
        wf_ex = db_api.get_execution(wf_ex.id)

        self.engine.stop_workflow(wf_ex.id, 'SUCCESS', "Like this, done")

        # Re-read from DB again
        wf_ex = db_api.get_execution(wf_ex.id)

        self.assertEqual('SUCCESS', wf_ex.state)
        self.assertEqual("Like this, done", wf_ex.state_info)
예제 #12
0
    def test_stop_workflow_fail(self):
        # Start workflow.
        wf_ex = self.engine.start_workflow('wb.wf', {
            'param1': 'Hey',
            'param2': 'Hi'
        },
                                           task_name="task2")
        # Re-read execution to access related tasks.
        wf_ex = db_api.get_execution(wf_ex.id)

        self.engine.stop_workflow(wf_ex.id, 'ERROR', "Stop this!")

        # Re-read from DB again
        wf_ex = db_api.get_execution(wf_ex.id)

        self.assertEqual('ERROR', wf_ex.state)
        self.assertEqual("Stop this!", wf_ex.state_info)
예제 #13
0
    def stop_workflow(self, execution_id, state, message=None):
        with db_api.transaction():
            # Must be before loading the object itself (see method doc).
            self._lock_workflow_execution(execution_id)

            wf_ex = db_api.get_execution(execution_id)

            return self._stop_workflow(wf_ex, state, message)
예제 #14
0
    def stop_workflow(self, execution_id, state, message=None):
        with db_api.transaction():
            # Must be before loading the object itself (see method doc).
            self._lock_workflow_execution(execution_id)

            wf_ex = db_api.get_execution(execution_id)

            return self._stop_workflow(wf_ex, state, message)
예제 #15
0
    def test_stop_workflow_bad_status(self):
        wf_ex = self.engine.start_workflow(
            'wb.wf', {'param1': 'Hey', 'param2': 'Hi'}, task_name="task2")
        # Re-read execution to access related tasks.
        wf_ex = db_api.get_execution(wf_ex.id)

        self.assertNotEqual(
            'PAUSE',
            self.engine.stop_workflow(wf_ex.id, 'PAUSE')
        )
예제 #16
0
    def test_full_join_parallel_published_vars_complex(self):
        wfs_tasks_join_complex = """---
        version: "2.0"

        main:
          type: direct
          output:
            var_a: <% $.var_a %>
            var_b: <% $.var_b %>
            var_c: <% $.var_c %>
            var_d: <% $.var_d %>
          tasks:
            init:
              publish:
                var_a: 0
                var_b: 0
                var_c: 0
              on-success:
                - branch1_0
                - branch2_0

            branch1_0:
              publish:
                var_c: 1
              on-success:
                - branch1_1

            branch2_0:
              publish:
                var_a: 1
              on-success:
                - done

            branch1_1:
              publish:
                var_b: 1
              on-success:
                - done

            done:
              join: all
              publish:
                var_d: 1
        """
        wf_service.create_workflows(wfs_tasks_join_complex)

        # Start workflow.
        exec_db = self.engine.start_workflow("main", {})

        self._await(lambda: self.is_execution_success(exec_db.id))

        # Note: We need to reread execution to access related tasks.
        exec_db = db_api.get_execution(exec_db.id)

        self.assertDictEqual({"var_a": 1, "var_b": 1, "var_c": 1, "var_d": 1}, exec_db.output)
예제 #17
0
    def test_stop_workflow_bad_status(self):
        wf_ex = self.engine.start_workflow('wb.wf', {
            'param1': 'Hey',
            'param2': 'Hi'
        },
                                           task_name="task2")
        # Re-read execution to access related tasks.
        wf_ex = db_api.get_execution(wf_ex.id)

        self.assertNotEqual('PAUSE',
                            self.engine.stop_workflow(wf_ex.id, 'PAUSE'))
예제 #18
0
    def test_with_items_subflow_concurrency_gt_list_length(self):
        wb_text = """---
        version: "2.0"
        name: wb1

        workflows:
          main:
            type: direct

            input:
             - names

            tasks:
              task1:
                with-items: name in <% $.names %>
                workflow: subflow1 name=<% $.name %>
                concurrency: 3

          subflow1:
            type: direct

            input:
                - name
            output:
              result: <% task(task1).result %>

            tasks:
              task1:
                action: std.echo output=<% $.name %>
        """

        wb_service.create_workbook_v2(wb_text)

        # Start workflow.
        names = ["Peter", "Susan", "Edmund", "Lucy", "Aslan", "Caspian"]
        wf_ex = self.engine.start_workflow('wb1.main', {'names': names})

        self.await_execution_success(wf_ex.id)

        wf_ex = db_api.get_execution(wf_ex.id)

        task_ex = self._assert_single_item(
            wf_ex.task_executions,
            name='task1',
            state=states.SUCCESS
        )

        result = [
            item['result']
            for item in data_flow.get_task_execution_result(task_ex)
        ]

        self.assertListEqual(sorted(result), sorted(names))
예제 #19
0
    def test_wait_before_policy_from_var(self):
        wb_service.create_workbook_v2(WAIT_BEFORE_FROM_VAR)

        # Start workflow.
        exec_db = self.engine.start_workflow('wb.wf1', {'wait_before': 1})

        # Note: We need to reread execution to access related tasks.
        exec_db = db_api.get_execution(exec_db.id)
        task_db = exec_db.task_executions[0]

        self.assertEqual(states.RUNNING_DELAYED, task_db.state)

        self.await_execution_success(exec_db.id)
예제 #20
0
    def test_wait_before_policy_from_var(self):
        wb_service.create_workbook_v2(WAIT_BEFORE_FROM_VAR)

        # Start workflow.
        exec_db = self.engine.start_workflow('wb.wf1', {'wait_before': 1})

        # Note: We need to reread execution to access related tasks.
        exec_db = db_api.get_execution(exec_db.id)
        task_db = exec_db.task_executions[0]

        self.assertEqual(states.RUNNING_DELAYED, task_db.state)

        self._await(lambda: self.is_execution_success(exec_db.id))
예제 #21
0
    def test_with_items_subflow_concurrency_gt_list_length(self):
        wb_text = """---
        version: "2.0"
        name: wb1

        workflows:
          main:
            type: direct

            input:
             - names

            tasks:
              task1:
                with-items: name in <% $.names %>
                workflow: subflow1 name=<% $.name %>
                concurrency: 3

          subflow1:
            type: direct

            input:
                - name
            output:
              result: <% task(task1).result %>

            tasks:
              task1:
                action: std.echo output=<% $.name %>
        """

        wb_service.create_workbook_v2(wb_text)

        # Start workflow.
        names = ["Peter", "Susan", "Edmund", "Lucy", "Aslan", "Caspian"]
        wf_ex = self.engine.start_workflow('wb1.main', {'names': names})

        self.await_execution_success(wf_ex.id)

        wf_ex = db_api.get_execution(wf_ex.id)

        task_ex = self._assert_single_item(wf_ex.task_executions,
                                           name='task1',
                                           state=states.SUCCESS)

        result = [
            item['result']
            for item in data_flow.get_task_execution_result(task_ex)
        ]

        self.assertListEqual(sorted(result), sorted(names))
    def test_expiration_policy_for_executions(self):
        # Delete execution uses a secured filtering and we need
        # to verify that admin able to do that for other projects.
        cfg.CONF.set_default('auth_enable', True, group='pecan')

        # Since we are removing other projects execution,
        # we want to load the executions with other project_id.
        _switch_context('non_admin_project', False)

        _load_executions()

        now = datetime.datetime.now()

        # This execution has a parent wf and testing that we are
        # querying only for parent wfs.
        exec_child = db_api.get_execution('654')

        self.assertEqual('789', exec_child.task_execution_id)

        # Call for all expired wfs execs.
        execs = db_api.get_expired_executions(now)

        # Should be only 3, the RUNNING execution shouldn't return,
        # so the child wf (that has parent task id).
        self.assertEqual(3, len(execs))

        # Switch context to Admin since expiration policy running as Admin.
        _switch_context(None, True)

        # TODO(m4dcoder): The expiration policy is changed here to expire
        # executions older than 30 minutes. It was originally 10 minutes.
        # The unit test below expects 1 execution to remain after the policy
        # is applied. However, the unit test fail frequently because the
        # process that deletes the expired executions seem to run late and
        # all executions are deleted. The unit tests seems to run better if
        # the config is changed to 30 minutes. Troubleshoot the expiration
        # policy to identify cause of the delay.
        _set_expiration_policy_config(1, 30)
        expiration_policy.run_execution_expiration_policy(self, ctx)

        # Only non_expired available (update_at < older_than).
        execs = db_api.get_expired_executions(now)

        self.assertEqual(1, len(execs))
        self.assertEqual('987', execs[0].id)

        _set_expiration_policy_config(1, 5)
        expiration_policy.run_execution_expiration_policy(self, ctx)
        execs = db_api.get_expired_executions(now)

        self.assertEqual(0, len(execs))
    def test_expiration_policy_for_executions(self):
        # Delete execution uses a secured filtering and we need
        # to verify that admin able to do that for other projects.
        cfg.CONF.set_default('auth_enable', True, group='pecan')

        # Since we are removing other projects execution,
        # we want to load the executions with other project_id.
        _switch_context('non_admin_project', False)

        _load_executions()

        now = datetime.datetime.now()

        # This execution has a parent wf and testing that we are
        # querying only for parent wfs.
        exec_child = db_api.get_execution('654')

        self.assertEqual('789', exec_child.task_execution_id)

        # Call for all expired wfs execs.
        execs = db_api.get_expired_executions(now)

        # Should be only 3, the RUNNING execution shouldn't return,
        # so the child wf (that has parent task id).
        self.assertEqual(3, len(execs))

        # Switch context to Admin since expiration policy running as Admin.
        _switch_context(None, True)

        _set_expiration_policy_config(1, 30)
        expiration_policy.run_execution_expiration_policy(self, ctx)

        # Only non_expired available (update_at < older_than).
        execs = db_api.get_expired_executions(now)

        self.assertEqual(1, len(execs))
        self.assertEqual('987', execs[0].id)

        _set_expiration_policy_config(1, 5)
        expiration_policy.run_execution_expiration_policy(self, ctx)
        execs = db_api.get_expired_executions(now)

        self.assertEqual(0, len(execs))
    def test_expiration_policy_for_executions(self):
        # Delete execution uses a secured filtering and we need
        # to verify that admin able to do that for other projects.
        cfg.CONF.set_default('auth_enable', True, group='pecan')

        # Since we are removing other projects execution,
        # we want to load the executions with other project_id.
        _switch_context('non_admin_project', False)

        _load_executions()

        now = datetime.datetime.now()

        # This execution has a parent wf and testing that we are
        # querying only for parent wfs.
        exec_child = db_api.get_execution('654')

        self.assertEqual('789', exec_child.task_execution_id)

        # Call for all expired wfs execs.
        execs = db_api.get_expired_executions(now)

        # Should be only 3, the RUNNING execution shouldn't return,
        # so the child wf (that has parent task id).
        self.assertEqual(3, len(execs))

        # Switch context to Admin since expiration policy running as Admin.
        _switch_context(None, True)

        _set_expiration_policy_config(1, 30)
        expiration_policy.run_execution_expiration_policy(self, ctx)

        # Only non_expired available (update_at < older_than).
        execs = db_api.get_expired_executions(now)

        self.assertEqual(1, len(execs))
        self.assertEqual('987', execs[0].id)

        _set_expiration_policy_config(1, 5)
        expiration_policy.run_execution_expiration_policy(self, ctx)
        execs = db_api.get_expired_executions(now)

        self.assertEqual(0, len(execs))
예제 #25
0
    def test_with_items_concurrency_2_fail(self):
        workflow_with_concurrency_2_fail = """---
        version: "2.0"

        concurrency_test_fail:
          type: direct

          tasks:
            task1:
              with-items: i in [1, 2, 3, 4]
              action: std.fail
              concurrency: 2
              on-error: task2

            task2:
              action: std.echo output="With-items failed"

        """
        wf_service.create_workflows(workflow_with_concurrency_2_fail)

        # Start workflow.
        wf_ex = self.engine.start_workflow('concurrency_test_fail', {})

        self._await(
            lambda: self.is_execution_success(wf_ex.id),
        )
        wf_ex = db_api.get_execution(wf_ex.id)

        task_exs = wf_ex.task_executions

        self.assertEqual(2, len(task_exs))

        task_2 = self._assert_single_item(task_exs, name='task2')

        self.assertEqual(
            "With-items failed",
            data_flow.get_task_execution_result(task_2)
        )
예제 #26
0
 def is_execution_in_state(self, ex_id, state):
     return db_api.get_execution(ex_id).state == state
예제 #27
0
 def is_execution_in_state(self, ex_id, state):
     return db_api.get_execution(ex_id).state == state
예제 #28
0
    def test_with_items_concurrency_3(self):
        wf_with_concurrency_3 = """---
        version: "2.0"

        concurrency_test:
          type: direct

          input:
           - names: ["John", "Ivan", "Mistral"]

          tasks:
            task1:
              action: std.async_noop
              with-items: name in <% $.names %>
              concurrency: 3

        """

        wf_service.create_workflows(wf_with_concurrency_3)

        # Start workflow.
        wf_ex = self.engine.start_workflow('concurrency_test', {})

        wf_ex = db_api.get_execution(wf_ex.id)
        task_ex = wf_ex.task_executions[0]

        self.assert_capacity(0, task_ex)
        self.assertEqual(3, self.get_running_action_exs_number(task_ex))

        # 1st iteration complete.
        self.engine.on_action_complete(
            self.get_incomplete_action_ex(task_ex).id, wf_utils.Result("John"))

        task_ex = db_api.get_task_execution(task_ex.id)

        self.assert_capacity(1, task_ex)

        # 2nd iteration complete.
        self.engine.on_action_complete(
            self.get_incomplete_action_ex(task_ex).id, wf_utils.Result("Ivan"))

        task_ex = db_api.get_task_execution(task_ex.id)

        self.assert_capacity(2, task_ex)

        # 3rd iteration complete.
        self.engine.on_action_complete(
            self.get_incomplete_action_ex(task_ex).id,
            wf_utils.Result("Mistral"))

        task_ex = db_api.get_task_execution(task_ex.id)

        self.assert_capacity(3, task_ex)

        self.await_execution_success(wf_ex.id)

        task_ex = db_api.get_task_execution(task_ex.id)

        self.assertEqual(states.SUCCESS, task_ex.state)

        # Since we know that we can receive results in random order,
        # check is not depend on order of items.
        result = data_flow.get_task_execution_result(task_ex)

        self.assertIsInstance(result, list)

        self.assertIn('John', result)
        self.assertIn('Ivan', result)
        self.assertIn('Mistral', result)
예제 #29
0
    def test_with_items_concurrency_3(self):
        workflow_with_concurrency_3 = """---
        version: "2.0"

        concurrency_test:
          type: direct

          input:
           - names: ["John", "Ivan", "Mistral"]

          tasks:
            task1:
              action: std.async_noop
              with-items: name in <% $.names %>
              concurrency: 3

        """
        wf_service.create_workflows(workflow_with_concurrency_3)

        # Start workflow.
        wf_ex = self.engine.start_workflow('concurrency_test', {})
        wf_ex = db_api.get_execution(wf_ex.id)
        task_ex = wf_ex.task_executions[0]

        self.assert_capacity(0, task_ex)
        self.assertEqual(3, self.get_running_action_exs_number(task_ex))

        # 1st iteration complete.
        self.engine.on_action_complete(
            self.get_incomplete_action_ex(task_ex).id,
            wf_utils.Result("John")
        )

        task_ex = db_api.get_task_execution(task_ex.id)
        self.assert_capacity(1, task_ex)

        # 2nd iteration complete.
        self.engine.on_action_complete(
            self.get_incomplete_action_ex(task_ex).id,
            wf_utils.Result("Ivan")
        )

        task_ex = db_api.get_task_execution(task_ex.id)
        self.assert_capacity(2, task_ex)

        # 3rd iteration complete.
        self.engine.on_action_complete(
            self.get_incomplete_action_ex(task_ex).id,
            wf_utils.Result("Mistral")
        )

        task_ex = db_api.get_task_execution(task_ex.id)
        self.assert_capacity(3, task_ex)

        self._await(
            lambda: self.is_execution_success(wf_ex.id),
        )

        task_ex = db_api.get_task_execution(task_ex.id)
        # Since we know that we can receive results in random order,
        # check is not depend on order of items.
        result = data_flow.get_task_execution_result(task_ex)
        self.assertTrue(isinstance(result, list))

        self.assertIn('John', result)
        self.assertIn('Ivan', result)
        self.assertIn('Mistral', result)

        self.assertEqual(states.SUCCESS, task_ex.state)