Merge branch 'dev' into partial_testing

This commit is contained in:
Mike Cullerton 2021-06-30 16:13:31 -04:00 committed by GitHub
commit 98d641f54d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 141 additions and 30 deletions

View File

@ -47,6 +47,7 @@ xlrd = "*"
xlsxwriter = "*"
pygithub = "*"
python-levenshtein = "*"
apscheduler = "*"
[requires]
python_version = "3.8"

45
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "62845ef7722714110fce095f525ffd73ba29eadb886b1fb8d6a54ae41417e34b"
"sha256": "2d74273fabb4ccda79f76e59ed2595d68a72eaa4a56bd4e04d0e7fbd9489039e"
},
"pipfile-spec": 6,
"requires": {
@ -46,6 +46,14 @@
],
"version": "==9.0.1"
},
"apscheduler": {
"hashes": [
"sha256:1cab7f2521e107d07127b042155b632b7a1cd5e02c34be5a28ff62f77c900c6a",
"sha256:c06cc796d5bb9eb3c4f77727f6223476eb67749e7eea074d1587550702a7fbe3"
],
"index": "pypi",
"version": "==3.7.0"
},
"attrs": {
"hashes": [
"sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
@ -706,7 +714,6 @@
"sha256:eda2829af498946c59d8585a9fd74da3f810866e05f8df03a86f70079c7531dd",
"sha256:fd0a359c1c17f00cb37de2969984a74320970e0ceef4808c32e00773b06649d9"
],
"markers": "python_version >= '3.7'",
"version": "==1.21.0"
},
"openapi-schema-validator": {
@ -767,14 +774,6 @@
"index": "pypi",
"version": "==1.2.5"
},
"prompt-toolkit": {
"hashes": [
"sha256:08360ee3a3148bdb5163621709ee322ec34fc4375099afa4bbf751e9b7b7fa4f",
"sha256:7089d8d2938043508aa9420ec18ce0922885304cddae87fb96eebca942299f88"
],
"markers": "python_full_version >= '3.6.1'",
"version": "==3.0.19"
},
"psycopg2-binary": {
"hashes": [
"sha256:0b7dae87f0b729922e06f85f667de7bf16455d411971b2043bbd9577af9d1975",
@ -916,17 +915,8 @@
"sha256:f3ef98d7b76da5eb19c37fda834d50262ff9167c65658d1d8f974d2e4d90676b",
"sha256:f4c8cabb46ff8e5d61f56a037974228e978f26bfefce4f61a4b1ac0ba7a2ab72"
],
"markers": "python_version >= '3.6'",
"version": "==0.18.0"
},
"python-box": {
"hashes": [
"sha256:4ed4ef5d34de505a65c01e3f1911de8cdb29484fcae0c035141dce535c6c194a",
"sha256:f2a531f9f5bbef078c175fad6abb31e9b59d40d121ea79993197e6bb221c6be6"
],
"markers": "python_version >= '3.6'",
"version": "==5.3.0"
},
"python-dateutil": {
"hashes": [
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
@ -1143,7 +1133,6 @@
"sha256:ff38ecf89c69a531a7326c2dae71982edfe2f805f3c016cdc5bfd1a04ebf80cb",
"sha256:ff8bebc7a9d297dff2003460e01db2c20c63818b45fb19170f388b1a72fe5a14"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
"version": "==1.4.20"
},
"swagger-ui-bundle": {
@ -1154,22 +1143,20 @@
"index": "pypi",
"version": "==0.0.8"
},
"tzlocal": {
"hashes": [
"sha256:643c97c5294aedc737780a49d9df30889321cbe1204eac2c2ec6134035a92e44",
"sha256:e2cb6c6b5b604af38597403e9852872d7f534962ae2954c7f35efcb1ccacf4a4"
],
"version": "==2.1"
},
"urllib3": {
"hashes": [
"sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4",
"sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
"version": "==1.26.6"
},
"vine": {
"hashes": [
"sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30",
"sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e"
],
"markers": "python_version >= '3.6'",
"version": "==5.0.0"
},
"waitress": {
"hashes": [
"sha256:29af5a53e9fb4e158f525367678b50053808ca6c21ba585754c77d790008c746",

View File

@ -12,6 +12,8 @@ from flask_mail import Mail
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
from sentry_sdk.integrations.flask import FlaskIntegration
from apscheduler.schedulers.background import BackgroundScheduler
logging.basicConfig(level=logging.INFO)
@ -33,6 +35,7 @@ db = SQLAlchemy(app)
session = db.session
""":type: sqlalchemy.orm.Session"""
scheduler = BackgroundScheduler()
# Mail settings
mail = Mail(app)
@ -43,9 +46,18 @@ ma = Marshmallow(app)
from crc import models
from crc import api
from crc.api import admin
from crc.services.workflow_service import WorkflowService
connexion_app.add_api('api.yml', base_path='/v1.0')
# needed function to avoid circular import
def process_waiting_tasks():
with app.app_context():
WorkflowService.do_waiting()
scheduler.add_job(process_waiting_tasks,'interval',minutes=5)
scheduler.start()
# Convert list of allowed origins to list of regexes
origins_re = [r"^https?:\/\/%s(.*)" % o.replace('.', '\.') for o in app.config['CORS_ALLOW_ORIGINS']]

View File

@ -366,6 +366,7 @@ class WorkflowProcessor(object):
def do_engine_steps(self, exit_at = None):
try:
self.bpmn_workflow.refresh_waiting_tasks()
self.bpmn_workflow.do_engine_steps(exit_at = exit_at)
except WorkflowTaskExecException as we:
raise ApiError.from_task("task_error", str(we), we.task)

View File

@ -94,6 +94,18 @@ class WorkflowService(object):
db.session.commit()
@staticmethod
def do_waiting():
records = db.session.query(WorkflowModel).filter(WorkflowModel.status==WorkflowStatus.waiting).all()
for workflow_model in records:
print('processing workflow %d'%workflow_model.id)
processor = WorkflowProcessor(workflow_model)
processor.bpmn_workflow.refresh_waiting_tasks()
processor.bpmn_workflow.do_engine_steps()
processor.save()
@staticmethod
@timeit
def test_spec(spec_id, validate_study_id=None, test_until=None, required_only=False):
"""Runs a spec through it's paces to see if it results in any errors.
Not fool-proof, but a good sanity check. Returns the final data

View File

@ -0,0 +1,68 @@
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_0ilr8m3" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.7.0">
<bpmn:process id="timer" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_1pahvlr</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:manualTask id="get_coffee" name="Get Coffee">
<bpmn:incoming>Flow_1pahvlr</bpmn:incoming>
<bpmn:outgoing>Flow_1pvkgnu</bpmn:outgoing>
</bpmn:manualTask>
<bpmn:intermediateCatchEvent id="Event_0bxivgz" name="Take 5">
<bpmn:incoming>Flow_1pvkgnu</bpmn:incoming>
<bpmn:outgoing>Flow_1elbn9u</bpmn:outgoing>
<bpmn:timerEventDefinition id="TimerEventDefinition_1jrn73k">
<bpmn:timeDuration xsi:type="bpmn:tFormalExpression">timedelta(seconds=.25)</bpmn:timeDuration>
</bpmn:timerEventDefinition>
</bpmn:intermediateCatchEvent>
<bpmn:manualTask id="back_to_work" name="Get Back To Work">
<bpmn:incoming>Flow_1elbn9u</bpmn:incoming>
<bpmn:outgoing>Flow_1ekgt3x</bpmn:outgoing>
</bpmn:manualTask>
<bpmn:endEvent id="Event_03w65sk">
<bpmn:incoming>Flow_1ekgt3x</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1ekgt3x" sourceRef="back_to_work" targetRef="Event_03w65sk" />
<bpmn:sequenceFlow id="Flow_1elbn9u" sourceRef="Event_0bxivgz" targetRef="back_to_work" />
<bpmn:sequenceFlow id="Flow_1pvkgnu" sourceRef="get_coffee" targetRef="Event_0bxivgz" />
<bpmn:sequenceFlow id="Flow_1pahvlr" sourceRef="StartEvent_1" targetRef="get_coffee" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="timer">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0tjl9dd_di" bpmnElement="get_coffee">
<dc:Bounds x="260" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0bljn9v_di" bpmnElement="Event_0bxivgz">
<dc:Bounds x="412" y="99" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="414" y="142" width="33" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_15zi5m4_di" bpmnElement="back_to_work">
<dc:Bounds x="533" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_03w65sk_di" bpmnElement="Event_03w65sk">
<dc:Bounds x="682" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1ekgt3x_di" bpmnElement="Flow_1ekgt3x">
<di:waypoint x="633" y="117" />
<di:waypoint x="682" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1elbn9u_di" bpmnElement="Flow_1elbn9u">
<di:waypoint x="448" y="117" />
<di:waypoint x="533" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1pvkgnu_di" bpmnElement="Flow_1pvkgnu">
<di:waypoint x="360" y="117" />
<di:waypoint x="412" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1pahvlr_di" bpmnElement="Flow_1pahvlr">
<di:waypoint x="215" y="117" />
<di:waypoint x="260" y="117" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

30
tests/test_wait_event.py Normal file
View File

@ -0,0 +1,30 @@
import json
import time
from crc.services.workflow_processor import WorkflowProcessor
from tests.base_test import BaseTest
from crc.models.workflow import WorkflowStatus, WorkflowModel
from crc import db
from crc.api.common import ApiError
from crc.models.task_event import TaskEventModel, TaskEventSchema
from crc.services.workflow_service import WorkflowService
class TestTimerEvent(BaseTest):
def test_timer_event(self):
workflow = self.create_workflow('timer_event')
processor = WorkflowProcessor(workflow)
processor.do_engine_steps()
task = processor.next_task()
processor.complete_task(task)
tasks = processor.get_ready_user_tasks()
self.assertEqual(tasks,[])
processor.save()
time.sleep(.3) # our timer is at .25 sec so we have to wait for it
# get done waiting
WorkflowService.do_waiting()
wf = db.session.query(WorkflowModel).filter(WorkflowModel.id == workflow.id).first()
self.assertTrue(wf.status != WorkflowStatus.waiting)