cleaned up process model tests and added support for service tasks w/ burnettk
This commit is contained in:
parent
acaf3a3c24
commit
40c67f000c
|
@ -36,6 +36,10 @@ class MissingBpmnFileForTestCaseError(Exception):
|
|||
pass
|
||||
|
||||
|
||||
class NoTestCasesFoundError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class TestCaseResult:
|
||||
passed: bool
|
||||
|
@ -95,6 +99,8 @@ class ProcessModelTestRunner:
|
|||
return len(failed_tests) < 1
|
||||
|
||||
def run(self) -> None:
|
||||
if len(self.test_mappings.items()) < 1:
|
||||
raise NoTestCasesFoundError(f"Could not find any test cases in given directory: {self.process_model_directory_for_test_discovery}")
|
||||
for json_test_case_file, bpmn_file in self.test_mappings.items():
|
||||
with open(json_test_case_file) as f:
|
||||
json_file_contents = json.loads(f.read())
|
||||
|
@ -189,21 +195,14 @@ class ProcessModelTestRunner:
|
|||
return self.instantiate_executer_callback(bpmn_file)
|
||||
return self._default_instantiate_executer(bpmn_file)
|
||||
|
||||
def _get_ready_engine_steps(self, bpmn_process_instance: BpmnWorkflow) -> list[SpiffTask]:
|
||||
tasks = list([t for t in bpmn_process_instance.get_tasks(TaskState.READY) if not t.task_spec.manual])
|
||||
if len(tasks) > 0:
|
||||
tasks = [tasks[0]]
|
||||
|
||||
return tasks
|
||||
|
||||
def _default_get_next_task(self, bpmn_process_instance: BpmnWorkflow) -> Optional[SpiffTask]:
|
||||
engine_steps = self._get_ready_engine_steps(bpmn_process_instance)
|
||||
if len(engine_steps) > 0:
|
||||
return engine_steps[0]
|
||||
ready_tasks = list([t for t in bpmn_process_instance.get_tasks(TaskState.READY)])
|
||||
if len(ready_tasks) > 0:
|
||||
return ready_tasks[0]
|
||||
return None
|
||||
|
||||
def _default_execute_task(self, spiff_task: SpiffTask, test_case_task_properties: Optional[dict]) -> None:
|
||||
if spiff_task.task_spec.manual:
|
||||
if spiff_task.task_spec.manual or spiff_task.task_spec.__class__.__name__ == 'ServiceTask':
|
||||
if test_case_task_properties and 'data' in test_case_task_properties:
|
||||
spiff_task.update_data(test_case_task_properties['data'])
|
||||
spiff_task.complete()
|
||||
|
@ -274,40 +273,3 @@ class ProcessModelTestRunnerService:
|
|||
|
||||
def run(self) -> None:
|
||||
self.process_model_test_runner.run()
|
||||
|
||||
def _execute_task_callback(self, spiff_task: SpiffTask, _test_case_json: Optional[dict]) -> None:
|
||||
spiff_task.run()
|
||||
|
||||
def _get_next_task_callback(self, bpmn_process_instance: BpmnWorkflow) -> Optional[SpiffTask]:
|
||||
engine_steps = self._get_ready_engine_steps(bpmn_process_instance)
|
||||
if len(engine_steps) > 0:
|
||||
return engine_steps[0]
|
||||
return None
|
||||
|
||||
def _get_ready_engine_steps(self, bpmn_process_instance: BpmnWorkflow) -> list[SpiffTask]:
|
||||
tasks = list([t for t in bpmn_process_instance.get_tasks(TaskState.READY) if not t.task_spec.manual])
|
||||
if len(tasks) > 0:
|
||||
tasks = [tasks[0]]
|
||||
|
||||
return tasks
|
||||
|
||||
def _instantiate_executer_callback(self, bpmn_file: str) -> BpmnWorkflow:
|
||||
parser = MyCustomParser()
|
||||
data = None
|
||||
with open(bpmn_file, "rb") as f_handle:
|
||||
data = f_handle.read()
|
||||
etree_xml_parser = etree.XMLParser(resolve_entities=False)
|
||||
bpmn = etree.fromstring(data, parser=etree_xml_parser)
|
||||
parser.add_bpmn_xml(bpmn, filename=os.path.basename(bpmn_file))
|
||||
sub_parsers = list(parser.process_parsers.values())
|
||||
executable_process = None
|
||||
for sub_parser in sub_parsers:
|
||||
if sub_parser.process_executable:
|
||||
executable_process = sub_parser.bpmn_id
|
||||
if executable_process is None:
|
||||
raise BpmnFileMissingExecutableProcessError(
|
||||
f"Executable process cannot be found in {bpmn_file}. Test cannot run."
|
||||
)
|
||||
bpmn_process_spec = parser.get_spec(executable_process)
|
||||
bpmn_process_instance = BpmnWorkflow(bpmn_process_spec)
|
||||
return bpmn_process_instance
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
|
||||
<bpmn:process id="BasicServiceTaskProcess" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_19ephzh</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_19ephzh" sourceRef="StartEvent_1" targetRef="service_task_one" />
|
||||
<bpmn:endEvent id="Event_132m0z7">
|
||||
<bpmn:incoming>Flow_1dsxn78</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_1dsxn78" sourceRef="service_task_one" targetRef="Event_132m0z7" />
|
||||
<bpmn:serviceTask id="service_task_one" name="Task 2">
|
||||
<bpmn:extensionElements>
|
||||
<spiffworkflow:serviceTaskOperator id="http/GetRequest" resultVariable="bamboo_get_employee">
|
||||
<spiffworkflow:parameters>
|
||||
<spiffworkflow:parameter id="basic_auth_password" type="str" value=""x"" />
|
||||
<spiffworkflow:parameter id="basic_auth_username" type="str" value=""secret:BAMBOOHR_API_KEY"" />
|
||||
<spiffworkflow:parameter id="headers" type="any" value="{"Accept": "application/json"}" />
|
||||
<spiffworkflow:parameter id="params" type="any" value="{"fields": "firstName,lastName"}" />
|
||||
<spiffworkflow:parameter id="url" type="str" value="f"https://api.bamboohr.com/api/gateway.php/statusresearchdemo/v1/employees/113"" />
|
||||
</spiffworkflow:parameters>
|
||||
</spiffworkflow:serviceTaskOperator>
|
||||
<spiffworkflow:instructionsForEndUser>This is the Service Task Unit Test Screen.</spiffworkflow:instructionsForEndUser>
|
||||
<spiffworkflow:postScript />
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_0xx2kop</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_1dsxn78</bpmn:outgoing>
|
||||
</bpmn:serviceTask>
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="BasicServiceTaskProcess">
|
||||
<bpmndi:BPMNEdge id="Flow_19ephzh_di" bpmnElement="Flow_19ephzh">
|
||||
<di:waypoint x="215" y="177" />
|
||||
<di:waypoint x="270" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0xx2kop_di" bpmnElement="Flow_0xx2kop">
|
||||
<di:waypoint x="370" y="177" />
|
||||
<di:waypoint x="430" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_1dsxn78_di" bpmnElement="Flow_1dsxn78">
|
||||
<di:waypoint x="530" y="177" />
|
||||
<di:waypoint x="592" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||
<dc:Bounds x="179" y="159" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_132m0z7_di" bpmnElement="Event_132m0z7">
|
||||
<dc:Bounds x="592" y="159" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_1nlg9cc_di" bpmnElement="service_task_one">
|
||||
<dc:Bounds x="430" y="137" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"description": "A.1.0.2",
|
||||
"display_name": "A.1.0.2 - Service Task",
|
||||
"display_order": 13,
|
||||
"exception_notification_addresses": [],
|
||||
"fault_or_suspend_on_exception": "fault",
|
||||
"files": [],
|
||||
"primary_file_name": "A.1.0.2.bpmn",
|
||||
"primary_process_id": "Process_test_a102_A_1_0_2_bd2e724"
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"test_case_one": {
|
||||
"tasks": {
|
||||
"service_task_one": {
|
||||
"data": { "the_result": "result_from_service" }
|
||||
}
|
||||
},
|
||||
"expected_output_json": { "the_result": "result_from_service" }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
import os
|
||||
from typing import Any
|
||||
from typing import Optional
|
||||
|
||||
import pytest
|
||||
from flask import current_app
|
||||
from flask import Flask
|
||||
from pytest_mock import MockerFixture
|
||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||
|
||||
from spiffworkflow_backend.models.task import TaskModel # noqa: F401
|
||||
from spiffworkflow_backend.services.file_system_service import FileSystemService
|
||||
from spiffworkflow_backend.services.process_model_test_runner_service import NoTestCasesFoundError, ProcessModelTestRunner
|
||||
|
||||
|
||||
class TestProcessModelTestRunner(BaseTest):
|
||||
def test_can_test_a_simple_process_model(
|
||||
self,
|
||||
app: Flask,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_mocked_root_path: Any,
|
||||
) -> None:
|
||||
process_model_test_runner = self._run_model_tests('basic_script_task')
|
||||
assert len(process_model_test_runner.test_case_results) == 1
|
||||
|
||||
def test_will_raise_if_no_tests_found(
|
||||
self,
|
||||
app: Flask,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_mocked_root_path: Any,
|
||||
) -> None:
|
||||
process_model_test_runner = ProcessModelTestRunner(
|
||||
os.path.join(FileSystemService.root_path(), "DNE")
|
||||
)
|
||||
with pytest.raises(NoTestCasesFoundError):
|
||||
process_model_test_runner.run()
|
||||
assert process_model_test_runner.all_test_cases_passed(), process_model_test_runner.test_case_results
|
||||
|
||||
def test_can_test_multiple_process_models_with_all_passing_tests(
|
||||
self,
|
||||
app: Flask,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_mocked_root_path: Any,
|
||||
) -> None:
|
||||
process_model_test_runner = self._run_model_tests()
|
||||
assert len(process_model_test_runner.test_case_results) > 1
|
||||
|
||||
def test_can_test_multiple_process_models_with_failing_tests(
|
||||
self,
|
||||
app: Flask,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_mocked_root_path: Any,
|
||||
) -> None:
|
||||
process_model_test_runner = self._run_model_tests(parent_directory='failing_tests')
|
||||
assert len(process_model_test_runner.test_case_results) == 1
|
||||
|
||||
def test_can_test_process_model_call_activity(
|
||||
self,
|
||||
app: Flask,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_mocked_root_path: Any,
|
||||
) -> None:
|
||||
process_model_test_runner = self._run_model_tests(bpmn_process_directory_name='basic_call_activity')
|
||||
assert len(process_model_test_runner.test_case_results) == 1
|
||||
|
||||
def test_can_test_process_model_with_service_task(
|
||||
self,
|
||||
app: Flask,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_mocked_root_path: Any,
|
||||
) -> None:
|
||||
process_model_test_runner = self._run_model_tests(bpmn_process_directory_name='basic_service_task')
|
||||
assert len(process_model_test_runner.test_case_results) == 1
|
||||
|
||||
def _run_model_tests(self, bpmn_process_directory_name: Optional[str] = None, parent_directory: str = 'passing_tests') -> ProcessModelTestRunner:
|
||||
base_process_model_dir_path_segments = [FileSystemService.root_path(), parent_directory]
|
||||
path_segments = base_process_model_dir_path_segments
|
||||
if bpmn_process_directory_name:
|
||||
path_segments = path_segments + [bpmn_process_directory_name]
|
||||
process_model_test_runner = ProcessModelTestRunner(
|
||||
process_model_directory_path=os.path.join(*base_process_model_dir_path_segments),
|
||||
process_model_directory_for_test_discovery=os.path.join(*path_segments)
|
||||
)
|
||||
process_model_test_runner.run()
|
||||
|
||||
all_tests_expected_to_pass = parent_directory == 'passing_tests'
|
||||
assert process_model_test_runner.all_test_cases_passed() is all_tests_expected_to_pass, process_model_test_runner.test_case_results
|
||||
return process_model_test_runner
|
||||
|
||||
@pytest.fixture()
|
||||
def with_mocked_root_path(self, mocker: MockerFixture) -> None:
|
||||
path = os.path.join(
|
||||
current_app.instance_path,
|
||||
"..",
|
||||
"..",
|
||||
"tests",
|
||||
"data",
|
||||
"bpmn_unit_test_process_models",
|
||||
)
|
||||
mocker.patch.object(FileSystemService, attribute="root_path", return_value=path)
|
|
@ -1,61 +0,0 @@
|
|||
import os
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from flask import current_app
|
||||
from flask import Flask
|
||||
from pytest_mock import MockerFixture
|
||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||
|
||||
from spiffworkflow_backend.models.task import TaskModel # noqa: F401
|
||||
from spiffworkflow_backend.services.file_system_service import FileSystemService
|
||||
from spiffworkflow_backend.services.process_model_test_runner_service import ProcessModelTestRunner, ProcessModelTestRunnerService
|
||||
|
||||
|
||||
class TestProcessModelTestRunnerService(BaseTest):
|
||||
def test_can_test_a_simple_process_model(
|
||||
self,
|
||||
app: Flask,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_mocked_root_path: Any,
|
||||
) -> None:
|
||||
test_runner_service = ProcessModelTestRunnerService(
|
||||
os.path.join(FileSystemService.root_path(), "basic_script_task")
|
||||
)
|
||||
test_runner_service.run()
|
||||
assert test_runner_service.process_model_test_runner.all_test_cases_passed(), test_runner_service.process_model_test_runner.test_case_results
|
||||
|
||||
def test_can_test_multiple_process_models(
|
||||
self,
|
||||
app: Flask,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_mocked_root_path: Any,
|
||||
) -> None:
|
||||
test_runner_service = ProcessModelTestRunnerService(FileSystemService.root_path())
|
||||
test_runner_service.run()
|
||||
assert test_runner_service.process_model_test_runner.all_test_cases_passed() is False
|
||||
|
||||
def test_can_test_process_model_call_activity(
|
||||
self,
|
||||
app: Flask,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_mocked_root_path: Any,
|
||||
) -> None:
|
||||
test_runner_service = ProcessModelTestRunner(
|
||||
process_model_directory_path=FileSystemService.root_path(),
|
||||
process_model_directory_for_test_discovery=os.path.join(FileSystemService.root_path(), "basic_call_activity")
|
||||
)
|
||||
test_runner_service.run()
|
||||
assert test_runner_service.all_test_cases_passed() is True, test_runner_service.test_case_results
|
||||
|
||||
@pytest.fixture()
|
||||
def with_mocked_root_path(self, mocker: MockerFixture) -> None:
|
||||
path = os.path.join(
|
||||
current_app.instance_path,
|
||||
"..",
|
||||
"..",
|
||||
"tests",
|
||||
"data",
|
||||
"bpmn_unit_test_process_models",
|
||||
)
|
||||
mocker.patch.object(FileSystemService, attribute="root_path", return_value=path)
|
Loading…
Reference in New Issue