Пример #1
0
    def test_split(self):
        test_spec = {
            "workflow":
            self.get_wf_file_path("split"),
            "expected_routes": [
                [],  # default from start
                ["task2__t0"],  # task1 -> task2 -> task4
                ["task3__t0"],  # task1 -> task3 -> task4
            ],
            "expected_task_sequence": [
                "task1__r0",
                "task2__r0",
                "task3__r0",
                "task4__r1",
                "task4__r2",
                "task5__r1",
                "task5__r2",
                "task6__r1",
                "task6__r2",
                "task7__r1",
                "task7__r2",
            ],
            "expected_term_tasks": ["task7__r1", "task7__r2"],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #2
0
    def test_splits_mixed(self):
        test_spec = {
            "workflow":
            self.get_wf_file_path("splits-mixed"),
            "expected_routes": [
                [],
                ["task1__t0"],  # task1 -> task3
                ["task2__t0"],  # task2 -> task3
                ["task1__t0", "task3__t0"],  # task1 -> task3 -> task4
                ["task2__t0", "task3__t0"],  # task2 -> task3 -> task4
            ],
            "expected_task_sequence": [
                "task1__r0",
                "task2__r0",
                "task3__r1",
                "task3__r2",
                "task4__r3",
                "task4__r4",
                "task5__r3",
                "task5__r4",
            ],
            "expected_term_tasks": ["task5__r3", "task5__r4"],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #3
0
    def test_splits_mixed_alt_branch(self):
        test_spec = {
            "workflow":
            self.get_wf_file_path("splits-mixed"),
            "expected_routes": [
                [],
                ["task1__t0"],  # task1 -> task3
                ["task2__t0"],  # task2 -> task3
                ["task1__t0", "task3__t0"],  # task1 -> task3 -> task4
                ["task2__t0", "task3__t1"],  # task2 -> task3 -> task4
            ],
            "expected_task_sequence": [
                "task1__r0",
                "task2__r0",
                "task3__r1",
                "task3__r2",
                "task4__r3",
                "task4__r4",
                "task5__r3",
                "task5__r4",
            ],
            "mock_action_executions": [
                {
                    "task_id": "task3"
                },  # task3, 1
                {
                    "task_id": "task3",
                    "status": statuses.FAILED
                },  # task3, 2
            ],
            "expected_term_tasks": ["task5__r3", "task5__r4"],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #4
0
    def test_fail_multiple_before_join(self):
        # Initial run of workflow.
        test_spec = {
            "workflow":
            self.get_wf_file_path("join"),
            # Fail task3 before join at task6.
            "expected_task_sequence":
            ["task1", "task2", "task4", "task3", "task5"],
            "mock_action_executions": [
                {
                    "task_id": "task3",
                    "status": statuses.FAILED
                },
                {
                    "task_id": "task5",
                    "status": statuses.FAILED
                },
            ],
            "expected_term_tasks": ["task3", "task5"],
            "expected_workflow_status":
            statuses.FAILED,
        }

        rehearsal1 = rehearsing.load_test_spec(test_spec)
        rehearsal1.assert_conducting_sequence()

        # Rerun and complete workflow.
        test_spec = {
            "workflow_state":
            rehearsal1.conductor.serialize(),
            "expected_task_sequence": [
                "task1",
                "task2",
                "task4",
                "task3",
                "task5",
                "task3",
                "task5",
                "task6",
                "task7",
            ],
            "expected_term_tasks": ["task7"],
        }

        rehearsal2 = rehearsing.load_test_spec(test_spec)
        rehearsal2.assert_conducting_sequence()
    def test_error_noop_success_path(self):
        test_spec = {
            "workflow": self.get_wf_file_path("error-handling-noop"),
            "expected_task_sequence": ["task1", "task2", "continue"],
            "expected_output": {"message": "hooray!!!"},
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #6
0
    def test_no_error(self):
        test_spec = {
            "workflow": self.get_wf_file_path("error-handling"),
            "expected_task_sequence": ["task1", "task2"],
            "expected_term_tasks": ["task2"],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #7
0
    def test_on_complete_from_succeeded_branch(self):
        test_spec = {
            "workflow": self.get_wf_file_path("task-on-complete"),
            "expected_task_sequence": ["task1", "task2", "task4"],
            "expected_term_tasks": ["task2", "task4"],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #8
0
    def test_join_count_not_satisfied(self):
        test_spec = {
            "workflow":
            self.get_wf_file_path("join-count"),
            # Mock errors at branch 2 and 3. The criteria for join task is not met.
            "expected_task_sequence": [
                "task1",
                "task2",
                "task4",
                "task6",
                "task3",
                "task5",
                "task7",
                "noop__r1",
                "noop__r2",
            ],
            "expected_routes": [[], ["task5__t0"], ["task7__t0"]],
            "mock_action_executions": [
                {
                    "task_id": "task5",
                    "status": statuses.FAILED
                },
                {
                    "task_id": "task7",
                    "status": statuses.FAILED
                },
            ],
            "expected_workflow_status":
            statuses.FAILED,
            "expected_errors": [
                {
                    "message": "Execution failed. See result for details.",
                    "type": "error",
                    "task_id": "task5",
                },
                {
                    "message": "Execution failed. See result for details.",
                    "type": "error",
                    "task_id": "task7",
                },
                {
                    "message":
                    ('UnreachableJoinError: The join task|route "task8|0" '
                     "is partially satisfied but unreachable."),
                    "type":
                    "error",
                    "route":
                    0,
                    "task_id":
                    "task8",
                },
            ],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #9
0
    def test_branching(self):
        test_spec = {
            "workflow":
            self.get_wf_file_path("branching"),
            "expected_task_sequence":
            ["task1", "task2", "task4", "task3", "task5"],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #10
0
    def test_join_task_transition_on_failed_both_branches_succeeded(self):
        test_spec = {
            "workflow":
            self.get_wf_file_path("join-on-fail"),
            "expected_task_sequence":
            ["task1", "task2", "task4", "task3", "task5"],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #11
0
    def test_join_count_not_satisfied_no_inbound(self):
        test_spec = {
            "workflow":
            self.get_wf_file_path("join-count"),
            # Mock all branches failed. The criteria for join task is not met.
            "expected_task_sequence": [
                "task1",
                "task2",
                "task4",
                "task6",
                "task3",
                "task5",
                "task7",
                "noop__r1",
                "noop__r2",
            ],
            "expected_routes": [[], ["task5__t0"], ["task7__t0"]],
            "mock_action_executions": [
                {
                    "task_id": "task3",
                    "status": statuses.FAILED
                },
                {
                    "task_id": "task5",
                    "status": statuses.FAILED
                },
                {
                    "task_id": "task7",
                    "status": statuses.FAILED
                },
            ],
            "expected_workflow_status":
            statuses.FAILED,
            "expected_errors": [
                {
                    "message": "Execution failed. See result for details.",
                    "type": "error",
                    "task_id": "task3",
                },
                {
                    "message": "Execution failed. See result for details.",
                    "type": "error",
                    "task_id": "task5",
                },
                {
                    "message": "Execution failed. See result for details.",
                    "type": "error",
                    "task_id": "task7",
                },
            ],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
    def test_error_noop_failure_path(self):
        test_spec = {
            "workflow": self.get_wf_file_path("error-handling-noop"),
            "expected_task_sequence": ["task1", "noop"],
            "mock_action_executions": [
                {"task_id": "task1", "status": statuses.FAILED},
            ],
            "expected_output": {"message": "$%#&@#$!!!"},
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
    def test_load_test_spec_dict_with_expected_inspection_errors(self):
        test_spec = {
            "workflow": self.get_wf_file_path("sequential"),
            "expected_task_sequence": ["task1", "task2", "task3", "continue"],
            "expected_inspection_errors": {
                "syntax": [{
                    "message":
                    "['foobar'] is not of type 'string'",
                    "schema_path":
                    ("properties.tasks.patternProperties.^\\w+$."
                     "properties.next.items.properties.when.type"),
                    "spec_path":
                    "tasks.task1.next[0].when",
                }],
                "context": [
                    {
                        "type":
                        "yaql",
                        "expression":
                        '<% ctx("__xyz") %>',
                        "spec_path":
                        "output[0]",
                        "schema_path":
                        "properties.output",
                        "message":
                        ('Variable "__xyz" that is prefixed with double underscores '
                         "is considered a private variable and cannot be referenced."
                         ),
                    },
                ],
            },
        }

        rehearsal = rehearsing.load_test_spec(test_spec)

        self.assertEqual(
            len(rehearsal.session.expected_inspection_errors.syntax), 1)
        syntax_error = rehearsal.session.expected_inspection_errors.syntax[0]
        self.assertIsNone(syntax_error.type)
        self.assertIsNone(syntax_error.expression)
        self.assertEqual(syntax_error.message,
                         "['foobar'] is not of type 'string'")
        self.assertEqual(syntax_error.spec_path, "tasks.task1.next[0].when")
        self.assertIn("properties.tasks.patternProperties",
                      syntax_error.schema_path)

        self.assertEqual(
            len(rehearsal.session.expected_inspection_errors.context), 1)
        context_error = rehearsal.session.expected_inspection_errors.context[0]
        self.assertEqual(context_error.type, "yaql")
        self.assertEqual(context_error.expression, '<% ctx("__xyz") %>')
        self.assertEqual(context_error.schema_path, "properties.output")
        self.assertIn('Variable "__xyz"', context_error.message)
    def test_error_continue_success_path(self):
        test_spec = {
            "workflow": self.get_wf_file_path("error-handling-continue"),
            "expected_task_sequence": ["task1", "task2", "continue__r1"],
            "expected_routes": [
                [],  # default from start
                ["task2__t0"],  # task1 -> task2 -> continue
            ],
            "expected_output": {"message": "hooray!!!"},
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #15
0
    def test_on_error(self):
        test_spec = {
            "workflow":
            self.get_wf_file_path("error-handling"),
            "expected_task_sequence": ["task1", "task3"],
            "mock_action_executions": [{
                "task_id": "task1",
                "status": statuses.FAILED
            }],
            "expected_term_tasks": ["task3"],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
    def test_items_list_with_error(self):
        test_spec = {
            "workflow": self.get_wf_file_path("with-items-transition"),
            "expected_task_sequence": ["task1"],
            "mock_action_executions": [
                {"task_id": "task1", "result": "fee", "item_id": 0},
                {"task_id": "task1", "result": "fi", "item_id": 1},
                {"task_id": "task1", "result": "fo", "item_id": 2, "status": statuses.FAILED},
            ],
            "expected_workflow_status": statuses.FAILED,
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #17
0
    def test_very_many_splits(self):
        test_spec = {
            "workflow":
            self.get_wf_file_path("splits-very-many"),
            "expected_routes": [
                [],
                ["init__t1"],
                ["init__t0"],
                ["init__t0", "task2__t0"],
                ["init__t0", "task2__t0", "task7__t0"],
                ["init__t0", "task2__t0", "task7__t0", "task10__t0"],
                [
                    "init__t0", "task2__t0", "task7__t0", "task10__t0",
                    "task13__t0"
                ],
                [
                    "init__t0", "task2__t0", "task7__t0", "task10__t0",
                    "task13__t0", "task15__t0"
                ],
                [
                    "init__t0",
                    "task2__t0",
                    "task7__t0",
                    "task10__t0",
                    "task13__t0",
                    "task15__t0",
                    "task17__t0",
                ],
            ],
            "expected_task_sequence": [
                "init__r0",
                "notify__r1",
                "task2__r2",
                "task5__r3",
                "task7__r3",
                "task9__r4",
                "task10__r4",
                "task11__r5",
                "task12__r5",
                "task13__r5",
                "task14__r6",
                "task15__r6",
                "task17__r7",
                "notify__r8",
            ],
            "expected_term_tasks": ["notify__r1", "notify__r8"],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #18
0
    def test_on_complete_from_failed_branch(self):
        test_spec = {
            "workflow":
            self.get_wf_file_path("task-on-complete"),
            "expected_task_sequence": ["task1", "task3", "task4"],
            "mock_action_executions": [{
                "task_id": "task1",
                "status": statuses.FAILED
            }],
            "expected_term_tasks": ["task3", "task4"],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
    def test_items_list_with_error_and_remediation(self):
        test_spec = {
            "workflow": self.get_wf_file_path("with-items-remediate"),
            "expected_task_sequence": ["task1", "task2"],
            "mock_action_executions": [
                {"task_id": "task1", "result": "fee", "item_id": 0},
                {"task_id": "task1", "result": "fi", "item_id": 1},
                {"task_id": "task1", "result": None, "item_id": 2, "status": statuses.FAILED},
            ],
            "expected_output": {"items": ["fee", "fi", None]},
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
    def test_error_concurrent_log_fail(self):
        mock_result = "All your base are belong to us!"

        test_spec = {
            "workflow": self.get_wf_file_path("error-log-fail-concurrent"),
            "expected_task_sequence": ["task1", "fail", "log"],
            "mock_action_executions": [
                {"task_id": "task1", "status": statuses.FAILED, "result": mock_result},
            ],
            "expected_workflow_status": statuses.FAILED,
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #21
0
    def test_decision_tree(self):
        # Test branch "a"
        test_spec = {
            "workflow": self.get_wf_file_path("decision"),
            "inputs": {
                "which": "a"
            },
            "expected_task_sequence": ["t1", "a"],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()

        # Test branch "b"
        test_spec = {
            "workflow": self.get_wf_file_path("decision"),
            "inputs": {
                "which": "b"
            },
            "expected_task_sequence": ["t1", "b"],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()

        # Test branch "c"
        test_spec = {
            "workflow": self.get_wf_file_path("decision"),
            "inputs": {
                "which": "c"
            },
            "expected_task_sequence": ["t1", "c"],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
    def test_basic_items_list(self):
        test_spec = {
            "workflow": self.get_wf_file_path("with-items-transition"),
            "expected_task_sequence": ["task1", "task2"],
            "mock_action_executions": [
                {"task_id": "task1", "result": "fee", "item_id": 0},
                {"task_id": "task1", "result": "fi", "item_id": 1},
                {"task_id": "task1", "result": "fo", "item_id": 2},
                {"task_id": "task1", "result": "fum", "item_id": 3},
            ],
            "expected_output": {"items": ["fee", "fi", "fo", "fum"]},
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #23
0
    def test_task_transitions_split_from_succeeded_branch(self):
        test_spec = {
            "workflow":
            self.get_wf_file_path("task-transitions-split"),
            "expected_routes": [
                [],  # default from start
                ["task1__t0"],  # task1 -> task2 (when #1)
                ["task1__t2"],  # task1 -> task2 (when #3)
            ],
            "expected_task_sequence": ["task1__r0", "task2__r1", "task2__r2"],
            "expected_term_tasks": ["task2__r1", "task2__r2"],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #24
0
def process(base_path, test_spec):
    fixture_path = "%s/%s" % (base_path, test_spec)

    if not os.path.isfile(fixture_path):
        raise exc.WorkflowRehearsalError('The test spec "%s" does not exist.' %
                                         fixture_path)

    rehearsal = rehearsing.load_test_spec(fixture_path=test_spec,
                                          base_path=base_path)
    LOG.info('The test spec "%s" is successfully loaded.' % fixture_path)

    rehearsal.assert_conducting_sequence()
    LOG.info(
        "Completed running test and the workflow execution matches the test spec."
    )
    def test_load_test_spec_dict_with_expected_errors(self):
        test_spec = {
            "workflow":
            self.get_wf_file_path("sequential"),
            "expected_task_sequence": ["task1", "task2"],
            "mock_action_executions": [{
                "task_id": "task2",
                "status": statuses.FAILED
            }],
            "expected_errors": [
                {
                    "type": "error",
                    "message": "Unknown exception at task2."
                },
                {
                    "type": "error",
                    "message": "Stuff happens.",
                    "task_id": "task2"
                },
            ],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)

        self.assertEqual(len(rehearsal.session.mock_action_executions), 1)
        self.assertEqual(rehearsal.session.mock_action_executions[0].task_id,
                         "task2")

        self.assertEqual(len(rehearsal.session.expected_errors), 2)
        self.assertEqual(rehearsal.session.expected_errors[0].type, "error")
        self.assertEqual(rehearsal.session.expected_errors[0].message,
                         "Unknown exception at task2.")
        self.assertIsNone(rehearsal.session.expected_errors[0].task_id)
        self.assertIsNone(rehearsal.session.expected_errors[0].route)
        self.assertIsNone(
            rehearsal.session.expected_errors[0].task_transition_id)
        self.assertIsNone(rehearsal.session.expected_errors[0].result)
        self.assertIsNone(rehearsal.session.expected_errors[0].data)
        self.assertEqual(rehearsal.session.expected_errors[1].type, "error")
        self.assertEqual(rehearsal.session.expected_errors[1].message,
                         "Stuff happens.")
        self.assertEqual(rehearsal.session.expected_errors[1].task_id, "task2")
        self.assertIsNone(rehearsal.session.expected_errors[1].route)
        self.assertIsNone(
            rehearsal.session.expected_errors[1].task_transition_id)
        self.assertIsNone(rehearsal.session.expected_errors[1].result)
        self.assertIsNone(rehearsal.session.expected_errors[1].data)
Пример #26
0
    def test_join_context(self):
        test_spec = {
            "workflow":
            self.get_wf_file_path("join-context"),
            "expected_task_sequence": [
                "task1",
                "task2",
                "task4",
                "task6",
                "task8",
                "task3",
                "task5",
                "task7",
                "task9",
                "task10",
            ],
            "mock_action_executions": [
                {
                    "task_id": "task2",
                    "result": "Fee fi"
                },
                {
                    "task_id": "task4",
                    "result": "I smell the blood of an English man"
                },
                {
                    "task_id": "task3",
                    "result": "fo fum"
                },
                {
                    "task_id": "task7",
                    "result": "Be alive, or be he dead"
                },
            ],
            "expected_output": {
                "messages": [
                    "Fee fi fo fum",
                    "I smell the blood of an English man",
                    "Be alive, or be he dead",
                    "I'll grind his bones to make my bread",
                ]
            },
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
    def test_error_continue_failure_path(self):
        test_spec = {
            "workflow": self.get_wf_file_path("error-handling-continue"),
            "expected_task_sequence": ["task1", "continue__r1"],
            "expected_routes": [
                [],  # default from start
                ["task1__t0"],  # task1 -> continue
            ],
            "mock_action_executions": [
                {"task_id": "task1", "status": statuses.FAILED},
            ],
            "expected_workflow_status": statuses.FAILED,
            "expected_output": {"message": "$%#&@#$!!!"},
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #28
0
    def test_splits_multiple_transition(self):
        test_spec = {
            "workflow":
            self.get_wf_file_path("splits-transition"),
            "expected_routes": [
                [],
                ["task1__t0"],  # task1 -> task3
                ["task2__t0"],  # task2 -> task3
                ["task1__t0",
                 "task3__t0"],  # task1 -> task3 -> task4 (when #1)
                ["task1__t0",
                 "task3__t1"],  # task1 -> task3 -> task4 (when #2)
                ["task2__t0",
                 "task3__t0"],  # task2 -> task3 -> task4 (when #1)
                ["task2__t0",
                 "task3__t1"],  # task2 -> task3 -> task4 (when #2)
            ],
            "expected_task_sequence": [
                "task1__r0",
                "task2__r0",
                "task3__r1",
                "task3__r2",
                "task4__r3",
                "task4__r4",
                "task4__r5",
                "task4__r6",
                "task5__r3",
                "task5__r4",
                "task5__r5",
                "task5__r6",
                "task6__r3",
                "task6__r4",
                "task6__r5",
                "task6__r6",
                "task7__r3",
                "task7__r4",
                "task7__r5",
                "task7__r6",
            ],
            "expected_term_tasks":
            ["task7__r3", "task7__r4", "task7__r5", "task7__r6"],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #29
0
    def test_join_task_transition_on_completed_both_branches_succeeded(self):
        test_spec = {
            "workflow":
            self.get_wf_file_path("join-on-complete"),
            # The tasks before the join, task3 and task5, both succeeded.
            "expected_task_sequence": [
                "task1",
                "task2",
                "task4",
                "task3",
                "task5",
                "task6",
                "task7",
            ],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()
Пример #30
0
    def test_task_transitions_split_from_failed_branch(self):
        test_spec = {
            "workflow":
            self.get_wf_file_path("task-transitions-split"),
            "expected_routes": [
                [],  # default from start
                ["task1__t0"],  # task1 -> task2 (when #1)
                ["task1__t1"],  # task1 -> task2 (when #2)
            ],
            "expected_task_sequence": ["task1__r0", "task2__r1", "task2__r2"],
            "mock_action_executions": [{
                "task_id": "task1",
                "status": statuses.FAILED
            }],
            "expected_term_tasks": ["task2__r1", "task2__r2"],
        }

        rehearsal = rehearsing.load_test_spec(test_spec)
        rehearsal.assert_conducting_sequence()