New calling process table (#1480)
* added new table to handle called process relationships * process caller api endpoint is working again w/ burnettk * fixed more tests and mypy w/ burnettk * unit tests are passing and commented out unrelated failing test w/ burnettk * all tests are passing almost w/ burnettk * uncommented flakey test w/ burnettk * minor change while reviewing w/ burnettk * some changes from coderabbit suggestions w/ burnettk * commented out sampling change w/ burnettk * name the foreign keys on the process caller table w/ burnettk --------- Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
parent
b9e70d12a6
commit
86f97d5937
|
@ -73,7 +73,10 @@ if [[ "${SPIFFWORKFLOW_BACKEND_LOAD_FIXTURE_DATA:-}" == "true" ]]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${SPIFFWORKFLOW_BACKEND_RUN_DATA_SETUP:-}" != "false" ]]; then
|
if [[ "${SPIFFWORKFLOW_BACKEND_RUN_DATA_SETUP:-}" != "false" ]]; then
|
||||||
SPIFFWORKFLOW_BACKEND_FAIL_ON_INVALID_PROCESS_MODELS=false poetry run python bin/save_all_bpmn.py
|
if [[ -z "${SPIFFWORKFLOW_BACKEND_FAIL_ON_INVALID_PROCESS_MODELS:-}" ]]; then
|
||||||
|
export SPIFFWORKFLOW_BACKEND_FAIL_ON_INVALID_PROCESS_MODELS=false
|
||||||
|
fi
|
||||||
|
poetry run python bin/save_all_bpmn.py
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY:-}" ]]; then
|
if [[ -n "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY:-}" ]]; then
|
||||||
|
|
|
@ -76,3 +76,7 @@ fi
|
||||||
export SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER_IN_CREATE_APP
|
export SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER_IN_CREATE_APP
|
||||||
|
|
||||||
export FLASK_APP=src/spiffworkflow_backend
|
export FLASK_APP=src/spiffworkflow_backend
|
||||||
|
|
||||||
|
if [[ -z "${SPIFFWORKFLOW_BACKEND_FAIL_ON_INVALID_PROCESS_MODELS:-}" ]]; then
|
||||||
|
export SPIFFWORKFLOW_BACKEND_FAIL_ON_INVALID_PROCESS_MODELS=false
|
||||||
|
fi
|
||||||
|
|
|
@ -24,7 +24,7 @@ else
|
||||||
else
|
else
|
||||||
|
|
||||||
if [[ "${SPIFFWORKFLOW_BACKEND_RUN_DATA_SETUP:-}" != "false" ]]; then
|
if [[ "${SPIFFWORKFLOW_BACKEND_RUN_DATA_SETUP:-}" != "false" ]]; then
|
||||||
SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER_IN_CREATE_APP=false SPIFFWORKFLOW_BACKEND_FAIL_ON_INVALID_PROCESS_MODELS=false poetry run python bin/save_all_bpmn.py
|
SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER_IN_CREATE_APP=false poetry run python bin/save_all_bpmn.py
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# this line blocks
|
# this line blocks
|
||||||
|
|
|
@ -7,7 +7,6 @@ from spiffworkflow_backend.services.data_setup_service import DataSetupService
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
"""Main."""
|
|
||||||
app = create_app()
|
app = create_app()
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
failing_process_models = DataSetupService.save_all_process_models()
|
failing_process_models = DataSetupService.save_all_process_models()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
function error_handler() {
|
function error_handler() {
|
||||||
>&2 echo "Exited with BAD EXIT CODE '${2}' in ${0} script at line: ${1}."
|
echo >&2 "Exited with BAD EXIT CODE '${2}' in ${0} script at line: ${1}."
|
||||||
exit "$2"
|
exit "$2"
|
||||||
}
|
}
|
||||||
trap 'error_handler ${LINENO} $?' ERR
|
trap 'error_handler ${LINENO} $?' ERR
|
||||||
|
@ -16,7 +16,7 @@ user_file_with_one_email_per_line="${1:-}"
|
||||||
|
|
||||||
keycloak_realm="${2:-spiffworkflow}"
|
keycloak_realm="${2:-spiffworkflow}"
|
||||||
if [[ -z "${1:-}" ]]; then
|
if [[ -z "${1:-}" ]]; then
|
||||||
>&2 echo "usage: $(basename "$0") [user_file_with_one_email_per_line]"
|
echo >&2 "usage: $(basename "$0") [user_file_with_one_email_per_line]"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -42,14 +42,15 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# https://www.appsdeveloperblog.com/keycloak-rest-api-create-a-new-user/
|
# https://www.appsdeveloperblog.com/keycloak-rest-api-create-a-new-user/
|
||||||
result=$(curl --fail -s -X POST "$KEYCLOAK_URL" "$INSECURE" \
|
result=$(
|
||||||
|
curl --fail -s -X POST "$KEYCLOAK_URL" "$INSECURE" \
|
||||||
--header 'Content-Type: application/x-www-form-urlencoded' \
|
--header 'Content-Type: application/x-www-form-urlencoded' \
|
||||||
--data-urlencode "username=${ADMIN_USERNAME}" \
|
--data-urlencode "username=${ADMIN_USERNAME}" \
|
||||||
--data-urlencode "password=${ADMIN_PASSWORD}" \
|
--data-urlencode "password=${ADMIN_PASSWORD}" \
|
||||||
--data-urlencode 'grant_type=password' \
|
--data-urlencode 'grant_type=password' \
|
||||||
--data-urlencode 'client_id=admin-cli'
|
--data-urlencode 'client_id=admin-cli'
|
||||||
)
|
)
|
||||||
backend_token=$(jq -r '.access_token' <<< "$result")
|
backend_token=$(jq -r '.access_token' <<<"$result")
|
||||||
|
|
||||||
function add_user() {
|
function add_user() {
|
||||||
local user_email=$1
|
local user_email=$1
|
||||||
|
@ -77,16 +78,16 @@ first_line_processed="false"
|
||||||
custom_attribute_one=''
|
custom_attribute_one=''
|
||||||
|
|
||||||
while read -r input_line; do
|
while read -r input_line; do
|
||||||
if ! grep -qE '^#' <<<"$input_line" ; then
|
if ! grep -qE '^#' <<<"$input_line"; then
|
||||||
if [[ "$first_line_processed" == "false" ]]; then
|
if [[ "$first_line_processed" == "false" ]]; then
|
||||||
email_header=$(awk -F ',' '{print $1}' <<<"$input_line")
|
email_header=$(awk -F ',' '{print $1}' <<<"$input_line")
|
||||||
pass_header=$(awk -F ',' '{print $2}' <<<"$input_line")
|
pass_header=$(awk -F ',' '{print $2}' <<<"$input_line")
|
||||||
if [[ "$email_header" != "email" ]]; then
|
if [[ "$email_header" != "email" ]]; then
|
||||||
>&2 echo "ERROR: the first column in the first row must be email."
|
echo >&2 "ERROR: the first column in the first row must be email."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [[ "$pass_header" != "pass" ]]; then
|
if [[ "$pass_header" != "pass" ]]; then
|
||||||
>&2 echo "ERROR: the first column in the first row must be pass."
|
echo >&2 "ERROR: the first column in the first row must be pass."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
custom_attribute_one=$(awk -F ',' '{print $3}' <<<"$input_line")
|
custom_attribute_one=$(awk -F ',' '{print $3}' <<<"$input_line")
|
||||||
|
@ -97,7 +98,7 @@ while read -r input_line; do
|
||||||
username=$(awk -F '@' '{print $1}' <<<"$user_email")
|
username=$(awk -F '@' '{print $1}' <<<"$user_email")
|
||||||
|
|
||||||
if [[ "$username" == "$ADMIN_USERNAME" || "$user_email" == "$ADMIN_USERNAME" ]]; then
|
if [[ "$username" == "$ADMIN_USERNAME" || "$user_email" == "$ADMIN_USERNAME" ]]; then
|
||||||
>&2 echo "ERROR: The user used as the admin user matches a user in the current import list. This should not happen. Comment out that user from the list or use a different admin user: ${ADMIN_USERNAME}"
|
echo >&2 "ERROR: The user used as the admin user matches a user in the current import list. This should not happen. Comment out that user from the list or use a different admin user: ${ADMIN_USERNAME}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -113,7 +114,7 @@ while read -r input_line; do
|
||||||
|
|
||||||
user_id=$(jq -r '.[0] | .id' <<<"$user_info")
|
user_id=$(jq -r '.[0] | .id' <<<"$user_info")
|
||||||
if [[ -z "$user_id" ]]; then
|
if [[ -z "$user_id" ]]; then
|
||||||
>&2 echo "ERROR: Could not find user_id for user: ${user_email}"
|
echo >&2 "ERROR: Could not find user_id for user: ${user_email}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
curl --fail --location --silent --request DELETE "${KEYCLOAK_BASE_URL}/admin/realms/${keycloak_realm}/users/${user_id}" \
|
curl --fail --location --silent --request DELETE "${KEYCLOAK_BASE_URL}/admin/realms/${keycloak_realm}/users/${user_id}" \
|
||||||
|
@ -123,7 +124,7 @@ while read -r input_line; do
|
||||||
http_code=$(add_user "$user_email" "$username" "$password" "$user_attribute_one")
|
http_code=$(add_user "$user_email" "$username" "$password" "$user_attribute_one")
|
||||||
fi
|
fi
|
||||||
if [[ "$http_code" != "201" ]]; then
|
if [[ "$http_code" != "201" ]]; then
|
||||||
>&2 echo "ERROR: Failed to create user: ${user_email} with http_code: ${http_code}"
|
echo >&2 "ERROR: Failed to create user: ${user_email} with http_code: ${http_code}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: d4b900e71852
|
||||||
|
Revises: c6e246c3c04e
|
||||||
|
Create Date: 2024-05-02 16:21:48.287934
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'd4b900e71852'
|
||||||
|
down_revision = 'c6e246c3c04e'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('process_caller_relationship',
|
||||||
|
sa.Column('called_reference_cache_process_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('calling_reference_cache_process_id', sa.Integer(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['called_reference_cache_process_id'], ['reference_cache.id'], name='called_reference_cache_process_id_fk'),
|
||||||
|
sa.ForeignKeyConstraint(['calling_reference_cache_process_id'], ['reference_cache.id'], name='calling_reference_cache_process_id_fk'),
|
||||||
|
sa.PrimaryKeyConstraint('called_reference_cache_process_id', 'calling_reference_cache_process_id', name='process_caller_relationship_pk')
|
||||||
|
)
|
||||||
|
with op.batch_alter_table('process_caller_relationship', schema=None) as batch_op:
|
||||||
|
batch_op.create_index(batch_op.f('ix_process_caller_relationship_called_reference_cache_process_id'), ['called_reference_cache_process_id'], unique=False)
|
||||||
|
batch_op.create_index(batch_op.f('ix_process_caller_relationship_calling_reference_cache_process_id'), ['calling_reference_cache_process_id'], unique=False)
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('process_caller_relationship', schema=None) as batch_op:
|
||||||
|
batch_op.drop_index(batch_op.f('ix_process_caller_relationship_calling_reference_cache_process_id'))
|
||||||
|
batch_op.drop_index(batch_op.f('ix_process_caller_relationship_called_reference_cache_process_id'))
|
||||||
|
|
||||||
|
op.drop_table('process_caller_relationship')
|
||||||
|
# ### end Alembic commands ###
|
|
@ -112,5 +112,6 @@ from spiffworkflow_backend.models.future_task import (
|
||||||
from spiffworkflow_backend.models.feature_flag import (
|
from spiffworkflow_backend.models.feature_flag import (
|
||||||
FeatureFlagModel,
|
FeatureFlagModel,
|
||||||
) # noqa: F401
|
) # noqa: F401
|
||||||
|
from spiffworkflow_backend.models.process_caller_relationship import ProcessCallerRelationshipModel # noqa: F401
|
||||||
|
|
||||||
add_listeners()
|
add_listeners()
|
||||||
|
|
|
@ -2,6 +2,7 @@ from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
||||||
from spiffworkflow_backend.models.db import db
|
from spiffworkflow_backend.models.db import db
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: delete this file
|
||||||
class ProcessCallerCacheModel(SpiffworkflowBaseDBModel):
|
class ProcessCallerCacheModel(SpiffworkflowBaseDBModel):
|
||||||
"""A cache of calling process ids for all Processes defined in all files."""
|
"""A cache of calling process ids for all Processes defined in all files."""
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
from flask import current_app
|
||||||
|
from sqlalchemy import ForeignKey
|
||||||
|
from sqlalchemy import PrimaryKeyConstraint
|
||||||
|
from sqlalchemy.dialects.mysql import insert as mysql_insert
|
||||||
|
from sqlalchemy.dialects.postgresql import insert as postgres_insert
|
||||||
|
|
||||||
|
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
||||||
|
from spiffworkflow_backend.models.db import db
|
||||||
|
|
||||||
|
|
||||||
|
class CalledProcessNotFoundError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class CallingProcessNotFoundError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessCallerRelationshipModel(SpiffworkflowBaseDBModel):
|
||||||
|
"""A cache of calling process ids for all Processes defined in all files."""
|
||||||
|
|
||||||
|
__tablename__ = "process_caller_relationship"
|
||||||
|
__table_args__ = (
|
||||||
|
PrimaryKeyConstraint(
|
||||||
|
"called_reference_cache_process_id",
|
||||||
|
"calling_reference_cache_process_id",
|
||||||
|
name="process_caller_relationship_pk",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
called_reference_cache_process_id = db.Column(
|
||||||
|
ForeignKey("reference_cache.id", name="called_reference_cache_process_id_fk"), nullable=False, index=True
|
||||||
|
)
|
||||||
|
calling_reference_cache_process_id = db.Column(
|
||||||
|
ForeignKey("reference_cache.id", name="calling_reference_cache_process_id_fk"), nullable=False, index=True
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def insert_or_update(cls, called_reference_cache_process_id: int, calling_reference_cache_process_id: int) -> None:
|
||||||
|
caller_info = {
|
||||||
|
"called_reference_cache_process_id": called_reference_cache_process_id,
|
||||||
|
"calling_reference_cache_process_id": calling_reference_cache_process_id,
|
||||||
|
}
|
||||||
|
on_duplicate_key_stmt = None
|
||||||
|
if current_app.config["SPIFFWORKFLOW_BACKEND_DATABASE_TYPE"] == "mysql":
|
||||||
|
insert_stmt = mysql_insert(ProcessCallerRelationshipModel).values(caller_info)
|
||||||
|
# We don't actually want to update anything but it doesn't really matter if we do since it should be the same value
|
||||||
|
on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(
|
||||||
|
called_reference_cache_process_id=insert_stmt.inserted.called_reference_cache_process_id
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
insert_stmt = postgres_insert(ProcessCallerRelationshipModel).values(caller_info)
|
||||||
|
on_duplicate_key_stmt = insert_stmt.on_conflict_do_nothing(
|
||||||
|
index_elements=["called_reference_cache_process_id", "calling_reference_cache_process_id"]
|
||||||
|
)
|
||||||
|
db.session.execute(on_duplicate_key_stmt)
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
@ -13,6 +15,7 @@ from spiffworkflow_backend.helpers.spiff_enum import SpiffEnum
|
||||||
from spiffworkflow_backend.models.cache_generation import CacheGenerationModel
|
from spiffworkflow_backend.models.cache_generation import CacheGenerationModel
|
||||||
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
||||||
from spiffworkflow_backend.models.db import db
|
from spiffworkflow_backend.models.db import db
|
||||||
|
from spiffworkflow_backend.models.process_caller_relationship import ProcessCallerRelationshipModel
|
||||||
|
|
||||||
|
|
||||||
# SpecReferenceNotFoundError
|
# SpecReferenceNotFoundError
|
||||||
|
@ -83,6 +86,20 @@ class ReferenceCacheModel(SpiffworkflowBaseDBModel):
|
||||||
|
|
||||||
generation = relationship(CacheGenerationModel)
|
generation = relationship(CacheGenerationModel)
|
||||||
|
|
||||||
|
process_callers = relationship(
|
||||||
|
ProcessCallerRelationshipModel,
|
||||||
|
foreign_keys="[ProcessCallerRelationshipModel.called_reference_cache_process_id]",
|
||||||
|
cascade="all, delete-orphan",
|
||||||
|
single_parent=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
calling_processes = relationship(
|
||||||
|
ProcessCallerRelationshipModel,
|
||||||
|
foreign_keys="[ProcessCallerRelationshipModel.calling_reference_cache_process_id]",
|
||||||
|
cascade="all, delete-orphan",
|
||||||
|
single_parent=True,
|
||||||
|
)
|
||||||
|
|
||||||
def relative_path(self) -> str:
|
def relative_path(self) -> str:
|
||||||
return os.path.join(self.relative_location, self.file_name).replace("/", os.sep)
|
return os.path.join(self.relative_location, self.file_name).replace("/", os.sep)
|
||||||
|
|
||||||
|
@ -104,7 +121,7 @@ class ReferenceCacheModel(SpiffworkflowBaseDBModel):
|
||||||
relative_location: str,
|
relative_location: str,
|
||||||
properties: dict | None = None,
|
properties: dict | None = None,
|
||||||
use_current_cache_generation: bool = False,
|
use_current_cache_generation: bool = False,
|
||||||
) -> "ReferenceCacheModel":
|
) -> ReferenceCacheModel:
|
||||||
reference_cache = cls(
|
reference_cache = cls(
|
||||||
identifier=identifier,
|
identifier=identifier,
|
||||||
display_name=display_name,
|
display_name=display_name,
|
||||||
|
@ -124,7 +141,7 @@ class ReferenceCacheModel(SpiffworkflowBaseDBModel):
|
||||||
return reference_cache
|
return reference_cache
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_spec_reference(cls, ref: Reference, use_current_cache_generation: bool = False) -> "ReferenceCacheModel":
|
def from_spec_reference(cls, ref: Reference, use_current_cache_generation: bool = False) -> ReferenceCacheModel:
|
||||||
reference_cache = cls.from_params(
|
reference_cache = cls.from_params(
|
||||||
identifier=ref.identifier,
|
identifier=ref.identifier,
|
||||||
display_name=ref.display_name,
|
display_name=ref.display_name,
|
||||||
|
|
|
@ -46,11 +46,11 @@ from spiffworkflow_backend.services.file_system_service import FileSystemService
|
||||||
from spiffworkflow_backend.services.git_service import GitCommandError
|
from spiffworkflow_backend.services.git_service import GitCommandError
|
||||||
from spiffworkflow_backend.services.git_service import GitService
|
from spiffworkflow_backend.services.git_service import GitService
|
||||||
from spiffworkflow_backend.services.jinja_service import JinjaService
|
from spiffworkflow_backend.services.jinja_service import JinjaService
|
||||||
from spiffworkflow_backend.services.process_caller_service import ProcessCallerService
|
|
||||||
from spiffworkflow_backend.services.process_instance_processor import ProcessInstanceProcessor
|
from spiffworkflow_backend.services.process_instance_processor import ProcessInstanceProcessor
|
||||||
from spiffworkflow_backend.services.process_instance_queue_service import ProcessInstanceQueueService
|
from spiffworkflow_backend.services.process_instance_queue_service import ProcessInstanceQueueService
|
||||||
from spiffworkflow_backend.services.process_instance_service import ProcessInstanceService
|
from spiffworkflow_backend.services.process_instance_service import ProcessInstanceService
|
||||||
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
||||||
|
from spiffworkflow_backend.services.reference_cache_service import ReferenceCacheService
|
||||||
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
||||||
from spiffworkflow_backend.services.task_service import TaskModelError
|
from spiffworkflow_backend.services.task_service import TaskModelError
|
||||||
from spiffworkflow_backend.services.task_service import TaskService
|
from spiffworkflow_backend.services.task_service import TaskService
|
||||||
|
@ -122,14 +122,9 @@ def process_list() -> Any:
|
||||||
return ReferenceSchema(many=True).dump(permitted_references)
|
return ReferenceSchema(many=True).dump(permitted_references)
|
||||||
|
|
||||||
|
|
||||||
|
# if we pass in bpmn_process_identifiers of [a], a is "called" and we want to find which processes are *callers* of a
|
||||||
def process_caller_list(bpmn_process_identifiers: list[str]) -> Any:
|
def process_caller_list(bpmn_process_identifiers: list[str]) -> Any:
|
||||||
callers = ProcessCallerService.callers(bpmn_process_identifiers)
|
references = ReferenceCacheService.get_reference_cache_entries_calling_process(bpmn_process_identifiers)
|
||||||
references = (
|
|
||||||
ReferenceCacheModel.basic_query()
|
|
||||||
.filter_by(type="process")
|
|
||||||
.filter(ReferenceCacheModel.identifier.in_(callers)) # type: ignore
|
|
||||||
.all()
|
|
||||||
)
|
|
||||||
return ReferenceSchema(many=True).dump(references)
|
return ReferenceSchema(many=True).dump(references)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -472,21 +472,13 @@ def process_model_create_with_natural_language(modified_process_group_id: str, b
|
||||||
"required": [],
|
"required": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
SpecFileService.add_file(
|
files_to_update = {
|
||||||
process_model_info,
|
f"{process_model_identifier}.bpmn": str.encode(bpmn_template_contents),
|
||||||
f"{process_model_identifier}.bpmn",
|
f"{form_identifier}-schema.json": str.encode(json.dumps(form_schema_json)),
|
||||||
str.encode(bpmn_template_contents),
|
f"{form_identifier}-uischema.json": str.encode(json.dumps(form_uischema_json)),
|
||||||
)
|
}
|
||||||
SpecFileService.add_file(
|
for file_name, contents in files_to_update.items():
|
||||||
process_model_info,
|
SpecFileService.update_file(process_model_info, file_name, contents)
|
||||||
f"{form_identifier}-schema.json",
|
|
||||||
str.encode(json.dumps(form_schema_json)),
|
|
||||||
)
|
|
||||||
SpecFileService.add_file(
|
|
||||||
process_model_info,
|
|
||||||
f"{form_identifier}-uischema.json",
|
|
||||||
str.encode(json.dumps(form_uischema_json)),
|
|
||||||
)
|
|
||||||
|
|
||||||
_commit_and_push_to_git(f"User: {g.user.username} created process model via natural language: {process_model_info.id}")
|
_commit_and_push_to_git(f"User: {g.user.username} created process model via natural language: {process_model_info.id}")
|
||||||
|
|
||||||
|
@ -585,7 +577,7 @@ def _create_or_update_process_model_file(
|
||||||
|
|
||||||
file = None
|
file = None
|
||||||
try:
|
try:
|
||||||
file = SpecFileService.update_file(process_model, request_file.filename, request_file_contents, user=g.user)
|
file, _ = SpecFileService.update_file(process_model, request_file.filename, request_file_contents, user=g.user)
|
||||||
except ProcessModelFileInvalidError as exception:
|
except ProcessModelFileInvalidError as exception:
|
||||||
raise (
|
raise (
|
||||||
ApiError(
|
ApiError(
|
||||||
|
|
|
@ -33,6 +33,7 @@ class DataSetupService:
|
||||||
files = FileSystemService.walk_files_from_root_path(True, None)
|
files = FileSystemService.walk_files_from_root_path(True, None)
|
||||||
reference_objects: dict[str, ReferenceCacheModel] = {}
|
reference_objects: dict[str, ReferenceCacheModel] = {}
|
||||||
all_data_store_specifications: dict[tuple[str, str, str], Any] = {}
|
all_data_store_specifications: dict[tuple[str, str, str], Any] = {}
|
||||||
|
references = []
|
||||||
|
|
||||||
for file in files:
|
for file in files:
|
||||||
if FileSystemService.is_process_model_json_file(file):
|
if FileSystemService.is_process_model_json_file(file):
|
||||||
|
@ -46,13 +47,13 @@ class DataSetupService:
|
||||||
try:
|
try:
|
||||||
reference_cache = ReferenceCacheModel.from_spec_reference(ref)
|
reference_cache = ReferenceCacheModel.from_spec_reference(ref)
|
||||||
ReferenceCacheService.add_unique_reference_cache_object(reference_objects, reference_cache)
|
ReferenceCacheService.add_unique_reference_cache_object(reference_objects, reference_cache)
|
||||||
SpecFileService.update_caches_except_process(ref)
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
references.append(ref)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
failing_process_models.append(
|
failing_process_models.append(
|
||||||
(
|
(
|
||||||
f"{ref.relative_location}/{ref.file_name}",
|
f"{ref.relative_location}/{ref.file_name}",
|
||||||
str(ex),
|
repr(ex),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except Exception as ex2:
|
except Exception as ex2:
|
||||||
|
@ -103,6 +104,18 @@ class DataSetupService:
|
||||||
ReferenceCacheService.add_new_generation(reference_objects)
|
ReferenceCacheService.add_new_generation(reference_objects)
|
||||||
cls._sync_data_store_models_with_specifications(all_data_store_specifications)
|
cls._sync_data_store_models_with_specifications(all_data_store_specifications)
|
||||||
|
|
||||||
|
for ref in references:
|
||||||
|
try:
|
||||||
|
SpecFileService.update_caches_except_process(ref)
|
||||||
|
db.session.commit()
|
||||||
|
except Exception as ex:
|
||||||
|
failing_process_models.append(
|
||||||
|
(
|
||||||
|
f"{ref.relative_location}/{ref.file_name}",
|
||||||
|
repr(ex),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return failing_process_models
|
return failing_process_models
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -34,18 +34,19 @@ def traces_sampler(sampling_context: Any) -> Any:
|
||||||
if sampling_context["parent_sampled"] is not None:
|
if sampling_context["parent_sampled"] is not None:
|
||||||
return sampling_context["parent_sampled"]
|
return sampling_context["parent_sampled"]
|
||||||
|
|
||||||
if "wsgi_environ" in sampling_context:
|
# sample some requests at a higher rate
|
||||||
wsgi_environ = sampling_context["wsgi_environ"]
|
# if "wsgi_environ" in sampling_context:
|
||||||
path_info = wsgi_environ.get("PATH_INFO")
|
# wsgi_environ = sampling_context["wsgi_environ"]
|
||||||
request_method = wsgi_environ.get("REQUEST_METHOD")
|
# path_info = wsgi_environ.get("PATH_INFO")
|
||||||
|
# request_method = wsgi_environ.get("REQUEST_METHOD")
|
||||||
# tasks_controller.task_submit
|
#
|
||||||
# this is the current pain point as of 31 jan 2023.
|
# # tasks_controller.task_submit
|
||||||
if path_info and (
|
# # this is the current pain point as of 31 jan 2023.
|
||||||
(path_info.startswith("/v1.0/tasks/") and request_method == "PUT")
|
# if path_info and (
|
||||||
or (path_info.startswith("/v1.0/task-data/") and request_method == "GET")
|
# (path_info.startswith("/v1.0/tasks/") and request_method == "PUT")
|
||||||
):
|
# or (path_info.startswith("/v1.0/task-data/") and request_method == "GET")
|
||||||
return 1
|
# ):
|
||||||
|
# return 1
|
||||||
|
|
||||||
# Default sample rate for all others (replaces traces_sample_rate)
|
# Default sample rate for all others (replaces traces_sample_rate)
|
||||||
return 0.01
|
return 0.01
|
||||||
|
|
|
@ -1,35 +1,50 @@
|
||||||
from sqlalchemy import or_
|
from sqlalchemy import or_
|
||||||
|
|
||||||
from spiffworkflow_backend.models.db import db
|
from spiffworkflow_backend.models.db import db
|
||||||
from spiffworkflow_backend.models.process_caller import ProcessCallerCacheModel
|
from spiffworkflow_backend.models.process_caller_relationship import CalledProcessNotFoundError
|
||||||
|
from spiffworkflow_backend.models.process_caller_relationship import CallingProcessNotFoundError
|
||||||
|
from spiffworkflow_backend.models.process_caller_relationship import ProcessCallerRelationshipModel
|
||||||
|
from spiffworkflow_backend.models.reference_cache import ReferenceCacheModel
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: delete this file
|
||||||
class ProcessCallerService:
|
class ProcessCallerService:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def count() -> int:
|
def count() -> int:
|
||||||
return ProcessCallerCacheModel.query.count() # type: ignore
|
"""This is used in tests ONLY."""
|
||||||
|
return ProcessCallerRelationshipModel.query.count() # type: ignore
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def clear_cache() -> None:
|
def clear_cache() -> None:
|
||||||
db.session.query(ProcessCallerCacheModel).delete()
|
db.session.query(ProcessCallerRelationshipModel).delete()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def clear_cache_for_process_ids(process_ids: list[str]) -> None:
|
def clear_cache_for_process_ids(reference_cache_ids: list[int]) -> None:
|
||||||
db.session.query(ProcessCallerCacheModel).filter(
|
ProcessCallerRelationshipModel.query.filter(
|
||||||
or_(
|
or_(
|
||||||
ProcessCallerCacheModel.process_identifier.in_(process_ids),
|
ProcessCallerRelationshipModel.called_reference_cache_process_id.in_(reference_cache_ids),
|
||||||
ProcessCallerCacheModel.calling_process_identifier.in_(process_ids),
|
ProcessCallerRelationshipModel.calling_reference_cache_process_id.in_(reference_cache_ids),
|
||||||
)
|
)
|
||||||
).delete()
|
).delete()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_caller(process_id: str, called_process_ids: list[str]) -> None:
|
def add_caller(calling_process_identifier: str, called_process_identifiers: list[str]) -> None:
|
||||||
for called_process_id in called_process_ids:
|
reference_cache_records = (
|
||||||
db.session.add(ProcessCallerCacheModel(process_identifier=called_process_id, calling_process_identifier=process_id))
|
ReferenceCacheModel.basic_query()
|
||||||
|
.filter(ReferenceCacheModel.identifier.in_(called_process_identifiers + [calling_process_identifier])) # type: ignore
|
||||||
@staticmethod
|
.all()
|
||||||
def callers(process_ids: list[str]) -> list[str]:
|
)
|
||||||
records = (
|
reference_cache_dict = {r.identifier: r.id for r in reference_cache_records}
|
||||||
db.session.query(ProcessCallerCacheModel).filter(ProcessCallerCacheModel.process_identifier.in_(process_ids)).all()
|
if calling_process_identifier not in reference_cache_dict:
|
||||||
|
raise CallingProcessNotFoundError(
|
||||||
|
f"Could not find calling process id '{calling_process_identifier}' in reference_cache table."
|
||||||
|
)
|
||||||
|
for called_process_identifier in called_process_identifiers:
|
||||||
|
if called_process_identifier not in reference_cache_dict:
|
||||||
|
raise CalledProcessNotFoundError(
|
||||||
|
f"Could not find called process id '{called_process_identifier}' in reference_cache table."
|
||||||
|
)
|
||||||
|
ProcessCallerRelationshipModel.insert_or_update(
|
||||||
|
called_reference_cache_process_id=reference_cache_dict[called_process_identifier],
|
||||||
|
calling_reference_cache_process_id=reference_cache_dict[calling_process_identifier],
|
||||||
)
|
)
|
||||||
return sorted({r.calling_process_identifier for r in records})
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
from sqlalchemy import insert
|
from sqlalchemy import insert
|
||||||
|
from sqlalchemy.orm import aliased
|
||||||
|
|
||||||
from spiffworkflow_backend.models.cache_generation import CacheGenerationModel
|
from spiffworkflow_backend.models.cache_generation import CacheGenerationModel
|
||||||
from spiffworkflow_backend.models.db import db
|
from spiffworkflow_backend.models.db import db
|
||||||
|
from spiffworkflow_backend.models.process_caller_relationship import ProcessCallerRelationshipModel
|
||||||
from spiffworkflow_backend.models.reference_cache import ReferenceCacheModel
|
from spiffworkflow_backend.models.reference_cache import ReferenceCacheModel
|
||||||
from spiffworkflow_backend.services.upsearch_service import UpsearchService
|
from spiffworkflow_backend.services.upsearch_service import UpsearchService
|
||||||
|
|
||||||
|
@ -32,16 +34,12 @@ class ReferenceCacheService:
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def upsearch(cls, location: str, identifier: str, type: str) -> str | None:
|
def upsearch(cls, location: str, identifier: str, type: str) -> str | None:
|
||||||
# really want to be able to join to this table on max(id)
|
|
||||||
cache_generation = CacheGenerationModel.newest_generation_for_table("reference_cache")
|
|
||||||
if cache_generation is None:
|
|
||||||
return None
|
|
||||||
locations = UpsearchService.upsearch_locations(location)
|
locations = UpsearchService.upsearch_locations(location)
|
||||||
references = (
|
references = (
|
||||||
ReferenceCacheModel.query.filter_by(
|
ReferenceCacheModel.basic_query()
|
||||||
|
.filter_by(
|
||||||
identifier=identifier,
|
identifier=identifier,
|
||||||
type=type,
|
type=type,
|
||||||
generation=cache_generation,
|
|
||||||
)
|
)
|
||||||
.filter(ReferenceCacheModel.relative_location.in_(locations)) # type: ignore
|
.filter(ReferenceCacheModel.relative_location.in_(locations)) # type: ignore
|
||||||
.order_by(ReferenceCacheModel.relative_location.desc()) # type: ignore
|
.order_by(ReferenceCacheModel.relative_location.desc()) # type: ignore
|
||||||
|
@ -53,3 +51,20 @@ class ReferenceCacheService:
|
||||||
return reference.relative_location # type: ignore
|
return reference.relative_location # type: ignore
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_reference_cache_entries_calling_process(cls, bpmn_process_identifiers: list[str]) -> list[ReferenceCacheModel]:
|
||||||
|
called_reference_alias = aliased(ReferenceCacheModel)
|
||||||
|
references: list[ReferenceCacheModel] = (
|
||||||
|
ReferenceCacheModel.basic_query()
|
||||||
|
.join(
|
||||||
|
ProcessCallerRelationshipModel,
|
||||||
|
ProcessCallerRelationshipModel.calling_reference_cache_process_id == ReferenceCacheModel.id,
|
||||||
|
)
|
||||||
|
.join(
|
||||||
|
called_reference_alias,
|
||||||
|
called_reference_alias.id == ProcessCallerRelationshipModel.called_reference_cache_process_id,
|
||||||
|
)
|
||||||
|
.filter(called_reference_alias.identifier.in_(bpmn_process_identifiers))
|
||||||
|
).all()
|
||||||
|
return references
|
||||||
|
|
|
@ -138,11 +138,6 @@ class SpecFileService(FileSystemService):
|
||||||
)
|
)
|
||||||
return references
|
return references
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def add_file(process_model_info: ProcessModelInfo, file_name: str, binary_data: bytes) -> File:
|
|
||||||
# Same as update
|
|
||||||
return SpecFileService.update_file(process_model_info, file_name, binary_data)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_bpmn_xml(cls, file_name: str, binary_data: bytes) -> None:
|
def validate_bpmn_xml(cls, file_name: str, binary_data: bytes) -> None:
|
||||||
file_type = FileSystemService.file_type(file_name)
|
file_type = FileSystemService.file_type(file_name)
|
||||||
|
@ -156,8 +151,13 @@ class SpecFileService(FileSystemService):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def update_file(
|
def update_file(
|
||||||
cls, process_model_info: ProcessModelInfo, file_name: str, binary_data: bytes, user: UserModel | None = None
|
cls,
|
||||||
) -> File:
|
process_model_info: ProcessModelInfo,
|
||||||
|
file_name: str,
|
||||||
|
binary_data: bytes,
|
||||||
|
user: UserModel | None = None,
|
||||||
|
update_process_cache_only: bool = False,
|
||||||
|
) -> tuple[File, list[Reference]]:
|
||||||
SpecFileService.assert_valid_file_name(file_name)
|
SpecFileService.assert_valid_file_name(file_name)
|
||||||
cls.validate_bpmn_xml(file_name, binary_data)
|
cls.validate_bpmn_xml(file_name, binary_data)
|
||||||
|
|
||||||
|
@ -189,6 +189,9 @@ class SpecFileService(FileSystemService):
|
||||||
)
|
)
|
||||||
|
|
||||||
all_called_element_ids = all_called_element_ids | set(ref.called_element_ids)
|
all_called_element_ids = all_called_element_ids | set(ref.called_element_ids)
|
||||||
|
if update_process_cache_only:
|
||||||
|
SpecFileService.update_process_cache(ref)
|
||||||
|
else:
|
||||||
SpecFileService.update_all_caches(ref)
|
SpecFileService.update_all_caches(ref)
|
||||||
|
|
||||||
if user is not None:
|
if user is not None:
|
||||||
|
@ -217,7 +220,7 @@ class SpecFileService(FileSystemService):
|
||||||
# make sure we save the file as the last thing we do to ensure validations have run
|
# make sure we save the file as the last thing we do to ensure validations have run
|
||||||
full_file_path = SpecFileService.full_file_path(process_model_info, file_name)
|
full_file_path = SpecFileService.full_file_path(process_model_info, file_name)
|
||||||
SpecFileService.write_file_data_to_system(full_file_path, binary_data)
|
SpecFileService.write_file_data_to_system(full_file_path, binary_data)
|
||||||
return SpecFileService.to_file_object(file_name, full_file_path)
|
return (SpecFileService.to_file_object(file_name, full_file_path), references)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def last_modified(process_model: ProcessModelInfo, file_name: str) -> datetime:
|
def last_modified(process_model: ProcessModelInfo, file_name: str) -> datetime:
|
||||||
|
@ -264,20 +267,13 @@ class SpecFileService(FileSystemService):
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
|
|
||||||
process_ids = []
|
reference_cache_ids = []
|
||||||
|
|
||||||
for record in records:
|
for record in records:
|
||||||
process_ids.append(record.identifier)
|
reference_cache_ids.append(record.id)
|
||||||
db.session.delete(record)
|
db.session.delete(record)
|
||||||
|
|
||||||
ProcessCallerService.clear_cache_for_process_ids(process_ids)
|
ProcessCallerService.clear_cache_for_process_ids(reference_cache_ids)
|
||||||
# fixme: likely the other caches should be cleared as well, but we don't have a clean way to do so yet.
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def clear_caches() -> None:
|
|
||||||
db.session.query(ReferenceCacheModel).delete()
|
|
||||||
ProcessCallerService.clear_cache()
|
|
||||||
# fixme: likely the other caches should be cleared as well, but we don't have a clean way to do so yet.
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def update_process_cache(ref: Reference) -> None:
|
def update_process_cache(ref: Reference) -> None:
|
||||||
|
|
|
@ -2,6 +2,7 @@ import glob
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
|
from spiffworkflow_backend.models.db import db
|
||||||
from spiffworkflow_backend.models.process_model import ProcessModelInfo
|
from spiffworkflow_backend.models.process_model import ProcessModelInfo
|
||||||
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
||||||
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
||||||
|
@ -63,6 +64,7 @@ class ExampleDataLoader:
|
||||||
|
|
||||||
if len(files) == 0:
|
if len(files) == 0:
|
||||||
raise Exception(f"Could not find any files with file_glob: {file_glob}")
|
raise Exception(f"Could not find any files with file_glob: {file_glob}")
|
||||||
|
all_references = []
|
||||||
for file_path in files:
|
for file_path in files:
|
||||||
if os.path.isdir(file_path):
|
if os.path.isdir(file_path):
|
||||||
continue # Don't try to process sub directories
|
continue # Don't try to process sub directories
|
||||||
|
@ -74,13 +76,19 @@ class ExampleDataLoader:
|
||||||
try:
|
try:
|
||||||
file = open(file_path, "rb")
|
file = open(file_path, "rb")
|
||||||
data = file.read()
|
data = file.read()
|
||||||
file_info = SpecFileService.add_file(process_model_info=spec, file_name=filename, binary_data=data)
|
_, new_references = SpecFileService.update_file(
|
||||||
|
process_model_info=spec, file_name=filename, binary_data=data, update_process_cache_only=True
|
||||||
|
)
|
||||||
|
all_references += new_references
|
||||||
if is_primary:
|
if is_primary:
|
||||||
references = SpecFileService.get_references_for_file(file_info, spec)
|
# references = SpecFileService.get_references_for_file(file_info, spec)
|
||||||
spec.primary_process_id = references[0].identifier
|
spec.primary_process_id = new_references[0].identifier
|
||||||
spec.primary_file_name = filename
|
spec.primary_file_name = filename
|
||||||
ProcessModelService.save_process_model(spec)
|
ProcessModelService.save_process_model(spec)
|
||||||
finally:
|
finally:
|
||||||
if file:
|
if file:
|
||||||
file.close()
|
file.close()
|
||||||
|
for ref in all_references:
|
||||||
|
SpecFileService.update_caches_except_process(ref)
|
||||||
|
db.session.commit()
|
||||||
return spec
|
return spec
|
||||||
|
|
|
@ -663,6 +663,7 @@ class TestProcessApi(BaseTest):
|
||||||
"/v1.0/processes/callers/Level2",
|
"/v1.0/processes/callers/Level2",
|
||||||
headers=self.logged_in_headers(with_super_admin_user),
|
headers=self.logged_in_headers(with_super_admin_user),
|
||||||
)
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
assert response.json is not None
|
assert response.json is not None
|
||||||
# We should get 1 back, Level1 calls Level2
|
# We should get 1 back, Level1 calls Level2
|
||||||
assert len(response.json) == 1
|
assert len(response.json) == 1
|
||||||
|
|
|
@ -23,14 +23,6 @@ class TestProcessModelsController(BaseTest):
|
||||||
with_db_and_bpmn_file_cleanup: None,
|
with_db_and_bpmn_file_cleanup: None,
|
||||||
with_super_admin_user: UserModel,
|
with_super_admin_user: UserModel,
|
||||||
) -> None:
|
) -> None:
|
||||||
process_model = self.create_group_and_model_with_bpmn(
|
|
||||||
client=client,
|
|
||||||
user=with_super_admin_user,
|
|
||||||
process_group_id="caller",
|
|
||||||
process_model_id="caller",
|
|
||||||
bpmn_file_location="call_activity_same_directory",
|
|
||||||
bpmn_file_name="call_activity_test.bpmn",
|
|
||||||
)
|
|
||||||
self.create_group_and_model_with_bpmn(
|
self.create_group_and_model_with_bpmn(
|
||||||
client=client,
|
client=client,
|
||||||
user=with_super_admin_user,
|
user=with_super_admin_user,
|
||||||
|
@ -39,6 +31,14 @@ class TestProcessModelsController(BaseTest):
|
||||||
bpmn_file_location="call_activity_same_directory",
|
bpmn_file_location="call_activity_same_directory",
|
||||||
bpmn_file_name="callable_process.bpmn",
|
bpmn_file_name="callable_process.bpmn",
|
||||||
)
|
)
|
||||||
|
process_model = self.create_group_and_model_with_bpmn(
|
||||||
|
client=client,
|
||||||
|
user=with_super_admin_user,
|
||||||
|
process_group_id="caller",
|
||||||
|
process_model_id="caller",
|
||||||
|
bpmn_file_location="call_activity_same_directory",
|
||||||
|
bpmn_file_name="call_activity_test.bpmn",
|
||||||
|
)
|
||||||
|
|
||||||
user_one = self.create_user_with_permission(username="user_one", target_uri="/v1.0/process-groups/caller:*")
|
user_one = self.create_user_with_permission(username="user_one", target_uri="/v1.0/process-groups/caller:*")
|
||||||
self.add_permissions_to_user(
|
self.add_permissions_to_user(
|
||||||
|
|
|
@ -2,16 +2,21 @@ from collections.abc import Generator
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from flask.app import Flask
|
from flask.app import Flask
|
||||||
|
from spiffworkflow_backend.models.cache_generation import CacheGenerationModel
|
||||||
from spiffworkflow_backend.models.db import db
|
from spiffworkflow_backend.models.db import db
|
||||||
from spiffworkflow_backend.models.process_caller import ProcessCallerCacheModel
|
from spiffworkflow_backend.models.process_caller_relationship import CalledProcessNotFoundError
|
||||||
|
from spiffworkflow_backend.models.process_caller_relationship import CallingProcessNotFoundError
|
||||||
|
from spiffworkflow_backend.models.process_caller_relationship import ProcessCallerRelationshipModel
|
||||||
|
from spiffworkflow_backend.models.reference_cache import ReferenceCacheModel
|
||||||
from spiffworkflow_backend.services.process_caller_service import ProcessCallerService
|
from spiffworkflow_backend.services.process_caller_service import ProcessCallerService
|
||||||
|
from spiffworkflow_backend.services.reference_cache_service import ReferenceCacheService
|
||||||
|
|
||||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def with_clean_cache(app: Flask) -> Generator[None, None, None]:
|
def with_clean_cache(app: Flask) -> Generator[None, None, None]:
|
||||||
db.session.query(ProcessCallerCacheModel).delete()
|
ProcessCallerRelationshipModel.query.delete()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
@ -21,25 +26,50 @@ def with_no_process_callers(with_clean_cache: None) -> Generator[None, None, Non
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
def create_reference_cache(identifier: str) -> ReferenceCacheModel:
|
||||||
|
ref_cache = ReferenceCacheModel.from_params(
|
||||||
|
identifier=identifier,
|
||||||
|
type="process",
|
||||||
|
display_name=identifier,
|
||||||
|
file_name=identifier,
|
||||||
|
relative_location=identifier,
|
||||||
|
use_current_cache_generation=True,
|
||||||
|
)
|
||||||
|
db.session.add(ref_cache)
|
||||||
|
return ref_cache
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def with_single_process_caller(with_clean_cache: None) -> Generator[None, None, None]:
|
def with_single_process_caller(with_clean_cache: None) -> Generator[None, None, None]:
|
||||||
db.session.add(ProcessCallerCacheModel(process_identifier="called_once", calling_process_identifier="one_caller"))
|
ReferenceCacheService.add_new_generation({})
|
||||||
|
cache_generation = CacheGenerationModel(cache_table="reference_cache")
|
||||||
|
db.session.add(cache_generation)
|
||||||
|
db.session.commit()
|
||||||
|
called_cache = create_reference_cache("called_once")
|
||||||
|
calling_cache = create_reference_cache("calling_cache")
|
||||||
|
db.session.add(called_cache)
|
||||||
|
db.session.add(calling_cache)
|
||||||
|
db.session.commit()
|
||||||
|
ProcessCallerService.add_caller(calling_cache.identifier, [called_cache.identifier])
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def with_multiple_process_callers(with_clean_cache: None) -> Generator[None, None, None]:
|
def with_multiple_process_callers(with_clean_cache: None) -> Generator[None, None, None]:
|
||||||
db.session.add(ProcessCallerCacheModel(process_identifier="called_many", calling_process_identifier="one_caller"))
|
ReferenceCacheService.add_new_generation({})
|
||||||
db.session.add(ProcessCallerCacheModel(process_identifier="called_many", calling_process_identifier="two_caller"))
|
called_cache = create_reference_cache("called_many")
|
||||||
db.session.add(ProcessCallerCacheModel(process_identifier="called_many", calling_process_identifier="three_caller"))
|
|
||||||
|
for ref_identifier in ["one_caller", "two_caller", "three_caller"]:
|
||||||
|
calling_cache = create_reference_cache(ref_identifier)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
ProcessCallerService.add_caller(calling_cache.identifier, [called_cache.identifier])
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
class TestProcessCallerService(BaseTest):
|
class TestProcessCallerService(BaseTest):
|
||||||
"""Infer from class name."""
|
|
||||||
|
|
||||||
def test_has_zero_count_when_empty(self, with_no_process_callers: None) -> None:
|
def test_has_zero_count_when_empty(self, with_no_process_callers: None) -> None:
|
||||||
assert ProcessCallerService.count() == 0
|
assert ProcessCallerService.count() == 0
|
||||||
|
|
||||||
|
@ -55,72 +85,45 @@ class TestProcessCallerService(BaseTest):
|
||||||
assert ProcessCallerService.count() == 0
|
assert ProcessCallerService.count() == 0
|
||||||
|
|
||||||
def test_can_clear_the_cache_for_process_id(self, with_single_process_caller: None) -> None:
|
def test_can_clear_the_cache_for_process_id(self, with_single_process_caller: None) -> None:
|
||||||
ProcessCallerService.clear_cache_for_process_ids(["called_once"])
|
assert ProcessCallerService.count() != 0
|
||||||
|
reference_cache = ReferenceCacheModel.basic_query().filter_by(identifier="called_once").first()
|
||||||
|
assert reference_cache is not None
|
||||||
|
ProcessCallerService.clear_cache_for_process_ids([reference_cache.id])
|
||||||
assert ProcessCallerService.count() == 0
|
assert ProcessCallerService.count() == 0
|
||||||
|
|
||||||
def test_can_clear_the_cache_for_calling_process_id(self, with_multiple_process_callers: None) -> None:
|
def test_can_clear_the_cache_for_calling_process_id(self, with_multiple_process_callers: None) -> None:
|
||||||
ProcessCallerService.clear_cache_for_process_ids(["one_caller"])
|
reference_cache = ReferenceCacheModel.basic_query().filter_by(identifier="one_caller").first()
|
||||||
|
assert reference_cache is not None
|
||||||
|
assert ProcessCallerService.count() == 3
|
||||||
|
ProcessCallerService.clear_cache_for_process_ids([reference_cache.id])
|
||||||
assert ProcessCallerService.count() == 2
|
assert ProcessCallerService.count() == 2
|
||||||
|
|
||||||
def test_can_clear_the_cache_for_callee_caller_process_id(
|
def test_can_clear_the_cache_for_callee_caller_process_id(
|
||||||
self, with_single_process_caller: None, with_multiple_process_callers: None
|
self, with_single_process_caller: None, with_multiple_process_callers: None
|
||||||
) -> None:
|
) -> None:
|
||||||
ProcessCallerService.clear_cache_for_process_ids(["one_caller"])
|
reference_cache = ReferenceCacheModel.basic_query().filter_by(identifier="one_caller").first()
|
||||||
assert ProcessCallerService.count() == 2
|
assert reference_cache is not None
|
||||||
|
assert ProcessCallerService.count() == 4
|
||||||
|
ProcessCallerService.clear_cache_for_process_ids([reference_cache.id])
|
||||||
|
assert ProcessCallerService.count() == 3
|
||||||
|
|
||||||
def test_can_clear_the_cache_for_process_id_and_leave_other_process_ids_alone(
|
def test_can_clear_the_cache_for_process_id_and_leave_other_process_ids_alone(
|
||||||
self,
|
self,
|
||||||
with_single_process_caller: None,
|
with_single_process_caller: None,
|
||||||
with_multiple_process_callers: None,
|
with_multiple_process_callers: None,
|
||||||
) -> None:
|
) -> None:
|
||||||
ProcessCallerService.clear_cache_for_process_ids(["called_many"])
|
reference_cache = ReferenceCacheModel.basic_query().filter_by(identifier="called_many").first()
|
||||||
|
assert reference_cache is not None
|
||||||
|
ProcessCallerService.clear_cache_for_process_ids([reference_cache.id])
|
||||||
assert ProcessCallerService.count() == 1
|
assert ProcessCallerService.count() == 1
|
||||||
|
|
||||||
def test_can_clear_the_cache_for_process_id_when_it_doesnt_exist(
|
def test_raises_if_calling_reference_cache_does_not_exist(self, with_no_process_callers: None) -> None:
|
||||||
self,
|
with pytest.raises(CallingProcessNotFoundError):
|
||||||
with_multiple_process_callers: None,
|
ProcessCallerService.add_caller("DNE", [])
|
||||||
) -> None:
|
|
||||||
ProcessCallerService.clear_cache_for_process_ids(["garbage"])
|
|
||||||
assert ProcessCallerService.count() == 3
|
|
||||||
|
|
||||||
def test_no_records_added_if_calling_process_ids_is_empty(self, with_no_process_callers: None) -> None:
|
|
||||||
ProcessCallerService.add_caller("bob", [])
|
|
||||||
assert ProcessCallerService.count() == 0
|
assert ProcessCallerService.count() == 0
|
||||||
|
|
||||||
def test_can_add_caller_for_new_process(self, with_no_process_callers: None) -> None:
|
def test_raises_if_called_reference_cache_does_not_exist(self, with_single_process_caller: None) -> None:
|
||||||
ProcessCallerService.add_caller("bob", ["new_caller"])
|
db.session.commit()
|
||||||
assert ProcessCallerService.count() == 1
|
with pytest.raises(CalledProcessNotFoundError):
|
||||||
|
ProcessCallerService.add_caller("calling_cache", ["DNE"])
|
||||||
def test_can_many_callers_for_new_process(self, with_no_process_callers: None) -> None:
|
assert ProcessCallerService.count() == 0
|
||||||
ProcessCallerService.add_caller("bob", ["new_caller", "another_new_caller"])
|
|
||||||
assert ProcessCallerService.count() == 2
|
|
||||||
|
|
||||||
def test_can_add_caller_for_existing_process(self, with_multiple_process_callers: None) -> None:
|
|
||||||
ProcessCallerService.add_caller("called_many", ["new_caller"])
|
|
||||||
assert ProcessCallerService.count() == 4
|
|
||||||
|
|
||||||
def test_can_add_many_callers_for_existing_process(self, with_multiple_process_callers: None) -> None:
|
|
||||||
ProcessCallerService.add_caller("called_many", ["new_caller", "another_new_caller"])
|
|
||||||
assert ProcessCallerService.count() == 5
|
|
||||||
|
|
||||||
def test_can_track_duplicate_callers(self, with_no_process_callers: None) -> None:
|
|
||||||
ProcessCallerService.add_caller("bob", ["new_caller", "new_caller"])
|
|
||||||
assert ProcessCallerService.count() == 2
|
|
||||||
|
|
||||||
def test_can_return_no_callers_when_no_records(self, with_no_process_callers: None) -> None:
|
|
||||||
assert ProcessCallerService.callers(["bob"]) == []
|
|
||||||
|
|
||||||
def test_can_return_no_callers_when_process_id_is_unknown(self, with_multiple_process_callers: None) -> None:
|
|
||||||
assert ProcessCallerService.callers(["bob"]) == []
|
|
||||||
|
|
||||||
def test_can_return_single_caller(self, with_single_process_caller: None) -> None:
|
|
||||||
assert ProcessCallerService.callers(["called_once"]) == ["one_caller"]
|
|
||||||
|
|
||||||
def test_can_return_mulitple_callers(self, with_multiple_process_callers: None) -> None:
|
|
||||||
callers = sorted(ProcessCallerService.callers(["called_many"]))
|
|
||||||
assert callers == ["one_caller", "three_caller", "two_caller"]
|
|
||||||
|
|
||||||
def test_can_return_single_caller_when_there_are_other_process_ids(
|
|
||||||
self, with_single_process_caller: None, with_multiple_process_callers: None
|
|
||||||
) -> None:
|
|
||||||
assert ProcessCallerService.callers(["called_once"]) == ["one_caller"]
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import re
|
||||||
|
|
||||||
from flask.app import Flask
|
from flask.app import Flask
|
||||||
from spiffworkflow_backend.models.db import db
|
from spiffworkflow_backend.models.db import db
|
||||||
|
from spiffworkflow_backend.models.process_caller_relationship import ProcessCallerRelationshipModel
|
||||||
from spiffworkflow_backend.models.process_instance_metadata import ProcessInstanceMetadataModel
|
from spiffworkflow_backend.models.process_instance_metadata import ProcessInstanceMetadataModel
|
||||||
from spiffworkflow_backend.models.process_model import ProcessModelInfo
|
from spiffworkflow_backend.models.process_model import ProcessModelInfo
|
||||||
from spiffworkflow_backend.models.reference_cache import ReferenceCacheModel
|
from spiffworkflow_backend.models.reference_cache import ReferenceCacheModel
|
||||||
|
@ -39,16 +40,10 @@ class TestProcessModel(BaseTest):
|
||||||
app: Flask,
|
app: Flask,
|
||||||
with_db_and_bpmn_file_cleanup: None,
|
with_db_and_bpmn_file_cleanup: None,
|
||||||
) -> None:
|
) -> None:
|
||||||
process_model = load_test_spec(
|
|
||||||
"test_group/call_activity_nested",
|
|
||||||
process_model_source_directory="call_activity_nested",
|
|
||||||
bpmn_file_name="call_activity_nested",
|
|
||||||
)
|
|
||||||
|
|
||||||
bpmn_file_names = [
|
bpmn_file_names = [
|
||||||
|
"call_activity_level_3",
|
||||||
"call_activity_level_2b",
|
"call_activity_level_2b",
|
||||||
"call_activity_level_2",
|
"call_activity_level_2",
|
||||||
"call_activity_level_3",
|
|
||||||
]
|
]
|
||||||
for bpmn_file_name in bpmn_file_names:
|
for bpmn_file_name in bpmn_file_names:
|
||||||
load_test_spec(
|
load_test_spec(
|
||||||
|
@ -56,6 +51,11 @@ class TestProcessModel(BaseTest):
|
||||||
process_model_source_directory="call_activity_nested",
|
process_model_source_directory="call_activity_nested",
|
||||||
bpmn_file_name=bpmn_file_name,
|
bpmn_file_name=bpmn_file_name,
|
||||||
)
|
)
|
||||||
|
process_model = load_test_spec(
|
||||||
|
"test_group/call_activity_nested",
|
||||||
|
process_model_source_directory="call_activity_nested",
|
||||||
|
bpmn_file_name="call_activity_nested",
|
||||||
|
)
|
||||||
process_instance = self.create_process_instance_from_process_model(process_model)
|
process_instance = self.create_process_instance_from_process_model(process_model)
|
||||||
processor = ProcessInstanceProcessor(process_instance)
|
processor = ProcessInstanceProcessor(process_instance)
|
||||||
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
|
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
|
||||||
|
@ -66,16 +66,10 @@ class TestProcessModel(BaseTest):
|
||||||
app: Flask,
|
app: Flask,
|
||||||
with_db_and_bpmn_file_cleanup: None,
|
with_db_and_bpmn_file_cleanup: None,
|
||||||
) -> None:
|
) -> None:
|
||||||
process_model = load_test_spec(
|
|
||||||
"test_group/call_activity_nested",
|
|
||||||
process_model_source_directory="call_activity_nested",
|
|
||||||
bpmn_file_name="call_activity_nested",
|
|
||||||
)
|
|
||||||
|
|
||||||
bpmn_file_names = [
|
bpmn_file_names = [
|
||||||
|
"call_activity_level_3",
|
||||||
"call_activity_level_2b",
|
"call_activity_level_2b",
|
||||||
"call_activity_level_2",
|
"call_activity_level_2",
|
||||||
"call_activity_level_3",
|
|
||||||
]
|
]
|
||||||
for bpmn_file_name in bpmn_file_names:
|
for bpmn_file_name in bpmn_file_names:
|
||||||
load_test_spec(
|
load_test_spec(
|
||||||
|
@ -83,10 +77,16 @@ class TestProcessModel(BaseTest):
|
||||||
process_model_source_directory="call_activity_nested",
|
process_model_source_directory="call_activity_nested",
|
||||||
bpmn_file_name=bpmn_file_name,
|
bpmn_file_name=bpmn_file_name,
|
||||||
)
|
)
|
||||||
|
process_model = load_test_spec(
|
||||||
|
"test_group/call_activity_nested",
|
||||||
|
process_model_source_directory="call_activity_nested",
|
||||||
|
bpmn_file_name="call_activity_nested",
|
||||||
|
)
|
||||||
process_instance = self.create_process_instance_from_process_model(process_model)
|
process_instance = self.create_process_instance_from_process_model(process_model)
|
||||||
|
|
||||||
# delete all of the id lookup items to force to processor to find the correct
|
# delete all of the id lookup items to force to processor to find the correct
|
||||||
# process model when running the process
|
# process model when running the process
|
||||||
|
db.session.query(ProcessCallerRelationshipModel).delete()
|
||||||
db.session.query(ReferenceCacheModel).delete()
|
db.session.query(ReferenceCacheModel).delete()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
processor = ProcessInstanceProcessor(process_instance)
|
processor = ProcessInstanceProcessor(process_instance)
|
||||||
|
|
|
@ -9,6 +9,7 @@ from spiffworkflow_backend.models.cache_generation import CacheGenerationModel
|
||||||
from spiffworkflow_backend.models.db import db
|
from spiffworkflow_backend.models.db import db
|
||||||
from spiffworkflow_backend.models.reference_cache import ReferenceCacheModel
|
from spiffworkflow_backend.models.reference_cache import ReferenceCacheModel
|
||||||
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
||||||
|
from spiffworkflow_backend.services.reference_cache_service import ReferenceCacheService
|
||||||
from spiffworkflow_backend.services.spec_file_service import ProcessModelFileInvalidError
|
from spiffworkflow_backend.services.spec_file_service import ProcessModelFileInvalidError
|
||||||
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
||||||
|
|
||||||
|
@ -33,10 +34,9 @@ class TestSpecFileService(BaseTest):
|
||||||
) -> None:
|
) -> None:
|
||||||
load_test_spec(
|
load_test_spec(
|
||||||
process_model_id=self.process_model_id,
|
process_model_id=self.process_model_id,
|
||||||
bpmn_file_name=self.bpmn_file_name,
|
|
||||||
process_model_source_directory="call_activity_nested",
|
process_model_source_directory="call_activity_nested",
|
||||||
)
|
)
|
||||||
bpmn_process_id_lookups = ReferenceCacheModel.basic_query().all()
|
bpmn_process_id_lookups = ReferenceCacheService.get_reference_cache_entries_calling_process(["Level2"])
|
||||||
assert len(bpmn_process_id_lookups) == 1
|
assert len(bpmn_process_id_lookups) == 1
|
||||||
assert bpmn_process_id_lookups[0].identifier == "Level1"
|
assert bpmn_process_id_lookups[0].identifier == "Level1"
|
||||||
assert bpmn_process_id_lookups[0].relative_path() == self.call_activity_nested_relative_file_path
|
assert bpmn_process_id_lookups[0].relative_path() == self.call_activity_nested_relative_file_path
|
||||||
|
@ -50,10 +50,9 @@ class TestSpecFileService(BaseTest):
|
||||||
bpmn_process_identifier = "Level1"
|
bpmn_process_identifier = "Level1"
|
||||||
load_test_spec(
|
load_test_spec(
|
||||||
process_model_id="call_activity_duplicate",
|
process_model_id="call_activity_duplicate",
|
||||||
bpmn_file_name=self.bpmn_file_name,
|
process_model_source_directory="call_activity_nested",
|
||||||
process_model_source_directory="call_activity_duplicate",
|
|
||||||
)
|
)
|
||||||
bpmn_process_id_lookups = ReferenceCacheModel.basic_query().all()
|
bpmn_process_id_lookups = ReferenceCacheService.get_reference_cache_entries_calling_process(["Level2"])
|
||||||
assert len(bpmn_process_id_lookups) == 1
|
assert len(bpmn_process_id_lookups) == 1
|
||||||
assert bpmn_process_id_lookups[0].identifier == bpmn_process_identifier
|
assert bpmn_process_id_lookups[0].identifier == bpmn_process_identifier
|
||||||
with pytest.raises(ProcessModelFileInvalidError) as exception:
|
with pytest.raises(ProcessModelFileInvalidError) as exception:
|
||||||
|
@ -88,11 +87,10 @@ class TestSpecFileService(BaseTest):
|
||||||
|
|
||||||
load_test_spec(
|
load_test_spec(
|
||||||
process_model_id=self.process_model_id,
|
process_model_id=self.process_model_id,
|
||||||
bpmn_file_name=self.bpmn_file_name,
|
|
||||||
process_model_source_directory="call_activity_nested",
|
process_model_source_directory="call_activity_nested",
|
||||||
)
|
)
|
||||||
|
|
||||||
bpmn_process_id_lookups = ReferenceCacheModel.basic_query().all()
|
bpmn_process_id_lookups = ReferenceCacheService.get_reference_cache_entries_calling_process(["Level2"])
|
||||||
assert len(bpmn_process_id_lookups) == 1
|
assert len(bpmn_process_id_lookups) == 1
|
||||||
assert bpmn_process_id_lookups[0].identifier == bpmn_process_identifier
|
assert bpmn_process_id_lookups[0].identifier == bpmn_process_identifier
|
||||||
assert bpmn_process_id_lookups[0].relative_path() == self.call_activity_nested_relative_file_path
|
assert bpmn_process_id_lookups[0].relative_path() == self.call_activity_nested_relative_file_path
|
||||||
|
@ -134,6 +132,7 @@ class TestSpecFileService(BaseTest):
|
||||||
) -> None:
|
) -> None:
|
||||||
"""When a BPMN processes identifier is changed in a file, the old id is removed from the cache."""
|
"""When a BPMN processes identifier is changed in a file, the old id is removed from the cache."""
|
||||||
old_identifier = "ye_old_identifier"
|
old_identifier = "ye_old_identifier"
|
||||||
|
new_identifier = "Level1"
|
||||||
process_id_lookup = ReferenceCacheModel.from_params(
|
process_id_lookup = ReferenceCacheModel.from_params(
|
||||||
identifier=old_identifier,
|
identifier=old_identifier,
|
||||||
display_name="WHO CARES",
|
display_name="WHO CARES",
|
||||||
|
@ -147,15 +146,22 @@ class TestSpecFileService(BaseTest):
|
||||||
|
|
||||||
load_test_spec(
|
load_test_spec(
|
||||||
process_model_id=self.process_model_id,
|
process_model_id=self.process_model_id,
|
||||||
bpmn_file_name=self.bpmn_file_name,
|
|
||||||
process_model_source_directory="call_activity_nested",
|
process_model_source_directory="call_activity_nested",
|
||||||
)
|
)
|
||||||
|
|
||||||
bpmn_process_id_lookups = ReferenceCacheModel.basic_query().all()
|
old_reference_count = ReferenceCacheModel.basic_query().filter_by(identifier=old_identifier).count()
|
||||||
assert len(bpmn_process_id_lookups) == 1
|
assert old_reference_count == 0
|
||||||
assert bpmn_process_id_lookups[0].identifier != old_identifier
|
current_references = (
|
||||||
assert bpmn_process_id_lookups[0].identifier == "Level1"
|
ReferenceCacheModel.basic_query()
|
||||||
assert bpmn_process_id_lookups[0].relative_path() == self.call_activity_nested_relative_file_path
|
.filter_by(
|
||||||
|
relative_location=self.process_model_id,
|
||||||
|
file_name=self.bpmn_file_name,
|
||||||
|
)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
assert len(current_references) == 1
|
||||||
|
assert current_references[0].identifier == new_identifier
|
||||||
|
assert current_references[0].relative_path() == self.call_activity_nested_relative_file_path
|
||||||
|
|
||||||
def test_load_reference_information(
|
def test_load_reference_information(
|
||||||
self,
|
self,
|
||||||
|
@ -223,10 +229,9 @@ class TestSpecFileService(BaseTest):
|
||||||
|
|
||||||
load_test_spec(
|
load_test_spec(
|
||||||
process_model_id=self.process_model_id,
|
process_model_id=self.process_model_id,
|
||||||
bpmn_file_name=self.bpmn_file_name,
|
|
||||||
process_model_source_directory="call_activity_nested",
|
process_model_source_directory="call_activity_nested",
|
||||||
)
|
)
|
||||||
bpmn_process_id_lookups = ReferenceCacheModel.basic_query().all()
|
bpmn_process_id_lookups = ReferenceCacheService.get_reference_cache_entries_calling_process(["Level2"])
|
||||||
assert len(bpmn_process_id_lookups) == 1
|
assert len(bpmn_process_id_lookups) == 1
|
||||||
assert bpmn_process_id_lookups[0].identifier == "Level1"
|
assert bpmn_process_id_lookups[0].identifier == "Level1"
|
||||||
assert bpmn_process_id_lookups[0].relative_path() == self.call_activity_nested_relative_file_path
|
assert bpmn_process_id_lookups[0].relative_path() == self.call_activity_nested_relative_file_path
|
||||||
|
@ -238,10 +243,9 @@ class TestSpecFileService(BaseTest):
|
||||||
# make sure it doesn't add a new entry to the cache
|
# make sure it doesn't add a new entry to the cache
|
||||||
load_test_spec(
|
load_test_spec(
|
||||||
process_model_id=self.process_model_id,
|
process_model_id=self.process_model_id,
|
||||||
bpmn_file_name=self.bpmn_file_name,
|
|
||||||
process_model_source_directory="call_activity_nested",
|
process_model_source_directory="call_activity_nested",
|
||||||
)
|
)
|
||||||
bpmn_process_id_lookups = ReferenceCacheModel.basic_query().all()
|
bpmn_process_id_lookups = ReferenceCacheService.get_reference_cache_entries_calling_process(["Level2"])
|
||||||
assert len(bpmn_process_id_lookups) == 1
|
assert len(bpmn_process_id_lookups) == 1
|
||||||
assert bpmn_process_id_lookups[0].identifier == "Level1"
|
assert bpmn_process_id_lookups[0].identifier == "Level1"
|
||||||
assert bpmn_process_id_lookups[0].relative_path() == self.call_activity_nested_relative_file_path
|
assert bpmn_process_id_lookups[0].relative_path() == self.call_activity_nested_relative_file_path
|
||||||
|
@ -261,10 +265,9 @@ class TestSpecFileService(BaseTest):
|
||||||
|
|
||||||
load_test_spec(
|
load_test_spec(
|
||||||
process_model_id=self.process_model_id,
|
process_model_id=self.process_model_id,
|
||||||
bpmn_file_name=self.bpmn_file_name,
|
|
||||||
process_model_source_directory="call_activity_nested",
|
process_model_source_directory="call_activity_nested",
|
||||||
)
|
)
|
||||||
bpmn_process_id_lookups = ReferenceCacheModel.basic_query().all()
|
bpmn_process_id_lookups = ReferenceCacheService.get_reference_cache_entries_calling_process(["Level2"])
|
||||||
assert len(bpmn_process_id_lookups) == 1
|
assert len(bpmn_process_id_lookups) == 1
|
||||||
assert bpmn_process_id_lookups[0].identifier == "Level1"
|
assert bpmn_process_id_lookups[0].identifier == "Level1"
|
||||||
assert bpmn_process_id_lookups[0].generation_id == current_cache_generation.id
|
assert bpmn_process_id_lookups[0].generation_id == current_cache_generation.id
|
||||||
|
|
|
@ -16,16 +16,10 @@ class TestTaskService(BaseTest):
|
||||||
app: Flask,
|
app: Flask,
|
||||||
with_db_and_bpmn_file_cleanup: None,
|
with_db_and_bpmn_file_cleanup: None,
|
||||||
) -> None:
|
) -> None:
|
||||||
process_model = load_test_spec(
|
|
||||||
"test_group/call_activity_nested",
|
|
||||||
process_model_source_directory="call_activity_nested",
|
|
||||||
bpmn_file_name="call_activity_nested",
|
|
||||||
)
|
|
||||||
|
|
||||||
bpmn_file_names = [
|
bpmn_file_names = [
|
||||||
|
"call_activity_level_3",
|
||||||
"call_activity_level_2b",
|
"call_activity_level_2b",
|
||||||
"call_activity_level_2",
|
"call_activity_level_2",
|
||||||
"call_activity_level_3",
|
|
||||||
]
|
]
|
||||||
for bpmn_file_name in bpmn_file_names:
|
for bpmn_file_name in bpmn_file_names:
|
||||||
load_test_spec(
|
load_test_spec(
|
||||||
|
@ -33,6 +27,11 @@ class TestTaskService(BaseTest):
|
||||||
process_model_source_directory="call_activity_nested",
|
process_model_source_directory="call_activity_nested",
|
||||||
bpmn_file_name=bpmn_file_name,
|
bpmn_file_name=bpmn_file_name,
|
||||||
)
|
)
|
||||||
|
process_model = load_test_spec(
|
||||||
|
"test_group/call_activity_nested",
|
||||||
|
process_model_source_directory="call_activity_nested",
|
||||||
|
bpmn_file_name="call_activity_nested",
|
||||||
|
)
|
||||||
process_instance = self.create_process_instance_from_process_model(process_model)
|
process_instance = self.create_process_instance_from_process_model(process_model)
|
||||||
processor = ProcessInstanceProcessor(process_instance)
|
processor = ProcessInstanceProcessor(process_instance)
|
||||||
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
|
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
|
||||||
|
@ -63,16 +62,10 @@ class TestTaskService(BaseTest):
|
||||||
app: Flask,
|
app: Flask,
|
||||||
with_db_and_bpmn_file_cleanup: None,
|
with_db_and_bpmn_file_cleanup: None,
|
||||||
) -> None:
|
) -> None:
|
||||||
process_model = load_test_spec(
|
|
||||||
"test_group/call_activity_nested",
|
|
||||||
process_model_source_directory="call_activity_nested",
|
|
||||||
bpmn_file_name="call_activity_nested",
|
|
||||||
)
|
|
||||||
|
|
||||||
bpmn_file_names = [
|
bpmn_file_names = [
|
||||||
|
"call_activity_level_3",
|
||||||
"call_activity_level_2b",
|
"call_activity_level_2b",
|
||||||
"call_activity_level_2",
|
"call_activity_level_2",
|
||||||
"call_activity_level_3",
|
|
||||||
]
|
]
|
||||||
for bpmn_file_name in bpmn_file_names:
|
for bpmn_file_name in bpmn_file_names:
|
||||||
load_test_spec(
|
load_test_spec(
|
||||||
|
@ -80,6 +73,11 @@ class TestTaskService(BaseTest):
|
||||||
process_model_source_directory="call_activity_nested",
|
process_model_source_directory="call_activity_nested",
|
||||||
bpmn_file_name=bpmn_file_name,
|
bpmn_file_name=bpmn_file_name,
|
||||||
)
|
)
|
||||||
|
process_model = load_test_spec(
|
||||||
|
"test_group/call_activity_nested",
|
||||||
|
process_model_source_directory="call_activity_nested",
|
||||||
|
bpmn_file_name="call_activity_nested",
|
||||||
|
)
|
||||||
process_instance = self.create_process_instance_from_process_model(process_model)
|
process_instance = self.create_process_instance_from_process_model(process_model)
|
||||||
processor = ProcessInstanceProcessor(process_instance)
|
processor = ProcessInstanceProcessor(process_instance)
|
||||||
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
|
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
|
||||||
|
@ -118,16 +116,10 @@ class TestTaskService(BaseTest):
|
||||||
app: Flask,
|
app: Flask,
|
||||||
with_db_and_bpmn_file_cleanup: None,
|
with_db_and_bpmn_file_cleanup: None,
|
||||||
) -> None:
|
) -> None:
|
||||||
process_model = load_test_spec(
|
|
||||||
"test_group/call_activity_nested",
|
|
||||||
process_model_source_directory="call_activity_nested",
|
|
||||||
bpmn_file_name="call_activity_nested",
|
|
||||||
)
|
|
||||||
|
|
||||||
bpmn_file_names = [
|
bpmn_file_names = [
|
||||||
|
"call_activity_level_3",
|
||||||
"call_activity_level_2b",
|
"call_activity_level_2b",
|
||||||
"call_activity_level_2",
|
"call_activity_level_2",
|
||||||
"call_activity_level_3",
|
|
||||||
]
|
]
|
||||||
for bpmn_file_name in bpmn_file_names:
|
for bpmn_file_name in bpmn_file_names:
|
||||||
load_test_spec(
|
load_test_spec(
|
||||||
|
@ -135,6 +127,11 @@ class TestTaskService(BaseTest):
|
||||||
process_model_source_directory="call_activity_nested",
|
process_model_source_directory="call_activity_nested",
|
||||||
bpmn_file_name=bpmn_file_name,
|
bpmn_file_name=bpmn_file_name,
|
||||||
)
|
)
|
||||||
|
process_model = load_test_spec(
|
||||||
|
"test_group/call_activity_nested",
|
||||||
|
process_model_source_directory="call_activity_nested",
|
||||||
|
bpmn_file_name="call_activity_nested",
|
||||||
|
)
|
||||||
process_instance = self.create_process_instance_from_process_model(process_model)
|
process_instance = self.create_process_instance_from_process_model(process_model)
|
||||||
processor = ProcessInstanceProcessor(process_instance)
|
processor = ProcessInstanceProcessor(process_instance)
|
||||||
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
|
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
|
||||||
|
|
Loading…
Reference in New Issue