Bpmn unit test from pi (#1262)
* added most of the code needed to generate a bpmn unit test from a process instance w/ burnettk * pyl and tests are passing * renamed some files and some clean up * added api method to generate test case w/ burnettk * debugging the generate test api w/ burnettk * test case generator test case is now passing w/ burnettk * added test for TaskMismatchError w/ burnettk * added support for extension to create bpmn unit tests with the api w/ burnettk * coderabbit and typeguard fixes w/ burnettk --------- Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
parent
62ba2ed282
commit
a12d2883c1
|
@ -1945,8 +1945,6 @@ files = [
|
|||
{file = "psycopg2-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:426f9f29bde126913a20a96ff8ce7d73fd8a216cfb323b1f04da402d452853c3"},
|
||||
{file = "psycopg2-2.9.9-cp311-cp311-win32.whl", hash = "sha256:ade01303ccf7ae12c356a5e10911c9e1c51136003a9a1d92f7aa9d010fb98372"},
|
||||
{file = "psycopg2-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981"},
|
||||
{file = "psycopg2-2.9.9-cp312-cp312-win32.whl", hash = "sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024"},
|
||||
{file = "psycopg2-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693"},
|
||||
{file = "psycopg2-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:5e0d98cade4f0e0304d7d6f25bbfbc5bd186e07b38eac65379309c4ca3193efa"},
|
||||
{file = "psycopg2-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:7e2dacf8b009a1c1e843b5213a87f7c544b2b042476ed7755be813eaf4e8347a"},
|
||||
{file = "psycopg2-2.9.9-cp38-cp38-win32.whl", hash = "sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c"},
|
||||
|
@ -2286,7 +2284,6 @@ files = [
|
|||
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
|
||||
|
@ -2663,51 +2660,37 @@ python-versions = ">=3.6"
|
|||
files = [
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d92f81886165cb14d7b067ef37e142256f1c6a90a65cd156b063a43da1708cfd"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:b5edda50e5e9e15e54a6a8a0070302b00c518a9d32accc2346ad6c984aacd279"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:7048c338b6c86627afb27faecf418768acb6331fc24cfa56c93e8c9780f815fa"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3fcc54cb0c8b811ff66082de1680b4b14cf8a81dce0d4fbf665c2265a81e07a1"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win32.whl", hash = "sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:665f58bfd29b167039f714c6998178d27ccd83984084c286110ef26b230f259f"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win32.whl", hash = "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9eb5dee2772b0f704ca2e45b1713e4e5198c18f515b52743576d196348f374d3"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5"},
|
||||
{file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15"},
|
||||
{file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"},
|
||||
|
|
|
@ -562,7 +562,7 @@ paths:
|
|||
schema:
|
||||
$ref: "#/components/schemas/ProcessModel"
|
||||
|
||||
/process-model-tests/{modified_process_model_identifier}:
|
||||
/process-model-tests/run/{modified_process_model_identifier}:
|
||||
parameters:
|
||||
- name: modified_process_model_identifier
|
||||
in: path
|
||||
|
@ -589,13 +589,9 @@ paths:
|
|||
- Process Model Tests
|
||||
requestBody:
|
||||
content:
|
||||
multipart/form-data:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
file:
|
||||
type: string
|
||||
format: binary
|
||||
$ref: "#/components/schemas/AwesomeUnspecifiedPayload"
|
||||
responses:
|
||||
"201":
|
||||
description: Metadata about the uploaded file, but not the file content.
|
||||
|
@ -604,6 +600,47 @@ paths:
|
|||
schema:
|
||||
$ref: "#/components/schemas/File"
|
||||
|
||||
/process-model-tests/create/{modified_process_model_identifier}:
|
||||
parameters:
|
||||
- name: modified_process_model_identifier
|
||||
in: path
|
||||
required: true
|
||||
description: The process_model_id, modified to replace slashes (/)
|
||||
schema:
|
||||
type: string
|
||||
- name: test_case_identifier
|
||||
in: query
|
||||
required: false
|
||||
description: The name of the test case file to run
|
||||
schema:
|
||||
type: string
|
||||
post:
|
||||
operationId: spiffworkflow_backend.routes.process_models_controller.process_model_test_generate
|
||||
summary: Create a bpmn unit test from a process instance
|
||||
tags:
|
||||
- Process Model Tests
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
process_instance_id:
|
||||
description: The id of the associated process instance
|
||||
type: number
|
||||
example: 2
|
||||
nullable: false
|
||||
test_case_identifier:
|
||||
description: The name for the new test case
|
||||
type: string
|
||||
nullable: true
|
||||
responses:
|
||||
"201":
|
||||
description: The generated bpmn unit test
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/AwesomeUnspecifiedPayload"
|
||||
|
||||
/process-models/{modified_process_model_identifier}/files:
|
||||
parameters:
|
||||
- name: modified_process_model_identifier
|
||||
|
|
|
@ -55,3 +55,7 @@ class InvalidPermissionError(Exception):
|
|||
|
||||
class InvalidRedirectUrlError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class TaskMismatchError(Exception):
|
||||
pass
|
||||
|
|
|
@ -25,16 +25,19 @@ from spiffworkflow_backend.models.process_model import ProcessModelInfo
|
|||
from spiffworkflow_backend.models.process_model import ProcessModelInfoSchema
|
||||
from spiffworkflow_backend.models.reference_cache import ReferenceCacheModel
|
||||
from spiffworkflow_backend.routes.process_api_blueprint import _commit_and_push_to_git
|
||||
from spiffworkflow_backend.routes.process_api_blueprint import _find_process_instance_by_id_or_raise
|
||||
from spiffworkflow_backend.routes.process_api_blueprint import _get_process_model
|
||||
from spiffworkflow_backend.routes.process_api_blueprint import _un_modify_modified_process_model_id
|
||||
from spiffworkflow_backend.services.file_system_service import FileSystemService
|
||||
from spiffworkflow_backend.services.git_service import GitCommandError
|
||||
from spiffworkflow_backend.services.git_service import GitService
|
||||
from spiffworkflow_backend.services.git_service import MissingGitConfigsError
|
||||
from spiffworkflow_backend.services.process_instance_processor import ProcessInstanceProcessor
|
||||
from spiffworkflow_backend.services.process_instance_report_service import ProcessInstanceReportNotFoundError
|
||||
from spiffworkflow_backend.services.process_instance_report_service import ProcessInstanceReportService
|
||||
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
||||
from spiffworkflow_backend.services.process_model_service import ProcessModelWithInstancesNotDeletableError
|
||||
from spiffworkflow_backend.services.process_model_test_generator_service import ProcessModelTestGeneratorService
|
||||
from spiffworkflow_backend.services.process_model_test_runner_service import ProcessModelTestRunner
|
||||
from spiffworkflow_backend.services.spec_file_service import ProcessModelFileInvalidError
|
||||
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
||||
|
@ -352,6 +355,41 @@ def process_model_test_run(
|
|||
return make_response(jsonify(response_json), 200)
|
||||
|
||||
|
||||
def process_model_test_generate(modified_process_model_identifier: str, body: dict[str, str | int]) -> flask.wrappers.Response:
|
||||
process_instance_id = body["process_instance_id"]
|
||||
|
||||
if process_instance_id is None:
|
||||
raise ApiError(
|
||||
error_code="missing_process_instance_id",
|
||||
message="Process instance id is required to be in the body of request.",
|
||||
status_code=400,
|
||||
)
|
||||
|
||||
test_case_identifier = body.get("test_case_identifier", f"test_case_for_process_instance_{process_instance_id}")
|
||||
process_instance = _find_process_instance_by_id_or_raise(int(process_instance_id))
|
||||
processor = ProcessInstanceProcessor(process_instance, include_task_data_for_completed_tasks=True)
|
||||
process_instance_dict = processor.serialize()
|
||||
test_case_dict = ProcessModelTestGeneratorService.generate_test_from_process_instance_dict(
|
||||
process_instance_dict, test_case_identifier=str(test_case_identifier)
|
||||
)
|
||||
|
||||
process_model_identifier = modified_process_model_identifier.replace(":", "/")
|
||||
process_model = _get_process_model(process_model_identifier)
|
||||
|
||||
if process_model.primary_file_name is None:
|
||||
raise ApiError(
|
||||
error_code="process_model_primary_file_not_set",
|
||||
message="The primary file is not set for the given process model.",
|
||||
status_code=400,
|
||||
)
|
||||
|
||||
primary_file_name_without_extension = ".".join(process_model.primary_file_name.split(".")[0:-1])
|
||||
test_case_file_name = f"test_{primary_file_name_without_extension}.json"
|
||||
ProcessModelService.add_json_data_to_json_file(process_model, test_case_file_name, test_case_dict)
|
||||
|
||||
return make_response(jsonify(test_case_dict), 200)
|
||||
|
||||
|
||||
# {
|
||||
# "natural_language_text": "Create a bug tracker process model \
|
||||
# with a bug-details form that collects summary, description, and priority"
|
||||
|
|
|
@ -72,7 +72,8 @@ PATH_SEGMENTS_FOR_PERMISSION_ALL = [
|
|||
{"path": "/process-instance-terminate", "relevant_permissions": ["create"]},
|
||||
{"path": "/process-model-natural-language", "relevant_permissions": ["create"]},
|
||||
{"path": "/process-model-publish", "relevant_permissions": ["create"]},
|
||||
{"path": "/process-model-tests", "relevant_permissions": ["create"]},
|
||||
{"path": "/process-model-tests/create", "relevant_permissions": ["create"]},
|
||||
{"path": "/process-model-tests/run", "relevant_permissions": ["create"]},
|
||||
{"path": "/task-assign", "relevant_permissions": ["create"]},
|
||||
{"path": "/task-data", "relevant_permissions": ["read", "update"]},
|
||||
]
|
||||
|
|
|
@ -63,6 +63,7 @@ from spiffworkflow_backend.data_stores.kkv import KKVDataStoreConverter
|
|||
from spiffworkflow_backend.data_stores.typeahead import TypeaheadDataStore
|
||||
from spiffworkflow_backend.data_stores.typeahead import TypeaheadDataStoreConverter
|
||||
from spiffworkflow_backend.exceptions.api_error import ApiError
|
||||
from spiffworkflow_backend.exceptions.error import TaskMismatchError
|
||||
from spiffworkflow_backend.models.bpmn_process import BpmnProcessModel
|
||||
from spiffworkflow_backend.models.bpmn_process_definition import BpmnProcessDefinitionModel
|
||||
from spiffworkflow_backend.models.bpmn_process_definition_relationship import BpmnProcessDefinitionRelationshipModel
|
||||
|
@ -408,7 +409,6 @@ class ProcessInstanceProcessor:
|
|||
_serializer = BpmnWorkflowSerializer(wf_spec_converter, version=SPIFFWORKFLOW_BACKEND_SERIALIZER_VERSION)
|
||||
|
||||
PROCESS_INSTANCE_ID_KEY = "process_instance_id"
|
||||
VALIDATION_PROCESS_KEY = "validate_only"
|
||||
|
||||
# __init__ calls these helpers:
|
||||
# * get_spec, which returns a spec and any subprocesses (as IdToBpmnProcessSpecMapping dict)
|
||||
|
@ -416,7 +416,6 @@ class ProcessInstanceProcessor:
|
|||
def __init__(
|
||||
self,
|
||||
process_instance_model: ProcessInstanceModel,
|
||||
validate_only: bool = False,
|
||||
script_engine: PythonScriptEngine | None = None,
|
||||
workflow_completed_handler: WorkflowCompletedHandler | None = None,
|
||||
process_id_to_run: str | None = None,
|
||||
|
@ -429,7 +428,6 @@ class ProcessInstanceProcessor:
|
|||
self.additional_processing_identifier = additional_processing_identifier
|
||||
self.setup_processor_with_process_instance(
|
||||
process_instance_model=process_instance_model,
|
||||
validate_only=validate_only,
|
||||
process_id_to_run=process_id_to_run,
|
||||
include_task_data_for_completed_tasks=include_task_data_for_completed_tasks,
|
||||
)
|
||||
|
@ -437,7 +435,6 @@ class ProcessInstanceProcessor:
|
|||
def setup_processor_with_process_instance(
|
||||
self,
|
||||
process_instance_model: ProcessInstanceModel,
|
||||
validate_only: bool = False,
|
||||
process_id_to_run: str | None = None,
|
||||
include_task_data_for_completed_tasks: bool = False,
|
||||
) -> None:
|
||||
|
@ -482,7 +479,6 @@ class ProcessInstanceProcessor:
|
|||
) = self.__get_bpmn_process_instance(
|
||||
process_instance_model,
|
||||
bpmn_process_spec,
|
||||
validate_only,
|
||||
subprocesses=subprocesses,
|
||||
)
|
||||
self.set_script_engine(self.bpmn_process_instance, self._script_engine)
|
||||
|
@ -819,7 +815,6 @@ class ProcessInstanceProcessor:
|
|||
def __get_bpmn_process_instance(
|
||||
process_instance_model: ProcessInstanceModel,
|
||||
spec: BpmnProcessSpec | None = None,
|
||||
validate_only: bool = False,
|
||||
subprocesses: IdToBpmnProcessSpecMapping | None = None,
|
||||
include_task_data_for_completed_tasks: bool = False,
|
||||
) -> tuple[BpmnWorkflow, dict, dict]:
|
||||
|
@ -840,13 +835,13 @@ class ProcessInstanceProcessor:
|
|||
# FIXME: the from_dict entrypoint in spiff will one day do this copy instead
|
||||
process_copy = copy.deepcopy(full_bpmn_process_dict)
|
||||
bpmn_process_instance = ProcessInstanceProcessor._serializer.from_dict(process_copy)
|
||||
bpmn_process_instance.get_tasks()
|
||||
except Exception as err:
|
||||
raise err
|
||||
finally:
|
||||
spiff_logger.setLevel(original_spiff_logger_log_level)
|
||||
else:
|
||||
bpmn_process_instance = ProcessInstanceProcessor.get_bpmn_process_instance_from_workflow_spec(spec, subprocesses)
|
||||
bpmn_process_instance.data[ProcessInstanceProcessor.VALIDATION_PROCESS_KEY] = validate_only
|
||||
|
||||
return (
|
||||
bpmn_process_instance,
|
||||
|
@ -1663,6 +1658,11 @@ class ProcessInstanceProcessor:
|
|||
return task_json
|
||||
|
||||
def complete_task(self, spiff_task: SpiffTask, human_task: HumanTaskModel, user: UserModel) -> None:
|
||||
if str(spiff_task.id) != human_task.task_guid:
|
||||
raise TaskMismatchError(
|
||||
f"Given spiff task ({spiff_task.task_spec.bpmn_id} - {spiff_task.id}) and human task ({human_task.task_name} -"
|
||||
f" {human_task.task_guid}) must match"
|
||||
)
|
||||
task_model = TaskModel.query.filter_by(guid=human_task.task_id).first()
|
||||
if task_model is None:
|
||||
raise TaskNotFoundError(
|
||||
|
|
|
@ -114,6 +114,17 @@ class ProcessModelService(FileSystemService):
|
|||
configured_prefix = current_app.config["SPIFFWORKFLOW_BACKEND_EXTENSIONS_PROCESS_MODEL_PREFIX"]
|
||||
return process_model.id.startswith(f"{configured_prefix}/")
|
||||
|
||||
@classmethod
|
||||
def add_json_data_to_json_file(cls, process_model: ProcessModelInfo, file_name: str, json_data: dict) -> None:
|
||||
full_json_data = json_data
|
||||
process_model_path = os.path.abspath(os.path.join(FileSystemService.root_path(), process_model.id_for_file_path()))
|
||||
json_path = os.path.abspath(os.path.join(process_model_path, file_name))
|
||||
if os.path.exists(json_path):
|
||||
with open(json_path) as f:
|
||||
existing_json = json.loads(f.read())
|
||||
full_json_data = {**existing_json, **json_data}
|
||||
cls.write_json_file(json_path, full_json_data)
|
||||
|
||||
@classmethod
|
||||
def save_process_model(cls, process_model: ProcessModelInfo) -> None:
|
||||
process_model_path = os.path.abspath(os.path.join(FileSystemService.root_path(), process_model.id_for_file_path()))
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
import copy
|
||||
|
||||
from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer # type: ignore
|
||||
from SpiffWorkflow.bpmn.specs.mixins import ServiceTaskMixin # type: ignore
|
||||
from SpiffWorkflow.spiff.serializer.config import SPIFF_CONFIG # type: ignore
|
||||
|
||||
|
||||
class ProcessModelTestGeneratorService:
|
||||
@classmethod
|
||||
def generate_test_from_process_instance_dict(
|
||||
cls, process_instance_dict: dict, test_case_identifier: str = "auto_generated_test_case"
|
||||
) -> dict:
|
||||
wf_spec_converter = BpmnWorkflowSerializer.configure(SPIFF_CONFIG)
|
||||
serializer = BpmnWorkflowSerializer(wf_spec_converter)
|
||||
process_instance_dict_copy = copy.deepcopy(process_instance_dict)
|
||||
bpmn_process_instance = serializer.from_dict(process_instance_dict_copy)
|
||||
|
||||
human_tasks = bpmn_process_instance.get_tasks(manual=True)
|
||||
service_tasks = bpmn_process_instance.get_tasks(spec_class=ServiceTaskMixin)
|
||||
all_spiff_tasks = human_tasks + service_tasks
|
||||
bpmn_unit_test_specification = {"tasks": {}, "expected_output_json": bpmn_process_instance.data}
|
||||
for spiff_task in all_spiff_tasks:
|
||||
process_id = spiff_task.workflow.spec.name
|
||||
bpmn_task_identifier = f"{process_id}:{spiff_task.task_spec.bpmn_id}"
|
||||
if bpmn_task_identifier not in bpmn_unit_test_specification["tasks"]:
|
||||
bpmn_unit_test_specification["tasks"][bpmn_task_identifier] = {}
|
||||
if "data" not in bpmn_unit_test_specification["tasks"][bpmn_task_identifier]:
|
||||
bpmn_unit_test_specification["tasks"][bpmn_task_identifier]["data"] = []
|
||||
|
||||
previous_task_data = spiff_task.parent.data
|
||||
current_task_data = spiff_task.data
|
||||
cls.remove_duplicates(previous_task_data, current_task_data)
|
||||
bpmn_unit_test_specification["tasks"][bpmn_task_identifier]["data"].append(current_task_data)
|
||||
|
||||
return {test_case_identifier: bpmn_unit_test_specification}
|
||||
|
||||
@classmethod
|
||||
def remove_duplicates(cls, dict_one: dict, dict_two: dict) -> None:
|
||||
for key in list(dict_two.keys()):
|
||||
if key in dict_one:
|
||||
if isinstance(dict_one[key], dict) and isinstance(dict_two[key], dict):
|
||||
cls.remove_duplicates(dict_one[key], dict_two[key])
|
||||
if not dict_two[key]:
|
||||
del dict_two[key]
|
||||
else:
|
||||
del dict_two[key]
|
|
@ -30,6 +30,44 @@ from spiffworkflow_backend.services.custom_parser import MyCustomParser
|
|||
from spiffworkflow_backend.services.jinja_service import JinjaHelpers
|
||||
from spiffworkflow_backend.services.process_instance_processor import CustomScriptEngineEnvironment
|
||||
|
||||
DEFAULT_NSMAP = {
|
||||
"bpmn": "http://www.omg.org/spec/BPMN/20100524/MODEL",
|
||||
"bpmndi": "http://www.omg.org/spec/BPMN/20100524/DI",
|
||||
"dc": "http://www.omg.org/spec/DD/20100524/DC",
|
||||
}
|
||||
|
||||
|
||||
"""
|
||||
JSON file name:
|
||||
The name should be in format "test_BPMN_FILE_NAME.json".
|
||||
|
||||
BPMN_TASK_IDENTIIFER:
|
||||
can be either task bpmn identifier or in format:
|
||||
[BPMN_PROCESS_ID]:[TASK_BPMN_IDENTIFIER]
|
||||
example: 'BasicServiceTaskProcess:service_task_one'
|
||||
this allows for tasks to share bpmn identifiers across models
|
||||
which is useful for call activities
|
||||
|
||||
DATA for tasks:
|
||||
This is an array of task data. This allows for the task to
|
||||
be called multiple times and given different data each time.
|
||||
This is useful for testing loops where each iteration needs
|
||||
different input. The test will fail if the task is called
|
||||
multiple times without task data input for each call.
|
||||
|
||||
JSON file format:
|
||||
{
|
||||
TEST_CASE_NAME: {
|
||||
"tasks": {
|
||||
BPMN_TASK_IDENTIIFER: {
|
||||
"data": [DATA]
|
||||
}
|
||||
},
|
||||
"expected_output_json": DATA
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
class UnrunnableTestCaseError(Exception):
|
||||
pass
|
||||
|
@ -55,6 +93,29 @@ class BpmnFileMissingExecutableProcessError(Exception):
|
|||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class TestCaseErrorDetails:
|
||||
error_messages: list[str]
|
||||
task_error_line: str | None = None
|
||||
task_trace: list[str] | None = None
|
||||
task_bpmn_identifier: str | None = None
|
||||
task_bpmn_type: str | None = None
|
||||
task_bpmn_name: str | None = None
|
||||
task_line_number: int | None = None
|
||||
stacktrace: list[str] | None = None
|
||||
|
||||
output_data: dict | None = None
|
||||
expected_data: dict | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class TestCaseResult:
|
||||
passed: bool
|
||||
bpmn_file: str
|
||||
test_case_identifier: str
|
||||
test_case_error_details: TestCaseErrorDetails | None = None
|
||||
|
||||
|
||||
def _import(name: str, glbls: dict[str, Any], *args: Any) -> None:
|
||||
if name not in glbls:
|
||||
raise ImportError(f"Import not allowed: {name}", name=name)
|
||||
|
@ -137,25 +198,6 @@ class ProcessModelTestRunnerScriptEngine(PythonScriptEngine): # type: ignore
|
|||
raise Exception("please override this service task in your bpmn unit test json")
|
||||
|
||||
|
||||
@dataclass
|
||||
class TestCaseErrorDetails:
|
||||
error_messages: list[str]
|
||||
task_error_line: str | None = None
|
||||
task_trace: list[str] | None = None
|
||||
task_bpmn_identifier: str | None = None
|
||||
task_bpmn_name: str | None = None
|
||||
task_line_number: int | None = None
|
||||
stacktrace: list[str] | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class TestCaseResult:
|
||||
passed: bool
|
||||
bpmn_file: str
|
||||
test_case_identifier: str
|
||||
test_case_error_details: TestCaseErrorDetails | None = None
|
||||
|
||||
|
||||
class ProcessModelTestRunnerDelegate:
|
||||
"""Abstract class for the process model test runner delegate.
|
||||
|
||||
|
@ -288,45 +330,6 @@ class ProcessModelTestRunnerMostlyPureSpiffDelegate(ProcessModelTestRunnerDelega
|
|||
self.bpmn_processes_to_file_mappings[bpmn_process_identifier] = file_norm
|
||||
|
||||
|
||||
DEFAULT_NSMAP = {
|
||||
"bpmn": "http://www.omg.org/spec/BPMN/20100524/MODEL",
|
||||
"bpmndi": "http://www.omg.org/spec/BPMN/20100524/DI",
|
||||
"dc": "http://www.omg.org/spec/DD/20100524/DC",
|
||||
}
|
||||
|
||||
|
||||
"""
|
||||
JSON file name:
|
||||
The name should be in format "test_BPMN_FILE_NAME_IT_TESTS.json".
|
||||
|
||||
BPMN_TASK_IDENTIIFER:
|
||||
can be either task bpmn identifier or in format:
|
||||
[BPMN_PROCESS_ID]:[TASK_BPMN_IDENTIFIER]
|
||||
example: 'BasicServiceTaskProcess:service_task_one'
|
||||
this allows for tasks to share bpmn identifiers across models
|
||||
which is useful for call activities
|
||||
|
||||
DATA for tasks:
|
||||
This is an array of task data. This allows for the task to
|
||||
be called multiple times and given different data each time.
|
||||
This is useful for testing loops where each iteration needs
|
||||
different input. The test will fail if the task is called
|
||||
multiple times without task data input for each call.
|
||||
|
||||
JSON file format:
|
||||
{
|
||||
TEST_CASE_NAME: {
|
||||
"tasks": {
|
||||
BPMN_TASK_IDENTIIFER: {
|
||||
"data": [DATA]
|
||||
}
|
||||
},
|
||||
"expected_output_json": DATA
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
class ProcessModelTestRunner:
|
||||
"""Runs the test case json files for a given process model directory.
|
||||
|
||||
|
@ -401,6 +404,7 @@ class ProcessModelTestRunner:
|
|||
def run_test_case(self, bpmn_file: str, test_case_identifier: str, test_case_contents: dict) -> None:
|
||||
bpmn_process_instance = self._instantiate_executer(bpmn_file)
|
||||
method_overrides = {}
|
||||
# mocking python functions within script tasks
|
||||
if "mocks" in test_case_contents:
|
||||
for method_name, mock_return_value in test_case_contents["mocks"].items():
|
||||
method_overrides[method_name] = lambda value=mock_return_value: value
|
||||
|
@ -430,23 +434,23 @@ class ProcessModelTestRunner:
|
|||
|
||||
error_message = None
|
||||
if bpmn_process_instance.is_completed() is False:
|
||||
error_message = [
|
||||
"Expected process instance to complete but it did not.",
|
||||
f"Final data was: {bpmn_process_instance.last_task.data}",
|
||||
f"Last task bpmn id: {bpmn_process_instance.last_task.task_spec.bpmn_id}",
|
||||
f"Last task type: {bpmn_process_instance.last_task.task_spec.__class__.__name__}",
|
||||
]
|
||||
error_message = {
|
||||
"error_messages": ["Expected process instance to complete but it did not."],
|
||||
"output_data": bpmn_process_instance.last_task.data,
|
||||
"task_bpmn_identifier": bpmn_process_instance.last_task.task_spec.bpmn_id,
|
||||
"task_bpmn_type": bpmn_process_instance.last_task.task_spec.__class__.__name__,
|
||||
}
|
||||
elif bpmn_process_instance.success is False:
|
||||
error_message = [
|
||||
"Expected process instance to succeed but it did not.",
|
||||
f"Final data was: {bpmn_process_instance.data}",
|
||||
]
|
||||
error_message = {
|
||||
"error_messages": ["Expected process instance to succeed but it did not."],
|
||||
"output_data": bpmn_process_instance.data,
|
||||
}
|
||||
elif test_case_contents["expected_output_json"] != bpmn_process_instance.data:
|
||||
error_message = [
|
||||
"Expected output did not match actual output:",
|
||||
f"expected: {test_case_contents['expected_output_json']}",
|
||||
f"actual: {bpmn_process_instance.data}",
|
||||
]
|
||||
error_message = {
|
||||
"error_messages": ["Expected output did not match actual output."],
|
||||
"expected_data": test_case_contents["expected_output_json"],
|
||||
"output_data": bpmn_process_instance.data,
|
||||
}
|
||||
self._add_test_result(error_message is None, bpmn_file, test_case_identifier, error_message)
|
||||
|
||||
def _execute_task(
|
||||
|
@ -510,14 +514,14 @@ class ProcessModelTestRunner:
|
|||
passed: bool,
|
||||
bpmn_file: str,
|
||||
test_case_identifier: str,
|
||||
error_messages: list[str] | None = None,
|
||||
error_messages: dict | None = None,
|
||||
exception: Exception | None = None,
|
||||
) -> None:
|
||||
test_case_error_details = None
|
||||
if exception is not None:
|
||||
test_case_error_details = self._exception_to_test_case_error_details(exception)
|
||||
elif error_messages:
|
||||
test_case_error_details = TestCaseErrorDetails(error_messages=error_messages)
|
||||
test_case_error_details = TestCaseErrorDetails(**error_messages)
|
||||
|
||||
bpmn_file_relative = self._get_relative_path_of_bpmn_file(bpmn_file)
|
||||
test_result = TestCaseResult(
|
||||
|
|
|
@ -12,6 +12,7 @@ from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
|||
from SpiffWorkflow.util.task import TaskState # type: ignore
|
||||
from sqlalchemy import asc
|
||||
|
||||
from spiffworkflow_backend.exceptions.error import TaskMismatchError
|
||||
from spiffworkflow_backend.models.bpmn_process import BpmnProcessModel
|
||||
from spiffworkflow_backend.models.bpmn_process import BpmnProcessNotFoundError
|
||||
from spiffworkflow_backend.models.bpmn_process_definition import BpmnProcessDefinitionModel
|
||||
|
@ -280,6 +281,10 @@ class TaskService:
|
|||
This will NOT update start_in_seconds or end_in_seconds.
|
||||
It also returns the relating json_data object so they can be imported later.
|
||||
"""
|
||||
if str(spiff_task.id) != task_model.guid:
|
||||
raise TaskMismatchError(
|
||||
f"Given spiff task ({spiff_task.task_spec.bpmn_id} - {spiff_task.id}) and task ({task_model.guid}) must match"
|
||||
)
|
||||
|
||||
new_properties_json = self.serializer.to_dict(spiff_task)
|
||||
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
<?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="Process_top_level" name="Top Level Process" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_0j3unyw</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_0j3unyw" sourceRef="StartEvent_1" targetRef="top_script_task" />
|
||||
<bpmn:endEvent id="Event_1swh8gs">
|
||||
<bpmn:incoming>Flow_1dbi4yf</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_1dbi4yf" sourceRef="top_call_activity" targetRef="Event_1swh8gs" />
|
||||
<bpmn:callActivity id="top_call_activity" name="Top Call Activity" calledElement="Process_sub_level">
|
||||
<bpmn:incoming>Flow_0z2u0gc</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_1dbi4yf</bpmn:outgoing>
|
||||
</bpmn:callActivity>
|
||||
<bpmn:sequenceFlow id="Flow_0uoa0st" sourceRef="top_script_task" targetRef="top_service_task" />
|
||||
<bpmn:dataObjectReference id="DataObjectReference_0qfbjfj" name="top_level_data_object" dataObjectRef="top_level_data_object" />
|
||||
<bpmn:dataObject id="top_level_data_object" name="top_level_data_object" />
|
||||
<bpmn:scriptTask id="top_script_task" name="Top Script Task">
|
||||
<bpmn:extensionElements>
|
||||
<spiffworkflow:serviceTaskOperator id="http/GetRequestV2" resultVariable="the_response">
|
||||
<spiffworkflow:parameters>
|
||||
<spiffworkflow:parameter id="url" type="str" value=""http://localhost:7000/v1.0/status"" />
|
||||
<spiffworkflow:parameter id="headers" type="any" />
|
||||
<spiffworkflow:parameter id="params" type="any" />
|
||||
<spiffworkflow:parameter id="basic_auth_username" type="str" />
|
||||
<spiffworkflow:parameter id="basic_auth_password" type="str" />
|
||||
<spiffworkflow:parameter id="attempts" type="int" />
|
||||
</spiffworkflow:parameters>
|
||||
</spiffworkflow:serviceTaskOperator>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_0j3unyw</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0uoa0st</bpmn:outgoing>
|
||||
<bpmn:dataOutputAssociation id="DataOutputAssociation_1fxfphs">
|
||||
<bpmn:targetRef>DataObjectReference_0qfbjfj</bpmn:targetRef>
|
||||
</bpmn:dataOutputAssociation>
|
||||
<bpmn:script>top_level_data_object = "a"</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:sequenceFlow id="Flow_0z2u0gc" sourceRef="top_service_task" targetRef="top_call_activity" />
|
||||
<bpmn:serviceTask id="top_service_task" name="Top Service Task">
|
||||
<bpmn:extensionElements>
|
||||
<spiffworkflow:serviceTaskOperator id="http/GetRequestV2" resultVariable="backend_status_response">
|
||||
<spiffworkflow:parameters>
|
||||
<spiffworkflow:parameter id="url" type="str" value=""http://localhost:7000/v1.0/status"" />
|
||||
<spiffworkflow:parameter id="headers" type="any" />
|
||||
<spiffworkflow:parameter id="params" type="any" />
|
||||
<spiffworkflow:parameter id="basic_auth_username" type="str" />
|
||||
<spiffworkflow:parameter id="basic_auth_password" type="str" />
|
||||
<spiffworkflow:parameter id="attempts" type="int" />
|
||||
</spiffworkflow:parameters>
|
||||
</spiffworkflow:serviceTaskOperator>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_0uoa0st</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0z2u0gc</bpmn:outgoing>
|
||||
</bpmn:serviceTask>
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_top_level">
|
||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||
<dc:Bounds x="32" y="159" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_1swh8gs_di" bpmnElement="Event_1swh8gs">
|
||||
<dc:Bounds x="502" y="159" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_18m3q89_di" bpmnElement="top_call_activity">
|
||||
<dc:Bounds x="370" y="137" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="DataObjectReference_0qfbjfj_di" bpmnElement="DataObjectReference_0qfbjfj">
|
||||
<dc:Bounds x="132" y="55" width="36" height="50" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="105" y="31" width="90" height="27" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0dh9loj_di" bpmnElement="top_script_task">
|
||||
<dc:Bounds x="100" y="137" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_1ngnsv7_di" bpmnElement="top_service_task">
|
||||
<dc:Bounds x="230" y="137" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_0j3unyw_di" bpmnElement="Flow_0j3unyw">
|
||||
<di:waypoint x="68" y="177" />
|
||||
<di:waypoint x="100" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_1dbi4yf_di" bpmnElement="Flow_1dbi4yf">
|
||||
<di:waypoint x="470" y="177" />
|
||||
<di:waypoint x="502" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0uoa0st_di" bpmnElement="Flow_0uoa0st">
|
||||
<di:waypoint x="200" y="177" />
|
||||
<di:waypoint x="230" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="DataOutputAssociation_1fxfphs_di" bpmnElement="DataOutputAssociation_1fxfphs">
|
||||
<di:waypoint x="152" y="137" />
|
||||
<di:waypoint x="153" y="105" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0z2u0gc_di" bpmnElement="Flow_0z2u0gc">
|
||||
<di:waypoint x="330" y="177" />
|
||||
<di:waypoint x="370" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"firstName": "Chuck"
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"title": "Text Field",
|
||||
"description": "A simple text field that is required, has a default value, sets a placeholder, includes a description. (field name will be 'firstname')",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"firstName"
|
||||
],
|
||||
"properties": {
|
||||
"firstName": {
|
||||
"type": "string",
|
||||
"title": "First name",
|
||||
"default": "Chuck"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"firstName": {
|
||||
"ui:autofocus": true,
|
||||
"ui:emptyValue": "",
|
||||
"ui:placeholder": "ui:emptyValue causes this field to always be valid despite being required",
|
||||
"ui:autocomplete": "family-name",
|
||||
"ui:enableMarkdownInDescription": true,
|
||||
"ui:description": "Make text **bold** or *italic*. Take a look at other options [here](https://probablyup.com/markdown-to-jsx/)."
|
||||
}
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
<?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:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
|
||||
<bpmn:process id="Process_sub_level" name="Process Sub Level" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_18zaszw</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:endEvent id="EndEvent_1">
|
||||
<bpmn:extensionElements>
|
||||
<spiffworkflow:instructionsForEndUser>The process instance completed successfully.</spiffworkflow:instructionsForEndUser>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_02mnp5n</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_1dbpkjb" sourceRef="sub_script_task" targetRef="sub_manual_task" />
|
||||
<bpmn:scriptTask id="sub_script_task" name="Sub Script Task">
|
||||
<bpmn:incoming>Flow_18zaszw</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_1dbpkjb</bpmn:outgoing>
|
||||
<bpmn:dataOutputAssociation id="DataOutputAssociation_0nq3jkj">
|
||||
<bpmn:targetRef>DataObjectReference_11gskr0</bpmn:targetRef>
|
||||
</bpmn:dataOutputAssociation>
|
||||
<bpmn:script>sub_level_data_object = "b"</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:dataObject id="sub_level_data_object" name="sub_level_data_object" />
|
||||
<bpmn:dataObjectReference id="DataObjectReference_11gskr0" name="sub_level_data_object" dataObjectRef="sub_level_data_object" />
|
||||
<bpmn:sequenceFlow id="Flow_18zaszw" sourceRef="StartEvent_1" targetRef="sub_script_task" />
|
||||
<bpmn:sequenceFlow id="Flow_15y3o98" sourceRef="sub_manual_task" targetRef="call_activity_sub_process" />
|
||||
<bpmn:manualTask id="sub_manual_task" name="Sub Manual Task">
|
||||
<bpmn:incoming>Flow_1dbpkjb</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_15y3o98</bpmn:outgoing>
|
||||
</bpmn:manualTask>
|
||||
<bpmn:sequenceFlow id="Flow_02mnp5n" sourceRef="sub_script_task_two" targetRef="EndEvent_1" />
|
||||
<bpmn:scriptTask id="sub_script_task_two" name="Sub Script Task Two">
|
||||
<bpmn:incoming>Flow_0zr28rt</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_02mnp5n</bpmn:outgoing>
|
||||
<bpmn:dataOutputAssociation id="DataOutputAssociation_0quuwm4">
|
||||
<bpmn:targetRef>DataObjectReference_06uyy2z</bpmn:targetRef>
|
||||
</bpmn:dataOutputAssociation>
|
||||
<bpmn:script>sub_level_data_object_two = 'c'</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:dataObject id="sub_level_data_object_two" name="sub_level_data_object_two" />
|
||||
<bpmn:dataObjectReference id="DataObjectReference_06uyy2z" name="sub_level_data_object_two" dataObjectRef="sub_level_data_object_two" />
|
||||
<bpmn:sequenceFlow id="Flow_0zr28rt" sourceRef="call_activity_sub_process" targetRef="sub_script_task_two" />
|
||||
<bpmn:subProcess id="call_activity_sub_process" name="Call Activity Sub Process">
|
||||
<bpmn:incoming>Flow_15y3o98</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0zr28rt</bpmn:outgoing>
|
||||
<bpmn:startEvent id="Event_0yfq3gm">
|
||||
<bpmn:outgoing>Flow_1ekcyuv</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_1ekcyuv" sourceRef="Event_0yfq3gm" targetRef="sub_level_sub_process_user_task" />
|
||||
<bpmn:endEvent id="Event_00vjfmy">
|
||||
<bpmn:incoming>Flow_1p3g9vw</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_1p3g9vw" sourceRef="sub_level_sub_process_script_task" targetRef="Event_00vjfmy" />
|
||||
<bpmn:dataObjectReference id="DataObjectReference_1v83y6h" name="sub_level_data_object_three" dataObjectRef="sub_level_data_object_three" />
|
||||
<bpmn:dataObject id="sub_level_data_object_three" name="sub_level_data_object_three" />
|
||||
<bpmn:scriptTask id="sub_level_sub_process_script_task" name="Sub Level Sub Process Script Task">
|
||||
<bpmn:incoming>Flow_157qtq3</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_1p3g9vw</bpmn:outgoing>
|
||||
<bpmn:dataOutputAssociation id="DataOutputAssociation_1xpueyl">
|
||||
<bpmn:targetRef>DataObjectReference_1v83y6h</bpmn:targetRef>
|
||||
</bpmn:dataOutputAssociation>
|
||||
<bpmn:script>sub_level_data_object_three = 'd'</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:sequenceFlow id="Flow_157qtq3" sourceRef="sub_level_sub_process_user_task" targetRef="sub_level_sub_process_script_task" />
|
||||
<bpmn:userTask id="sub_level_sub_process_user_task" name="Sub Level Sub Process User Task">
|
||||
<bpmn:extensionElements>
|
||||
<spiffworkflow:properties>
|
||||
<spiffworkflow:property name="formJsonSchemaFilename" value="sub-level-sub-process-user-form-schema.json" />
|
||||
<spiffworkflow:property name="formUiSchemaFilename" value="sub-level-sub-process-user-form-uischema.json" />
|
||||
</spiffworkflow:properties>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_1ekcyuv</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_157qtq3</bpmn:outgoing>
|
||||
</bpmn:userTask>
|
||||
</bpmn:subProcess>
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_sub_level">
|
||||
<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_14za570_di" bpmnElement="EndEvent_1">
|
||||
<dc:Bounds x="762" y="159" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0stvzig_di" bpmnElement="sub_script_task">
|
||||
<dc:Bounds x="260" y="137" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="DataObjectReference_11gskr0_di" bpmnElement="DataObjectReference_11gskr0">
|
||||
<dc:Bounds x="292" y="45" width="36" height="50" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="266" y="21" width="87" height="27" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_1roka0p_di" bpmnElement="sub_manual_task">
|
||||
<dc:Bounds x="380" y="137" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0ao5f38_di" bpmnElement="sub_script_task_two">
|
||||
<dc:Bounds x="630" y="137" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="DataObjectReference_06uyy2z_di" bpmnElement="DataObjectReference_06uyy2z">
|
||||
<dc:Bounds x="662" y="25" width="36" height="50" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="636" y="-12.5" width="87" height="27" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0bc52l5_di" bpmnElement="call_activity_sub_process">
|
||||
<dc:Bounds x="510" y="137" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_1dbpkjb_di" bpmnElement="Flow_1dbpkjb">
|
||||
<di:waypoint x="360" y="177" />
|
||||
<di:waypoint x="380" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="DataOutputAssociation_0nq3jkj_di" bpmnElement="DataOutputAssociation_0nq3jkj">
|
||||
<di:waypoint x="311" y="137" />
|
||||
<di:waypoint x="314" y="95" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_18zaszw_di" bpmnElement="Flow_18zaszw">
|
||||
<di:waypoint x="215" y="177" />
|
||||
<di:waypoint x="260" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_15y3o98_di" bpmnElement="Flow_15y3o98">
|
||||
<di:waypoint x="480" y="177" />
|
||||
<di:waypoint x="510" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_02mnp5n_di" bpmnElement="Flow_02mnp5n">
|
||||
<di:waypoint x="730" y="177" />
|
||||
<di:waypoint x="762" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="DataOutputAssociation_0quuwm4_di" bpmnElement="DataOutputAssociation_0quuwm4">
|
||||
<di:waypoint x="680" y="137" />
|
||||
<di:waypoint x="679" y="75" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0zr28rt_di" bpmnElement="Flow_0zr28rt">
|
||||
<di:waypoint x="610" y="177" />
|
||||
<di:waypoint x="630" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_0714uj7">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1xy36cs" bpmnElement="call_activity_sub_process">
|
||||
<bpmndi:BPMNShape id="Event_00vjfmy_di" bpmnElement="Event_00vjfmy">
|
||||
<dc:Bounds x="812" y="292" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="DataObjectReference_1v83y6h_di" bpmnElement="DataObjectReference_1v83y6h">
|
||||
<dc:Bounds x="692" y="135" width="36" height="50" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="666" y="98" width="87" height="27" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_165y1p1_di" bpmnElement="sub_level_sub_process_script_task">
|
||||
<dc:Bounds x="660" y="270" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_0yfq3gm_di" bpmnElement="Event_0yfq3gm">
|
||||
<dc:Bounds x="402" y="292" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_1xq5smk_di" bpmnElement="sub_level_sub_process_user_task">
|
||||
<dc:Bounds x="490" y="270" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_1ekcyuv_di" bpmnElement="Flow_1ekcyuv">
|
||||
<di:waypoint x="438" y="310" />
|
||||
<di:waypoint x="490" y="310" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_1p3g9vw_di" bpmnElement="Flow_1p3g9vw">
|
||||
<di:waypoint x="760" y="310" />
|
||||
<di:waypoint x="812" y="310" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="DataOutputAssociation_1xpueyl_di" bpmnElement="DataOutputAssociation_1xpueyl">
|
||||
<di:waypoint x="709" y="270" />
|
||||
<di:waypoint x="708" y="185" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_157qtq3_di" bpmnElement="Flow_157qtq3">
|
||||
<di:waypoint x="590" y="310" />
|
||||
<di:waypoint x="660" y="310" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
|
@ -1,6 +1,5 @@
|
|||
{
|
||||
"data": {
|
||||
"validate_only": false,
|
||||
"top_level_data_object": "a",
|
||||
"sub_level_data_object_two": "c",
|
||||
"sub_level_data_object_three": "d"
|
||||
|
@ -12,9 +11,7 @@
|
|||
"098e4fc2-a399-4325-b0a9-76d6c330fbf4": {
|
||||
"id": "098e4fc2-a399-4325-b0a9-76d6c330fbf4",
|
||||
"parent": "142bb43d-7d87-4341-acb5-f7762e48d8d3",
|
||||
"children": [
|
||||
"aa3991dd-2e91-4210-89e1-594245a0cf15"
|
||||
],
|
||||
"children": ["aa3991dd-2e91-4210-89e1-594245a0cf15"],
|
||||
"last_state_change": 1710947480.2315426,
|
||||
"state": 64,
|
||||
"task_spec": "StartEvent_1",
|
||||
|
@ -28,9 +25,7 @@
|
|||
"142bb43d-7d87-4341-acb5-f7762e48d8d3": {
|
||||
"id": "142bb43d-7d87-4341-acb5-f7762e48d8d3",
|
||||
"parent": null,
|
||||
"children": [
|
||||
"098e4fc2-a399-4325-b0a9-76d6c330fbf4"
|
||||
],
|
||||
"children": ["098e4fc2-a399-4325-b0a9-76d6c330fbf4"],
|
||||
"last_state_change": 1710947480.210416,
|
||||
"state": 64,
|
||||
"task_spec": "Start",
|
||||
|
@ -42,9 +37,7 @@
|
|||
"270d76e0-c1fe-4add-b58e-d5a51214a37b": {
|
||||
"id": "270d76e0-c1fe-4add-b58e-d5a51214a37b",
|
||||
"parent": "aa3991dd-2e91-4210-89e1-594245a0cf15",
|
||||
"children": [
|
||||
"e1188a09-95be-4b79-9a10-f7c376fa04a0"
|
||||
],
|
||||
"children": ["e1188a09-95be-4b79-9a10-f7c376fa04a0"],
|
||||
"last_state_change": 1710950132.28626,
|
||||
"state": 64,
|
||||
"task_spec": "top_call_activity",
|
||||
|
@ -56,9 +49,7 @@
|
|||
"973db925-12b3-4f45-95fe-53215db8929d": {
|
||||
"id": "973db925-12b3-4f45-95fe-53215db8929d",
|
||||
"parent": "e1188a09-95be-4b79-9a10-f7c376fa04a0",
|
||||
"children": [
|
||||
"a8052b4d-65ed-4e55-8233-062113ebe18f"
|
||||
],
|
||||
"children": ["a8052b4d-65ed-4e55-8233-062113ebe18f"],
|
||||
"last_state_change": 1710950132.2983754,
|
||||
"state": 64,
|
||||
"task_spec": "Process_top_level.EndJoin",
|
||||
|
@ -82,9 +73,7 @@
|
|||
"aa3991dd-2e91-4210-89e1-594245a0cf15": {
|
||||
"id": "aa3991dd-2e91-4210-89e1-594245a0cf15",
|
||||
"parent": "098e4fc2-a399-4325-b0a9-76d6c330fbf4",
|
||||
"children": [
|
||||
"270d76e0-c1fe-4add-b58e-d5a51214a37b"
|
||||
],
|
||||
"children": ["270d76e0-c1fe-4add-b58e-d5a51214a37b"],
|
||||
"last_state_change": 1710947480.247028,
|
||||
"state": 64,
|
||||
"task_spec": "top_script_task",
|
||||
|
@ -96,9 +85,7 @@
|
|||
"e1188a09-95be-4b79-9a10-f7c376fa04a0": {
|
||||
"id": "e1188a09-95be-4b79-9a10-f7c376fa04a0",
|
||||
"parent": "270d76e0-c1fe-4add-b58e-d5a51214a37b",
|
||||
"children": [
|
||||
"973db925-12b3-4f45-95fe-53215db8929d"
|
||||
],
|
||||
"children": ["973db925-12b3-4f45-95fe-53215db8929d"],
|
||||
"last_state_change": 1710950132.2913136,
|
||||
"state": 64,
|
||||
"task_spec": "Event_1swh8gs",
|
||||
|
@ -119,9 +106,7 @@
|
|||
"description": "BPMN Task",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"Process_top_level.EndJoin"
|
||||
],
|
||||
"inputs": ["Process_top_level.EndJoin"],
|
||||
"outputs": [],
|
||||
"bpmn_id": null,
|
||||
"bpmn_name": null,
|
||||
|
@ -137,12 +122,8 @@
|
|||
"description": "Default End Event",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"top_call_activity"
|
||||
],
|
||||
"outputs": [
|
||||
"Process_top_level.EndJoin"
|
||||
],
|
||||
"inputs": ["top_call_activity"],
|
||||
"outputs": ["Process_top_level.EndJoin"],
|
||||
"bpmn_id": "Event_1swh8gs",
|
||||
"bpmn_name": null,
|
||||
"lane": null,
|
||||
|
@ -163,12 +144,8 @@
|
|||
"description": "BPMN Task",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"Event_1swh8gs"
|
||||
],
|
||||
"outputs": [
|
||||
"End"
|
||||
],
|
||||
"inputs": ["Event_1swh8gs"],
|
||||
"outputs": ["End"],
|
||||
"bpmn_id": null,
|
||||
"bpmn_name": null,
|
||||
"lane": null,
|
||||
|
@ -184,9 +161,7 @@
|
|||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
"StartEvent_1"
|
||||
],
|
||||
"outputs": ["StartEvent_1"],
|
||||
"bpmn_id": null,
|
||||
"bpmn_name": null,
|
||||
"lane": null,
|
||||
|
@ -201,12 +176,8 @@
|
|||
"description": "Default Start Event",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"Start"
|
||||
],
|
||||
"outputs": [
|
||||
"top_script_task"
|
||||
],
|
||||
"inputs": ["Start"],
|
||||
"outputs": ["top_script_task"],
|
||||
"bpmn_id": "StartEvent_1",
|
||||
"bpmn_name": null,
|
||||
"lane": null,
|
||||
|
@ -227,12 +198,8 @@
|
|||
"description": "Call Activity",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"top_script_task"
|
||||
],
|
||||
"outputs": [
|
||||
"Event_1swh8gs"
|
||||
],
|
||||
"inputs": ["top_script_task"],
|
||||
"outputs": ["Event_1swh8gs"],
|
||||
"bpmn_id": "top_call_activity",
|
||||
"bpmn_name": "Top Call Activity",
|
||||
"lane": null,
|
||||
|
@ -251,12 +218,8 @@
|
|||
"description": "Script Task",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"StartEvent_1"
|
||||
],
|
||||
"outputs": [
|
||||
"top_call_activity"
|
||||
],
|
||||
"inputs": ["StartEvent_1"],
|
||||
"outputs": ["top_call_activity"],
|
||||
"bpmn_id": "top_script_task",
|
||||
"bpmn_name": "Top Script Task",
|
||||
"lane": null,
|
||||
|
@ -312,12 +275,8 @@
|
|||
"description": "Subprocess",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"sub_manual_task"
|
||||
],
|
||||
"outputs": [
|
||||
"sub_script_task_two"
|
||||
],
|
||||
"inputs": ["sub_manual_task"],
|
||||
"outputs": ["sub_script_task_two"],
|
||||
"bpmn_id": "call_activity_sub_process",
|
||||
"bpmn_name": "Call Activity Sub Process",
|
||||
"lane": null,
|
||||
|
@ -336,9 +295,7 @@
|
|||
"description": "BPMN Task",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"Process_sub_level.EndJoin"
|
||||
],
|
||||
"inputs": ["Process_sub_level.EndJoin"],
|
||||
"outputs": [],
|
||||
"bpmn_id": null,
|
||||
"bpmn_name": null,
|
||||
|
@ -354,12 +311,8 @@
|
|||
"description": "Default End Event",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"sub_script_task_two"
|
||||
],
|
||||
"outputs": [
|
||||
"Process_sub_level.EndJoin"
|
||||
],
|
||||
"inputs": ["sub_script_task_two"],
|
||||
"outputs": ["Process_sub_level.EndJoin"],
|
||||
"bpmn_id": "EndEvent_1",
|
||||
"bpmn_name": null,
|
||||
"lane": null,
|
||||
|
@ -382,12 +335,8 @@
|
|||
"description": "BPMN Task",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"EndEvent_1"
|
||||
],
|
||||
"outputs": [
|
||||
"End"
|
||||
],
|
||||
"inputs": ["EndEvent_1"],
|
||||
"outputs": ["End"],
|
||||
"bpmn_id": null,
|
||||
"bpmn_name": null,
|
||||
"lane": null,
|
||||
|
@ -403,9 +352,7 @@
|
|||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
"StartEvent_1"
|
||||
],
|
||||
"outputs": ["StartEvent_1"],
|
||||
"bpmn_id": null,
|
||||
"bpmn_name": null,
|
||||
"lane": null,
|
||||
|
@ -420,12 +367,8 @@
|
|||
"description": "Default Start Event",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"Start"
|
||||
],
|
||||
"outputs": [
|
||||
"sub_script_task"
|
||||
],
|
||||
"inputs": ["Start"],
|
||||
"outputs": ["sub_script_task"],
|
||||
"bpmn_id": "StartEvent_1",
|
||||
"bpmn_name": null,
|
||||
"lane": null,
|
||||
|
@ -446,12 +389,8 @@
|
|||
"description": "Manual Task",
|
||||
"manual": true,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"sub_script_task"
|
||||
],
|
||||
"outputs": [
|
||||
"call_activity_sub_process"
|
||||
],
|
||||
"inputs": ["sub_script_task"],
|
||||
"outputs": ["call_activity_sub_process"],
|
||||
"bpmn_id": "sub_manual_task",
|
||||
"bpmn_name": "Sub Manual Task",
|
||||
"lane": null,
|
||||
|
@ -469,12 +408,8 @@
|
|||
"description": "Script Task",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"StartEvent_1"
|
||||
],
|
||||
"outputs": [
|
||||
"sub_manual_task"
|
||||
],
|
||||
"inputs": ["StartEvent_1"],
|
||||
"outputs": ["sub_manual_task"],
|
||||
"bpmn_id": "sub_script_task",
|
||||
"bpmn_name": "Sub Script Task",
|
||||
"lane": null,
|
||||
|
@ -500,12 +435,8 @@
|
|||
"description": "Script Task",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"call_activity_sub_process"
|
||||
],
|
||||
"outputs": [
|
||||
"EndEvent_1"
|
||||
],
|
||||
"inputs": ["call_activity_sub_process"],
|
||||
"outputs": ["EndEvent_1"],
|
||||
"bpmn_id": "sub_script_task_two",
|
||||
"bpmn_name": "Sub Script Task Two",
|
||||
"lane": null,
|
||||
|
@ -555,12 +486,8 @@
|
|||
"description": "BPMN Task",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"Event_00vjfmy"
|
||||
],
|
||||
"outputs": [
|
||||
"End"
|
||||
],
|
||||
"inputs": ["Event_00vjfmy"],
|
||||
"outputs": ["End"],
|
||||
"bpmn_id": null,
|
||||
"bpmn_name": null,
|
||||
"lane": null,
|
||||
|
@ -575,9 +502,7 @@
|
|||
"description": "BPMN Task",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"call_activity_sub_process.EndJoin"
|
||||
],
|
||||
"inputs": ["call_activity_sub_process.EndJoin"],
|
||||
"outputs": [],
|
||||
"bpmn_id": null,
|
||||
"bpmn_name": null,
|
||||
|
@ -593,12 +518,8 @@
|
|||
"description": "Default End Event",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"sub_level_sub_process_script_task"
|
||||
],
|
||||
"outputs": [
|
||||
"call_activity_sub_process.EndJoin"
|
||||
],
|
||||
"inputs": ["sub_level_sub_process_script_task"],
|
||||
"outputs": ["call_activity_sub_process.EndJoin"],
|
||||
"bpmn_id": "Event_00vjfmy",
|
||||
"bpmn_name": null,
|
||||
"lane": null,
|
||||
|
@ -619,12 +540,8 @@
|
|||
"description": "Default Start Event",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"Start"
|
||||
],
|
||||
"outputs": [
|
||||
"sub_level_sub_process_script_task"
|
||||
],
|
||||
"inputs": ["Start"],
|
||||
"outputs": ["sub_level_sub_process_script_task"],
|
||||
"bpmn_id": "Event_0yfq3gm",
|
||||
"bpmn_name": null,
|
||||
"lane": null,
|
||||
|
@ -646,9 +563,7 @@
|
|||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
"Event_0yfq3gm"
|
||||
],
|
||||
"outputs": ["Event_0yfq3gm"],
|
||||
"bpmn_id": null,
|
||||
"bpmn_name": null,
|
||||
"lane": null,
|
||||
|
@ -663,12 +578,8 @@
|
|||
"description": "Script Task",
|
||||
"manual": false,
|
||||
"lookahead": 2,
|
||||
"inputs": [
|
||||
"Event_0yfq3gm"
|
||||
],
|
||||
"outputs": [
|
||||
"Event_00vjfmy"
|
||||
],
|
||||
"inputs": ["Event_0yfq3gm"],
|
||||
"outputs": ["Event_00vjfmy"],
|
||||
"bpmn_id": "sub_level_sub_process_script_task",
|
||||
"bpmn_name": "Sub Level Sub Process Script Task",
|
||||
"lane": null,
|
||||
|
@ -718,7 +629,6 @@
|
|||
"subprocesses": {
|
||||
"270d76e0-c1fe-4add-b58e-d5a51214a37b": {
|
||||
"data": {
|
||||
"validate_only": false,
|
||||
"top_level_data_object": "a",
|
||||
"sub_level_data_object_two": "c",
|
||||
"sub_level_data_object_three": "d"
|
||||
|
@ -730,9 +640,7 @@
|
|||
"0315382d-fdf6-4c27-8d7d-63dddf0b05fb": {
|
||||
"id": "0315382d-fdf6-4c27-8d7d-63dddf0b05fb",
|
||||
"parent": "8efb7c04-82d1-459f-b0f8-778782dd7f0e",
|
||||
"children": [
|
||||
"5eb9e777-cfbf-4ef9-8ba8-79fa5d172b7e"
|
||||
],
|
||||
"children": ["5eb9e777-cfbf-4ef9-8ba8-79fa5d172b7e"],
|
||||
"last_state_change": 1710950132.2467537,
|
||||
"state": 64,
|
||||
"task_spec": "Process_sub_level.EndJoin",
|
||||
|
@ -744,9 +652,7 @@
|
|||
"186869f9-6992-4a79-86dc-365c3906dd64": {
|
||||
"id": "186869f9-6992-4a79-86dc-365c3906dd64",
|
||||
"parent": null,
|
||||
"children": [
|
||||
"b9762626-24e2-48d8-939a-ce1b17757781"
|
||||
],
|
||||
"children": ["b9762626-24e2-48d8-939a-ce1b17757781"],
|
||||
"last_state_change": 1710947480.247221,
|
||||
"state": 64,
|
||||
"task_spec": "Start",
|
||||
|
@ -770,9 +676,7 @@
|
|||
"688506fc-ab27-4eb2-a1fa-b435dd958561": {
|
||||
"id": "688506fc-ab27-4eb2-a1fa-b435dd958561",
|
||||
"parent": "8b51d215-15ab-4e0a-8dfc-e335e685fb52",
|
||||
"children": [
|
||||
"d0c6a2d9-9a43-4ccd-b4e3-ea62872f15ed"
|
||||
],
|
||||
"children": ["d0c6a2d9-9a43-4ccd-b4e3-ea62872f15ed"],
|
||||
"last_state_change": 1710950131.6774,
|
||||
"state": 64,
|
||||
"task_spec": "sub_manual_task",
|
||||
|
@ -784,9 +688,7 @@
|
|||
"8b51d215-15ab-4e0a-8dfc-e335e685fb52": {
|
||||
"id": "8b51d215-15ab-4e0a-8dfc-e335e685fb52",
|
||||
"parent": "b9762626-24e2-48d8-939a-ce1b17757781",
|
||||
"children": [
|
||||
"688506fc-ab27-4eb2-a1fa-b435dd958561"
|
||||
],
|
||||
"children": ["688506fc-ab27-4eb2-a1fa-b435dd958561"],
|
||||
"last_state_change": 1710947480.280872,
|
||||
"state": 64,
|
||||
"task_spec": "sub_script_task",
|
||||
|
@ -798,9 +700,7 @@
|
|||
"8efb7c04-82d1-459f-b0f8-778782dd7f0e": {
|
||||
"id": "8efb7c04-82d1-459f-b0f8-778782dd7f0e",
|
||||
"parent": "b482d5b3-a8e0-4903-9d48-0dbce70bd682",
|
||||
"children": [
|
||||
"0315382d-fdf6-4c27-8d7d-63dddf0b05fb"
|
||||
],
|
||||
"children": ["0315382d-fdf6-4c27-8d7d-63dddf0b05fb"],
|
||||
"last_state_change": 1710950132.1689236,
|
||||
"state": 64,
|
||||
"task_spec": "EndEvent_1",
|
||||
|
@ -812,9 +712,7 @@
|
|||
"b482d5b3-a8e0-4903-9d48-0dbce70bd682": {
|
||||
"id": "b482d5b3-a8e0-4903-9d48-0dbce70bd682",
|
||||
"parent": "d0c6a2d9-9a43-4ccd-b4e3-ea62872f15ed",
|
||||
"children": [
|
||||
"8efb7c04-82d1-459f-b0f8-778782dd7f0e"
|
||||
],
|
||||
"children": ["8efb7c04-82d1-459f-b0f8-778782dd7f0e"],
|
||||
"last_state_change": 1710950131.849423,
|
||||
"state": 64,
|
||||
"task_spec": "sub_script_task_two",
|
||||
|
@ -826,9 +724,7 @@
|
|||
"b9762626-24e2-48d8-939a-ce1b17757781": {
|
||||
"id": "b9762626-24e2-48d8-939a-ce1b17757781",
|
||||
"parent": "186869f9-6992-4a79-86dc-365c3906dd64",
|
||||
"children": [
|
||||
"8b51d215-15ab-4e0a-8dfc-e335e685fb52"
|
||||
],
|
||||
"children": ["8b51d215-15ab-4e0a-8dfc-e335e685fb52"],
|
||||
"last_state_change": 1710947480.255076,
|
||||
"state": 64,
|
||||
"task_spec": "StartEvent_1",
|
||||
|
@ -842,9 +738,7 @@
|
|||
"d0c6a2d9-9a43-4ccd-b4e3-ea62872f15ed": {
|
||||
"id": "d0c6a2d9-9a43-4ccd-b4e3-ea62872f15ed",
|
||||
"parent": "688506fc-ab27-4eb2-a1fa-b435dd958561",
|
||||
"children": [
|
||||
"b482d5b3-a8e0-4903-9d48-0dbce70bd682"
|
||||
],
|
||||
"children": ["b482d5b3-a8e0-4903-9d48-0dbce70bd682"],
|
||||
"last_state_change": 1710950131.8426125,
|
||||
"state": 64,
|
||||
"task_spec": "call_activity_sub_process",
|
||||
|
@ -861,7 +755,6 @@
|
|||
},
|
||||
"d0c6a2d9-9a43-4ccd-b4e3-ea62872f15ed": {
|
||||
"data": {
|
||||
"validate_only": false,
|
||||
"top_level_data_object": "a",
|
||||
"sub_level_data_object_two": "c",
|
||||
"sub_level_data_object_three": "d"
|
||||
|
@ -873,9 +766,7 @@
|
|||
"6e6ad5c3-e701-4b59-8a81-4ed2c63bd0e1": {
|
||||
"id": "6e6ad5c3-e701-4b59-8a81-4ed2c63bd0e1",
|
||||
"parent": "b346574d-c50c-4b4b-864c-685803ebf14e",
|
||||
"children": [
|
||||
"af12522c-811b-4258-a569-65890838677f"
|
||||
],
|
||||
"children": ["af12522c-811b-4258-a569-65890838677f"],
|
||||
"last_state_change": 1710950131.829411,
|
||||
"state": 64,
|
||||
"task_spec": "call_activity_sub_process.EndJoin",
|
||||
|
@ -887,9 +778,7 @@
|
|||
"95974b26-58b8-4fc3-a6d1-2158c1ab6de8": {
|
||||
"id": "95974b26-58b8-4fc3-a6d1-2158c1ab6de8",
|
||||
"parent": "b22dae80-ce20-4565-983e-e86b98625554",
|
||||
"children": [
|
||||
"b346574d-c50c-4b4b-864c-685803ebf14e"
|
||||
],
|
||||
"children": ["b346574d-c50c-4b4b-864c-685803ebf14e"],
|
||||
"last_state_change": 1710950131.8059175,
|
||||
"state": 64,
|
||||
"task_spec": "sub_level_sub_process_script_task",
|
||||
|
@ -913,9 +802,7 @@
|
|||
"b22dae80-ce20-4565-983e-e86b98625554": {
|
||||
"id": "b22dae80-ce20-4565-983e-e86b98625554",
|
||||
"parent": "ca86a501-34f8-48fc-b284-cce8e8af058d",
|
||||
"children": [
|
||||
"95974b26-58b8-4fc3-a6d1-2158c1ab6de8"
|
||||
],
|
||||
"children": ["95974b26-58b8-4fc3-a6d1-2158c1ab6de8"],
|
||||
"last_state_change": 1710950131.7874112,
|
||||
"state": 64,
|
||||
"task_spec": "Event_0yfq3gm",
|
||||
|
@ -929,9 +816,7 @@
|
|||
"b346574d-c50c-4b4b-864c-685803ebf14e": {
|
||||
"id": "b346574d-c50c-4b4b-864c-685803ebf14e",
|
||||
"parent": "95974b26-58b8-4fc3-a6d1-2158c1ab6de8",
|
||||
"children": [
|
||||
"6e6ad5c3-e701-4b59-8a81-4ed2c63bd0e1"
|
||||
],
|
||||
"children": ["6e6ad5c3-e701-4b59-8a81-4ed2c63bd0e1"],
|
||||
"last_state_change": 1710950131.817766,
|
||||
"state": 64,
|
||||
"task_spec": "Event_00vjfmy",
|
||||
|
@ -943,9 +828,7 @@
|
|||
"ca86a501-34f8-48fc-b284-cce8e8af058d": {
|
||||
"id": "ca86a501-34f8-48fc-b284-cce8e8af058d",
|
||||
"parent": null,
|
||||
"children": [
|
||||
"b22dae80-ce20-4565-983e-e86b98625554"
|
||||
],
|
||||
"children": ["b22dae80-ce20-4565-983e-e86b98625554"],
|
||||
"last_state_change": 1710950131.677685,
|
||||
"state": 64,
|
||||
"task_spec": "Start",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,6 +11,7 @@ from flask.app import Flask
|
|||
from flask.testing import FlaskClient
|
||||
from spiffworkflow_backend.exceptions.api_error import ApiError
|
||||
from spiffworkflow_backend.models.db import db
|
||||
from spiffworkflow_backend.models.human_task import HumanTaskModel
|
||||
from spiffworkflow_backend.models.message_instance import MessageInstanceModel
|
||||
from spiffworkflow_backend.models.permission_assignment import Permission
|
||||
from spiffworkflow_backend.models.permission_target import PermissionTargetModel
|
||||
|
@ -551,11 +552,21 @@ class BaseTest:
|
|||
db.session.delete(process_instance_report)
|
||||
db.session.commit()
|
||||
|
||||
def complete_next_manual_task(self, processor: ProcessInstanceProcessor) -> None:
|
||||
def complete_next_manual_task(
|
||||
self,
|
||||
processor: ProcessInstanceProcessor,
|
||||
execution_mode: str | None = None,
|
||||
data: dict | None = None,
|
||||
) -> None:
|
||||
user_task = processor.get_ready_user_tasks()[0]
|
||||
human_task = processor.process_instance_model.human_tasks[0]
|
||||
human_task = HumanTaskModel.query.filter_by(task_guid=str(user_task.id)).first()
|
||||
ProcessInstanceService.complete_form_task(
|
||||
processor, user_task, {}, processor.process_instance_model.process_initiator, human_task
|
||||
processor=processor,
|
||||
spiff_task=user_task,
|
||||
data=data or {},
|
||||
user=processor.process_instance_model.process_initiator,
|
||||
human_task=human_task,
|
||||
execution_mode=execution_mode,
|
||||
)
|
||||
|
||||
@contextmanager
|
||||
|
@ -583,3 +594,6 @@ class BaseTest:
|
|||
elif isinstance(bpmn_process_dict, list):
|
||||
for item in bpmn_process_dict:
|
||||
self.round_last_state_change(item)
|
||||
|
||||
def get_test_file(self, *args: str) -> str:
|
||||
return os.path.join(current_app.instance_path, "..", "..", "tests", "files", *args)
|
||||
|
|
|
@ -37,7 +37,6 @@ class TestExtensionsController(BaseTest):
|
|||
"Mike": "Awesome",
|
||||
"my_var": "Hello World",
|
||||
"person": "Kevin",
|
||||
"validate_only": False,
|
||||
"wonderfulness": "Very wonderful",
|
||||
"OUR_AWESOME_INPUT": "the awesome value",
|
||||
}
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
import io
|
||||
import json
|
||||
from hashlib import sha256
|
||||
from unittest.mock import patch
|
||||
|
||||
from flask.app import Flask
|
||||
from flask.testing import FlaskClient
|
||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus
|
||||
from spiffworkflow_backend.models.user import UserModel
|
||||
from spiffworkflow_backend.services.process_instance_processor import ProcessInstanceProcessor
|
||||
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
||||
|
||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||
|
@ -103,6 +108,78 @@ class TestProcessModelsController(BaseTest):
|
|||
)
|
||||
assert json["error_code"] == "process_model_cannot_be_found"
|
||||
|
||||
def test_process_model_test_generate(
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_super_admin_user: UserModel,
|
||||
) -> None:
|
||||
process_model = load_test_spec(
|
||||
process_model_id="test_group/with-service-task-call-activity-sub-process",
|
||||
process_model_source_directory="with-service-task-call-activity-sub-process",
|
||||
)
|
||||
process_instance = self.create_process_instance_from_process_model(process_model, user=with_super_admin_user)
|
||||
process_instance_id = process_instance.id
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
connector_response = {
|
||||
"body": '{"ok": true}',
|
||||
"mimetype": "application/json",
|
||||
"http_status": 200,
|
||||
"operator_identifier": "http/GetRequestV2",
|
||||
}
|
||||
with patch("requests.post") as mock_post:
|
||||
mock_post.return_value.status_code = 200
|
||||
mock_post.return_value.ok = True
|
||||
mock_post.return_value.text = json.dumps(connector_response)
|
||||
processor.do_engine_steps(save=True)
|
||||
self.complete_next_manual_task(processor, execution_mode="synchronous")
|
||||
self.complete_next_manual_task(processor, execution_mode="synchronous", data={"firstName": "Chuck"})
|
||||
process_instance = ProcessInstanceModel.query.filter_by(id=process_instance_id).first()
|
||||
assert process_instance.status == ProcessInstanceStatus.complete.value
|
||||
|
||||
url = f"/v1.0/process-model-tests/create/{process_model.modified_process_model_identifier()}"
|
||||
response = client.post(
|
||||
url,
|
||||
headers=self.logged_in_headers(with_super_admin_user),
|
||||
content_type="application/json",
|
||||
data=json.dumps({"process_instance_id": process_instance_id}),
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
test_case_identifier = f"test_case_for_process_instance_{process_instance_id}"
|
||||
expected_specification = {
|
||||
test_case_identifier: {
|
||||
"tasks": {
|
||||
"Process_sub_level:sub_manual_task": {"data": [{}]},
|
||||
"call_activity_sub_process:sub_level_sub_process_user_task": {"data": [{"firstName": "Chuck"}]},
|
||||
"Process_top_level:top_service_task": {
|
||||
"data": [
|
||||
{
|
||||
"backend_status_response": {
|
||||
"body": '{"ok": true}',
|
||||
"mimetype": "application/json",
|
||||
"http_status": 200,
|
||||
"operator_identifier": "http/GetRequestV2",
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
"expected_output_json": {
|
||||
"firstName": "Chuck",
|
||||
"data_objects": {"top_level_data_object": "a"},
|
||||
"backend_status_response": {
|
||||
"body": '{"ok": true}',
|
||||
"mimetype": "application/json",
|
||||
"http_status": 200,
|
||||
"operator_identifier": "http/GetRequestV2",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
assert expected_specification == response.json
|
||||
|
||||
def _get_process_show_show_response(
|
||||
self, client: FlaskClient, user: UserModel, process_model_id: str, expected_response: int = 200
|
||||
) -> dict:
|
||||
|
|
|
@ -127,7 +127,8 @@ class TestAuthorizationService(BaseTest):
|
|||
("/process-instances/some-process-group:some-process-model:*", "read"),
|
||||
("/process-model-natural-language/some-process-group:some-process-model:*", "create"),
|
||||
("/process-model-publish/some-process-group:some-process-model:*", "create"),
|
||||
("/process-model-tests/some-process-group:some-process-model:*", "create"),
|
||||
("/process-model-tests/create/some-process-group:some-process-model:*", "create"),
|
||||
("/process-model-tests/run/some-process-group:some-process-model:*", "create"),
|
||||
("/process-models/some-process-group:some-process-model:*", "create"),
|
||||
("/process-models/some-process-group:some-process-model:*", "delete"),
|
||||
("/process-models/some-process-group:some-process-model:*", "read"),
|
||||
|
@ -209,7 +210,8 @@ class TestAuthorizationService(BaseTest):
|
|||
("/process-instances/some-process-group:some-process-model/*", "read"),
|
||||
("/process-model-natural-language/some-process-group:some-process-model/*", "create"),
|
||||
("/process-model-publish/some-process-group:some-process-model/*", "create"),
|
||||
("/process-model-tests/some-process-group:some-process-model/*", "create"),
|
||||
("/process-model-tests/create/some-process-group:some-process-model/*", "create"),
|
||||
("/process-model-tests/run/some-process-group:some-process-model/*", "create"),
|
||||
("/process-models/some-process-group:some-process-model/*", "create"),
|
||||
("/process-models/some-process-group:some-process-model/*", "delete"),
|
||||
("/process-models/some-process-group:some-process-model/*", "read"),
|
||||
|
|
|
@ -52,5 +52,4 @@ class TestDotNotation(BaseTest):
|
|||
|
||||
processor.do_engine_steps(save=True)
|
||||
actual_data = processor.get_data()
|
||||
del actual_data["validate_only"]
|
||||
assert actual_data == expected
|
||||
|
|
|
@ -6,6 +6,7 @@ from flask.app import Flask
|
|||
from flask.testing import FlaskClient
|
||||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||
from SpiffWorkflow.util.task import TaskState # type: ignore
|
||||
from spiffworkflow_backend.exceptions.error import TaskMismatchError
|
||||
from spiffworkflow_backend.exceptions.error import UserDoesNotHaveAccessToTaskError
|
||||
from spiffworkflow_backend.models.bpmn_process import BpmnProcessModel
|
||||
from spiffworkflow_backend.models.db import db
|
||||
|
@ -551,7 +552,6 @@ class TestProcessInstanceProcessor(BaseTest):
|
|||
}
|
||||
data_set_5 = {**data_set_4, **{"a": 1, "we_move_on": True}}
|
||||
data_set_6 = {**data_set_5, **{"set_top_level_process_script_after_gate": 1}}
|
||||
data_set_7 = {**data_set_6, **{"validate_only": False, "set_top_level_process_script_after_gate": 1}}
|
||||
expected_task_data = {
|
||||
"top_level_script": {"data": data_set_1, "bpmn_process_identifier": "top_level_process"},
|
||||
"top_level_manual_task_one": {"data": data_set_1, "bpmn_process_identifier": "top_level_process"},
|
||||
|
@ -694,7 +694,7 @@ class TestProcessInstanceProcessor(BaseTest):
|
|||
.count()
|
||||
)
|
||||
assert task_models_that_are_predicted_count == 4
|
||||
assert processor_final.get_data() == data_set_7
|
||||
assert processor_final.get_data() == data_set_6
|
||||
|
||||
def test_does_not_recreate_human_tasks_on_multiple_saves(
|
||||
self,
|
||||
|
@ -971,3 +971,25 @@ class TestProcessInstanceProcessor(BaseTest):
|
|||
self.round_last_state_change(bpmn_process_dict_initial)
|
||||
|
||||
assert bpmn_process_dict_after == bpmn_process_dict_initial
|
||||
|
||||
def test_returns_error_if_spiff_task_and_human_task_are_different(
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
) -> None:
|
||||
process_model = load_test_spec(
|
||||
process_model_id="group/call_activity_with_manual_task",
|
||||
process_model_source_directory="call_activity_with_manual_task",
|
||||
)
|
||||
process_instance = self.create_process_instance_from_process_model(process_model=process_model)
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
processor.do_engine_steps(save=True)
|
||||
|
||||
process_instance = ProcessInstanceModel.query.filter_by(id=process_instance.id).first()
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
human_task_one = process_instance.active_human_tasks[0]
|
||||
non_manual_spiff_task = processor.bpmn_process_instance.get_tasks(manual=False)[0]
|
||||
assert human_task_one.task_guid != str(non_manual_spiff_task.id)
|
||||
with pytest.raises(TaskMismatchError):
|
||||
processor.complete_task(non_manual_spiff_task, human_task_one, user=process_instance.process_initiator)
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
import os
|
||||
|
||||
from flask import json
|
||||
from flask.app import Flask
|
||||
from spiffworkflow_backend.services.file_system_service import FileSystemService
|
||||
from spiffworkflow_backend.services.process_model_test_generator_service import ProcessModelTestGeneratorService
|
||||
from spiffworkflow_backend.services.process_model_test_runner_service import ProcessModelTestRunner
|
||||
|
||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
|
||||
|
||||
|
||||
class TestProcessModelTestGeneratorService(BaseTest):
|
||||
def test_can_generate_bpmn_unit_test_from_process_instance_json_and_run_it(
|
||||
self, app: Flask, with_db_and_bpmn_file_cleanup: None
|
||||
) -> None:
|
||||
process_instance_json_file = self.get_test_file("process_model_test_importer.json")
|
||||
with open(process_instance_json_file) as f:
|
||||
process_instance_json = f.read()
|
||||
process_instance_dict = json.loads(process_instance_json)
|
||||
test_case_identifier = "our_test_case"
|
||||
|
||||
bpmn_unit_test_specification = ProcessModelTestGeneratorService.generate_test_from_process_instance_dict(
|
||||
process_instance_dict, test_case_identifier=test_case_identifier
|
||||
)
|
||||
expected_specification = {
|
||||
test_case_identifier: {
|
||||
"tasks": {
|
||||
"Process_sub_level:sub_manual_task": {"data": [{}]},
|
||||
"call_activity_sub_process:sub_level_sub_process_user_task": {"data": [{"firstName": "Chuck"}]},
|
||||
"Process_top_level:top_service_task": {
|
||||
"data": [
|
||||
{
|
||||
"backend_status_response": {
|
||||
"body": '{"ok": true}',
|
||||
"mimetype": "application/json",
|
||||
"http_status": 200,
|
||||
"operator_identifier": "http/GetRequestV2",
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
"expected_output_json": {
|
||||
"firstName": "Chuck",
|
||||
"data_objects": {"top_level_data_object": "a"},
|
||||
"backend_status_response": {
|
||||
"body": '{"ok": true}',
|
||||
"mimetype": "application/json",
|
||||
"http_status": 200,
|
||||
"operator_identifier": "http/GetRequestV2",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
assert expected_specification == bpmn_unit_test_specification
|
||||
|
||||
process_model = load_test_spec(
|
||||
process_model_id="test_group/with-service-task-call-activity-sub-process",
|
||||
process_model_source_directory="with-service-task-call-activity-sub-process",
|
||||
)
|
||||
process_model_path = os.path.abspath(os.path.join(FileSystemService.root_path(), process_model.id_for_file_path()))
|
||||
with open(os.path.join(process_model_path, "test_main.json"), "w") as f:
|
||||
f.write(json.dumps(bpmn_unit_test_specification, indent=2))
|
||||
process_model_test_runner = ProcessModelTestRunner(
|
||||
process_model_directory_path=process_model_path,
|
||||
process_model_directory_for_test_discovery=process_model_path,
|
||||
test_case_file="test_main.json",
|
||||
test_case_identifier=test_case_identifier,
|
||||
)
|
||||
process_model_test_runner.run()
|
||||
|
||||
results = process_model_test_runner.test_case_results[0]
|
||||
assert results.passed is True
|
|
@ -5535,9 +5535,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@tanstack/query-core": {
|
||||
"version": "5.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.28.6.tgz",
|
||||
"integrity": "sha512-hnhotV+DnQtvtR3jPvbQMPNMW4KEK0J4k7c609zJ8muiNknm+yoDyMHmxTWM5ZnlZpsz0zOxYFr+mzRJNHWJsA==",
|
||||
"version": "5.28.8",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.28.8.tgz",
|
||||
"integrity": "sha512-cx64XHeB0kvKxFt22ibvegPeOxnaWVFUbAuhXoIrb7+XePEexHWoB9Kq5n9qroNPkRwQZwgFAP9HNbQz5ohoIg==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
|
@ -5553,11 +5553,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@tanstack/react-query": {
|
||||
"version": "5.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.28.6.tgz",
|
||||
"integrity": "sha512-/DdYuDBSsA21Qbcder1R8Cr/3Nx0ZnA2lgtqKsLMvov8wL4+g0HBz/gWYZPlIsof7iyfQafyhg4wUVUsS3vWZw==",
|
||||
"version": "5.28.8",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.28.8.tgz",
|
||||
"integrity": "sha512-4XYhoRmcThqziB32HsyiBLNXJcukaeGfYwAQ+fZqUUE3ZP4oB/Zy41UJdql+TUg98+vsezfbixxAwAbGHfc5Hg==",
|
||||
"dependencies": {
|
||||
"@tanstack/query-core": "5.28.6"
|
||||
"@tanstack/query-core": "5.28.8"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
|
@ -5568,9 +5568,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@tanstack/react-query-devtools": {
|
||||
"version": "5.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.28.6.tgz",
|
||||
"integrity": "sha512-xSfskHlM2JkP7WpN89UqhJV2RbFxg8YnOMzQz+EEzWSsgxMI5Crce8HO9pcUAcJce8gSmw93RQwuKNdG3FbT6w==",
|
||||
"version": "5.28.8",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.28.8.tgz",
|
||||
"integrity": "sha512-NorR2ueGlGdB5PTvt1WynzjfNI/OJwiisB1r0UAwgi0Em2UalZpMltwvoIrGhJ0T2V+8b0MV5wD+cmf0PPdHGA==",
|
||||
"dependencies": {
|
||||
"@tanstack/query-devtools": "5.28.6"
|
||||
},
|
||||
|
@ -5579,7 +5579,7 @@
|
|||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tanstack/react-query": "^5.28.6",
|
||||
"@tanstack/react-query": "^5.28.8",
|
||||
"react": "^18.0.0"
|
||||
}
|
||||
},
|
||||
|
@ -38168,9 +38168,9 @@
|
|||
}
|
||||
},
|
||||
"@tanstack/query-core": {
|
||||
"version": "5.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.28.6.tgz",
|
||||
"integrity": "sha512-hnhotV+DnQtvtR3jPvbQMPNMW4KEK0J4k7c609zJ8muiNknm+yoDyMHmxTWM5ZnlZpsz0zOxYFr+mzRJNHWJsA=="
|
||||
"version": "5.28.8",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.28.8.tgz",
|
||||
"integrity": "sha512-cx64XHeB0kvKxFt22ibvegPeOxnaWVFUbAuhXoIrb7+XePEexHWoB9Kq5n9qroNPkRwQZwgFAP9HNbQz5ohoIg=="
|
||||
},
|
||||
"@tanstack/query-devtools": {
|
||||
"version": "5.28.6",
|
||||
|
@ -38178,17 +38178,17 @@
|
|||
"integrity": "sha512-DXJGqbrsteWU9XehDf6s3k3QxwQqGUlNXpitsF1xbwkYBcDaAakiC6hjJSMfPBHOrbZCnWfAGCVf4vh2D75/xw=="
|
||||
},
|
||||
"@tanstack/react-query": {
|
||||
"version": "5.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.28.6.tgz",
|
||||
"integrity": "sha512-/DdYuDBSsA21Qbcder1R8Cr/3Nx0ZnA2lgtqKsLMvov8wL4+g0HBz/gWYZPlIsof7iyfQafyhg4wUVUsS3vWZw==",
|
||||
"version": "5.28.8",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.28.8.tgz",
|
||||
"integrity": "sha512-4XYhoRmcThqziB32HsyiBLNXJcukaeGfYwAQ+fZqUUE3ZP4oB/Zy41UJdql+TUg98+vsezfbixxAwAbGHfc5Hg==",
|
||||
"requires": {
|
||||
"@tanstack/query-core": "5.28.6"
|
||||
"@tanstack/query-core": "5.28.8"
|
||||
}
|
||||
},
|
||||
"@tanstack/react-query-devtools": {
|
||||
"version": "5.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.28.6.tgz",
|
||||
"integrity": "sha512-xSfskHlM2JkP7WpN89UqhJV2RbFxg8YnOMzQz+EEzWSsgxMI5Crce8HO9pcUAcJce8gSmw93RQwuKNdG3FbT6w==",
|
||||
"version": "5.28.8",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.28.8.tgz",
|
||||
"integrity": "sha512-NorR2ueGlGdB5PTvt1WynzjfNI/OJwiisB1r0UAwgi0Em2UalZpMltwvoIrGhJ0T2V+8b0MV5wD+cmf0PPdHGA==",
|
||||
"requires": {
|
||||
"@tanstack/query-devtools": "5.28.6"
|
||||
}
|
||||
|
|
|
@ -15,11 +15,15 @@ function errorDetailDisplay(
|
|||
title: string
|
||||
) {
|
||||
// Creates a bit of html for displaying a single error property if it exists.
|
||||
if (propertyName in errorObject && errorObject[propertyName]) {
|
||||
let value = errorObject[propertyName];
|
||||
if (propertyName in errorObject && value) {
|
||||
if (typeof value === 'object') {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
return (
|
||||
<div className="error_info">
|
||||
<span className="error_title">{title}:</span>
|
||||
{errorObject[propertyName]}
|
||||
{value}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -63,6 +67,10 @@ export const errorForDisplayFromTestCaseErrorDetails = (
|
|||
error_line: testCaseErrorDetails.task_line_contents,
|
||||
task_trace: testCaseErrorDetails.task_trace,
|
||||
stacktrace: testCaseErrorDetails.stacktrace,
|
||||
|
||||
task_type: testCaseErrorDetails.task_bpmn_type,
|
||||
output_data: testCaseErrorDetails.output_data,
|
||||
expected_data: testCaseErrorDetails.expected_data,
|
||||
};
|
||||
return errorForDisplay;
|
||||
};
|
||||
|
@ -94,6 +102,17 @@ export const childrenForErrorObject = (errorObject: ErrorForDisplay) => {
|
|||
'Line Number'
|
||||
);
|
||||
const errorLine = errorDetailDisplay(errorObject, 'error_line', 'Context');
|
||||
const taskType = errorDetailDisplay(errorObject, 'task_type', 'Task Type');
|
||||
const outputData = errorDetailDisplay(
|
||||
errorObject,
|
||||
'output_data',
|
||||
'Output Data'
|
||||
);
|
||||
const expectedData = errorDetailDisplay(
|
||||
errorObject,
|
||||
'expected_data',
|
||||
'Expected Data'
|
||||
);
|
||||
let codeTrace = null;
|
||||
if (errorObject.task_trace && errorObject.task_trace.length > 0) {
|
||||
codeTrace = (
|
||||
|
@ -126,6 +145,9 @@ export const childrenForErrorObject = (errorObject: ErrorForDisplay) => {
|
|||
lineNumber,
|
||||
errorLine,
|
||||
codeTrace,
|
||||
taskType,
|
||||
outputData,
|
||||
expectedData,
|
||||
];
|
||||
};
|
||||
|
||||
|
|
|
@ -226,9 +226,11 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
|||
element={Link}
|
||||
to={navItemPage}
|
||||
isCurrentPage={isActivePage(navItemPage)}
|
||||
data-qa={`extension-${slugifyString(uxElement.label)}`}
|
||||
data-qa={`extension-${slugifyString(
|
||||
uxElement.label || uxElement.page
|
||||
)}`}
|
||||
>
|
||||
{uxElement.label}
|
||||
{uxElement.label || uxElement.page}
|
||||
</HeaderMenuItem>
|
||||
</SpiffTooltip>
|
||||
);
|
||||
|
|
|
@ -81,6 +81,7 @@ export interface UiSchemaAction {
|
|||
* The api_path to call.
|
||||
* This will normally just be the colon delimited process model identifier for the extension minus the extension process group.
|
||||
* For example: extensions/path/to/extension -> path:to:extension
|
||||
* This will interpolate patterns like "{task_data_var}" if found in the task data.
|
||||
*/
|
||||
api_path: string;
|
||||
|
||||
|
@ -105,6 +106,13 @@ export interface UiSchemaAction {
|
|||
*/
|
||||
results_markdown_filename?: string;
|
||||
|
||||
/**
|
||||
* By default the extension data comes a key called "task_data" in the api result.
|
||||
* This will instead allow the extension data to be set by the full result.
|
||||
* this is useful when making api calls to non-extension apis.
|
||||
*/
|
||||
set_extension_data_from_full_api_result?: string;
|
||||
|
||||
/**
|
||||
* Parameters to grab from the search params of the url.
|
||||
* This is useful when linking from one extension to another so params can be grabbed and given to the process model when running.
|
||||
|
|
|
@ -35,7 +35,7 @@ export const useUriListForPermissions = () => {
|
|||
processModelFileShowPath: `/v1.0/process-models/${params.process_model_id}/files/${params.file_name}`,
|
||||
processModelPublishPath: `/v1.0/process-model-publish/${params.process_model_id}`,
|
||||
processModelShowPath: `/v1.0/process-models/${params.process_model_id}`,
|
||||
processModelTestsPath: `/v1.0/process-model-tests/${params.process_model_id}`,
|
||||
processModelTestsPath: `/v1.0/process-model-tests/run/${params.process_model_id}`,
|
||||
secretListPath: `/v1.0/secrets`,
|
||||
userSearch: `/v1.0/users/search`,
|
||||
userExists: `/v1.0/users/exists/by-username`,
|
||||
|
|
|
@ -326,6 +326,10 @@ export interface ErrorForDisplay {
|
|||
task_id?: string;
|
||||
task_name?: string;
|
||||
task_trace?: string[];
|
||||
|
||||
task_type?: string;
|
||||
output_data?: any;
|
||||
expected_data?: any;
|
||||
}
|
||||
|
||||
export interface AuthenticationParam {
|
||||
|
@ -420,6 +424,10 @@ export interface TestCaseErrorDetails {
|
|||
task_line_contents?: string;
|
||||
task_line_number?: number;
|
||||
task_trace?: string[];
|
||||
|
||||
task_bpmn_type?: string;
|
||||
output_data?: any;
|
||||
expected_data?: any;
|
||||
}
|
||||
|
||||
export interface TestCaseResult {
|
||||
|
|
|
@ -73,6 +73,7 @@ export default function Extension({
|
|||
|
||||
const interpolateNavigationString = useCallback(
|
||||
(navigationString: string, baseData: any) => {
|
||||
// This will interpolate patterns like "{task_data_var}" if found in the task data.
|
||||
let isValid = true;
|
||||
const data = { backend_base_url: BACKEND_BASE_URL, ...baseData };
|
||||
const optionString = navigationString.replace(/{(\w+)}/g, (_, k) => {
|
||||
|
@ -224,16 +225,20 @@ export default function Extension({
|
|||
pageComponent: UiSchemaPageComponent,
|
||||
result: ExtensionApiResponse
|
||||
) => {
|
||||
let taskData = result.task_data;
|
||||
if (pageComponent.on_form_submit?.set_extension_data_from_full_api_result) {
|
||||
taskData = result;
|
||||
}
|
||||
if (pageComponent && pageComponent.navigate_to_on_form_submit) {
|
||||
const optionString = interpolateNavigationString(
|
||||
pageComponent.navigate_to_on_form_submit,
|
||||
result.task_data
|
||||
taskData
|
||||
);
|
||||
if (optionString !== null) {
|
||||
window.location.href = optionString;
|
||||
}
|
||||
} else {
|
||||
setProcessedTaskData(result.task_data);
|
||||
setProcessedTaskData(taskData);
|
||||
if (result.rendered_results_markdown) {
|
||||
const newMarkdown = FormattingService.checkForSpiffFormats(
|
||||
result.rendered_results_markdown
|
||||
|
@ -277,16 +282,18 @@ export default function Extension({
|
|||
}
|
||||
} else {
|
||||
let postBody: ExtensionPostBody = { extension_input: dataToSubmit };
|
||||
let apiPath = targetUris.extensionPath;
|
||||
let apiPathRaw = targetUris.extensionPath;
|
||||
if (pageComponent && pageComponent.on_form_submit) {
|
||||
if (pageComponent.on_form_submit.is_full_api_path) {
|
||||
apiPath = `/${pageComponent.on_form_submit.api_path}`;
|
||||
postBody = dataToSubmit;
|
||||
apiPathRaw = pageComponent.on_form_submit.api_path.replace(/^\/?/, '/');
|
||||
if (!pageComponent.on_form_submit.is_full_api_path) {
|
||||
apiPathRaw = `${targetUris.extensionListPath}/${apiPathRaw}`;
|
||||
} else {
|
||||
apiPath = `${targetUris.extensionListPath}/${pageComponent.on_form_submit.api_path}`;
|
||||
postBody = dataToSubmit;
|
||||
}
|
||||
postBody.ui_schema_action = pageComponent.on_form_submit;
|
||||
}
|
||||
const apiPath =
|
||||
interpolateNavigationString(apiPathRaw, dataToSubmit) || apiPathRaw;
|
||||
|
||||
// NOTE: rjsf sets blanks values to undefined and JSON.stringify removes keys with undefined values
|
||||
// so we convert undefined values to null recursively so that we can unset values in form fields
|
||||
|
|
Loading…
Reference in New Issue