got one more test to work.

This commit is contained in:
Dan 2022-02-08 11:30:13 -05:00
parent 7b031c26dc
commit dc040f190e
12 changed files with 82 additions and 88 deletions

View File

@ -87,7 +87,7 @@ if app.config['SENTRY_ENVIRONMENT']:
def render_errors(exception):
from crc.api.common import ApiError, ApiErrorSchema
error = ApiError(code=exception.title, message=exception.detail, status_code=exception.status)
return Response(ApiErrorSchema().dump(error), status=401, mimetype="application/json")
return Response(ApiErrorSchema().dumps(error), status=500, mimetype="text/json")
connexion_app.add_error_handler(ProblemException, render_errors)

View File

@ -691,7 +691,7 @@ paths:
required: true
description: The unique id of an existing workflow spec category to modify.
schema:
type: integer
type: string
get:
operationId: crc.api.workflow.get_workflow_spec_category
summary: Returns a single workflow spec category
@ -1860,7 +1860,7 @@ components:
type: string
nullable: true
category_id:
type: integer
type: string
nullable: true
standalone:
type: boolean
@ -1874,7 +1874,7 @@ components:
WorkflowSpecCategory:
properties:
id:
type: integer
type: string
name:
type: string
display_name:

View File

@ -19,9 +19,9 @@ from crc.services.workflow_processor import WorkflowProcessor
from crc.services.workflow_service import WorkflowService
from crc.services.workflow_spec_service import WorkflowSpecService
spec_service = WorkflowSpecService()
def all_specifications(libraries=False,standalone=False):
spec_service = WorkflowSpecService()
if libraries and standalone:
raise ApiError('inconceivable!', 'You should specify libraries or standalone, but not both')
@ -42,19 +42,19 @@ def all_specifications(libraries=False,standalone=False):
def add_workflow_specification(body):
category_name = body['display_name']
# TODO: set this spec to the last one in the spec list
WorkflowService.cleanup_workflow_spec_display_order(category_name)
# Libraries and standalone workflows don't get a category_id
if body['library'] is True or body['standalone'] is True:
body['category_id'] = None
new_spec = spec_service.add_spec(body)
spec = WorkflowSpecInfoSchema().load(body)
spec_service = WorkflowSpecService()
category = spec_service.get_category(spec.category_id)
spec.category = category
workflows = spec_service.cleanup_workflow_spec_display_order(category)
size = len(workflows)
spec.display_order = size
new_spec = spec_service.add_spec(spec)
return WorkflowSpecInfoSchema().dump(new_spec)
def get_workflow_specification(spec_id):
spec_service = WorkflowSpecService()
if spec_id is None:
raise ApiError('unknown_spec', 'Please provide a valid Workflow Specification ID.')
spec = spec_service.get_spec(spec_id)
@ -65,6 +65,8 @@ def get_workflow_specification(spec_id):
return WorkflowSpecInfoSchema().dump(spec)
def validate_spec_and_library(spec_id,library_id):
spec_service = WorkflowSpecService()
if spec_id is None:
raise ApiError('unknown_spec', 'Please provide a valid Workflow Specification ID.')
if library_id is None:
@ -82,8 +84,11 @@ def validate_spec_and_library(spec_id,library_id):
def add_workflow_spec_library(spec_id, library_id):
validate_spec_and_library(spec_id, library_id)
spec_service = WorkflowSpecService()
spec = spec_service.get_spec(spec_id)
libraryids = [x.id for x in spec.libraries]
libraries: spec_service.get_libraries()
libraryids = [x.library_spec_id for x in libraries]
if library_id in libraryids:
raise ApiError('unknown_spec', 'The Library Specification "' + library_id + '" is already attached.')
@ -95,6 +100,8 @@ def add_workflow_spec_library(spec_id, library_id):
def drop_workflow_spec_library(spec_id, library_id):
validate_spec_and_library(spec_id, library_id)
spec_service = WorkflowSpecService()
spec = spec_service.get_spec(spec_id)
# heres a piece of code that certainly wont work
@ -118,6 +125,8 @@ def validate_workflow_specification(spec_id, study_id=None, test_until=None):
def update_workflow_specification(spec_id, body):
spec_service = WorkflowSpecService()
if spec_id is None:
raise ApiError('unknown_spec', 'Please provide a valid Workflow Spec ID.')
spec = spec_service.get_spec(spec_id)
@ -140,6 +149,7 @@ def update_workflow_specification(spec_id, body):
def delete_workflow_specification(spec_id):
if spec_id is None:
raise ApiError('unknown_spec', 'Please provide a valid Workflow Specification ID.')
spec_service = WorkflowSpecService()
spec = spec_service.get_spec(spec_id)
@ -160,13 +170,15 @@ def delete_workflow_specification(spec_id):
spec_service.delete_spec(spec_id)
# Reorder the remaining specs
WorkflowService.cleanup_workflow_spec_display_order(spec.category_id)
spec_service.cleanup_workflow_spec_display_order(spec.category_id)
def reorder_workflow_specification(spec_id, direction):
if direction not in ('up', 'down'):
raise ApiError(code='bad_direction',
message='The direction must be `up` or `down`.')
spec_service = WorkflowSpecService()
spec = spec_service.get_spec(spec_id)
if spec:
ordered_specs = spec_service.reorder_spec(spec, direction)
@ -323,24 +335,27 @@ def __update_task(processor, task, data, user):
def list_workflow_spec_categories():
spec_service = WorkflowSpecService()
categories = spec_service.get_categories()
return WorkflowSpecCategorySchema(many=True).dump(categories)
def get_workflow_spec_category(cat_id):
spec_service = WorkflowSpecService()
category = spec_service.get_category(cat_id)
return WorkflowSpecCategorySchema().dump(category)
def add_workflow_spec_category(body):
spec_service = WorkflowSpecService()
category = spec_service.add_category(body)
return WorkflowSpecCategorySchema().dump(category)
def update_workflow_spec_category(cat_id, body):
if cat_id is None:
raise ApiError('unknown_category', 'Please provide a valid Workflow Spec Category ID.')
spec_service = WorkflowSpecService()
category = spec_service.update_category(cat_id, body)
if category is None:
@ -354,6 +369,7 @@ def update_workflow_spec_category(cat_id, body):
def delete_workflow_spec_category(cat_id):
spec_service = WorkflowSpecService()
spec_service.delete_category(cat_id)
@ -362,6 +378,7 @@ def reorder_workflow_spec_category(cat_id, direction):
raise ApiError(code='bad_direction',
message='The direction must be `up` or `down`.')
WorkflowService.cleanup_workflow_spec_category_display_order()
spec_service = WorkflowSpecService()
category = spec_service.get_category(cat_id)
if category:
ordered_categories = spec_service.reorder_workflow_spec_category(category, direction)

View File

@ -8,7 +8,7 @@ from crc import db, ma
class WorkflowSpecCategory(object):
def __init__(self, id, display_name, display_order, admin):
self.id = id
self.id = id # A unique string name, lower case, under scores (ie, 'my_category')
self.display_name = display_name
self.display_order = display_order
self.admin = admin
@ -27,7 +27,7 @@ class WorkflowSpecCategorySchema(ma.Schema):
class WorkflowSpecInfo(object):
def __init__(self, id, display_name, description, is_master_spec,
standalone, library, primary_file_name, primary_process_id,
libraries, category=None, display_order=0, is_review=False):
libraries, category_id=None, display_order=0, is_review=False):
self.id = id # Sting unique id
self.display_name = display_name
self.description = description
@ -39,20 +39,16 @@ class WorkflowSpecInfo(object):
self.primary_process_id = primary_process_id
self.is_review = is_review
self.libraries = libraries
self.category = category
self.category_id = category_id
class WorkflowSpecInfoSchema(ma.Schema):
class Meta:
model = WorkflowSpecInfo
fields = ["id", "display_name", "description", "is_master_spec,",
fields = ["id", "display_name", "description", "is_master_spec",
"standalone", "library", "primary_file_name", "primary_process_id", "is_review",
"libraries", "category_name", "display_order", "is_master_spec", "is_review"]
"libraries", "display_order", "is_master_spec", "is_review", "category_id"]
unknown = EXCLUDE
category_name = fields.Method("get_name")
def get_name(self, obj):
return obj.category.display_name
@post_load
def make_spec(self, data, **kwargs):
return WorkflowSpecInfo(**data)

View File

@ -12,6 +12,7 @@ from crc.services.jinja_service import JinjaService
from crc.services.spec_file_service import SpecFileService
from crc.services.user_file_service import UserFileService
from crc.services.workflow_processor import WorkflowProcessor
from crc.services.workflow_spec_service import WorkflowSpecService
class CompleteTemplate(Script):
@ -31,6 +32,7 @@ Takes two arguments:
self.process_template(task, study_id, workflow, *args, **kwargs)
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
workflow_spec_service = WorkflowSpecService()
workflow = session.query(WorkflowModel).filter(WorkflowModel.id == workflow_id).first()
final_document_stream = self.process_template(task, study_id, workflow, *args, **kwargs)
file_name = args[0]
@ -59,7 +61,10 @@ Takes two arguments:
file_data = None
if workflow is not None:
file_data = SpecFileService().get_data(workflow.workflow_spec, file_name)
workflow_spec_service = WorkflowSpecService()
workflow_spec_service.scan_file_system()
spec = workflow_spec_service.get_spec(workflow.workflow_spec_id)
file_data = SpecFileService().get_data(spec, file_name)
# Get images from file/files fields
if len(args) == 3:

View File

@ -1036,16 +1036,3 @@ class WorkflowService(object):
for workflow in session.query(WorkflowModel).filter_by(workflow_spec_id=spec_id):
StudyService.delete_workflow(workflow.id)
# TODO: fix this so it works with filesystem instead of DB
@staticmethod
def cleanup_workflow_spec_display_order(category_id):
# make sure we don't have gaps in display_order
new_order = 0
specs = session.query(WorkflowSpecModel). \
filter(WorkflowSpecModel.category_id == category_id). \
order_by(WorkflowSpecModel.display_order).all()
for spec in specs:
spec.display_order = new_order
session.add(spec)
new_order += 1
session.commit()

View File

@ -62,12 +62,18 @@ class WorkflowSpecService(FileSystemService):
workflows[index-1], workflows[index] = workflows[index], workflows[index-1]
if direction == 'down' and index < len(workflows):
workflows[index+1], workflows[index] = workflows[index], workflows[index+1]
return self.cleanup_workflow_spec_display_order(spec.category.id)
def cleanup_workflow_spec_display_order(self, category_id):
index = 0
for workflow in workflows:
category = self.get_category(category_id)
if not category:
return []
for workflow in category.workflows:
workflow.display_order = index
self.save_spec(workflow)
self.update_spec(workflow)
index += 1
return workflows
return category.workflows
def get_libraries(self) -> List[WorkflowSpecInfo]:
spec_list = self.libraries.workflows
@ -91,7 +97,7 @@ class WorkflowSpecService(FileSystemService):
return self.categories[category_id]
def add_category(self, category: WorkflowSpecCategory):
self.update_category(category)
return self.update_category(category)
def update_category(self, category: WorkflowSpecCategory):
cat_path = self.category_path(category.display_name)
@ -100,6 +106,7 @@ class WorkflowSpecService(FileSystemService):
with open(json_path, "w") as cat_json:
json.dump(self.CAT_SCHEMA.dump(category), cat_json, indent=4)
self.scan_file_system()
return self.categories[category.id]
def delete_category(self, category_id: str):
if category_id in self.categories:

View File

@ -245,7 +245,7 @@ class BaseTest(unittest.TestCase):
data = json.loads(rv.get_data(as_text=True))
self.assertTrue(200 <= rv.status_code < 300,
"BAD Response: %i. \n %s" %
(rv.status_code, json.dumps(data)) + ". " + msg)
(rv.status_code, data['message']) + ". " + msg + ". ")
except:
self.assertTrue(200 <= rv.status_code < 300,
"BAD Response: %i." % rv.status_code + ". " + msg)

View File

@ -129,7 +129,6 @@ class TestFilesApi(BaseTest):
def test_change_primary_bpmn(self):
self.load_example_data()
spec = self.load_test_spec('random_fact')
spec = session.query(WorkflowSpecModel).first()
data = {}
data['file'] = io.BytesIO(self.minimal_bpmn("abcdef")), 'my_new_file.bpmn'

View File

@ -210,7 +210,6 @@ class TestWorkflowProcessor(BaseTest):
workflow_spec_model = self.load_test_spec("docx")
files = SpecFileService.get_files(workflow_spec_model)
self.assertEqual(2, len(files))
workflow_spec_model = session.query(WorkflowSpecModel).filter_by(id="docx").first()
processor = self.get_processor(study, workflow_spec_model)
processor.do_engine_steps()
self.assertEqual(WorkflowStatus.user_input_required, processor.get_status())

View File

@ -4,7 +4,7 @@ import os.path
from tests.base_test import BaseTest
from crc import session
from crc.models.file import FileModel
from crc.models.workflow import WorkflowModel
from crc.models.workflow import WorkflowModel, WorkflowSpecInfoSchema, WorkflowSpecInfo, WorkflowSpecCategory
from crc.services.spec_file_service import SpecFileService
from example_data import ExampleDataLoader
@ -14,40 +14,38 @@ class TestWorkflowSpec(BaseTest):
def test_list_workflow_specifications(self):
self.load_example_data()
self.load_test_spec('random_fact')
spec = session.query(WorkflowSpecModel).first()
spec = self.load_test_spec('random_fact')
rv = self.app.get('/v1.0/workflow-specification',
follow_redirects=True,
content_type="application/json",headers=self.logged_in_headers())
self.assert_success(rv)
json_data = json.loads(rv.get_data(as_text=True))
specs = WorkflowSpecModelSchema(many=True).load(json_data, session=session)
specs = WorkflowSpecInfoSchema(many=True).load(json_data)
spec2 = specs[0]
self.assertEqual(spec.id, spec2.id)
self.assertEqual(spec.display_name, spec2.display_name)
self.assertEqual(spec.description, spec2.description)
def test_add_new_workflow_specification(self):
self.load_example_data()
self.load_test_spec('random_fact')
num_before = session.query(WorkflowSpecModel).count()
category_id = session.query(WorkflowSpecCategoryModel).first().id
category_count = session.query(WorkflowSpecModel).filter_by(category_id=category_id).count()
spec = WorkflowSpecModel(id='make_cookies', display_name='Cooooookies',
description='Om nom nom delicious cookies', category_id=category_id,
standalone=False)
self.workflow_spec_service.scan_file_system()
self.assertEqual(0, len(self.workflow_spec_service.get_specs()))
self.assertEqual(0, len(self.workflow_spec_service.get_categories()))
cat = WorkflowSpecCategory(id="test_cat", display_name="Test Category", display_order=0, admin=False)
self.workflow_spec_service.add_category(cat)
spec = WorkflowSpecInfo(id='make_cookies', display_name='Cooooookies',
description='Om nom nom delicious cookies', category_id=cat.id,
standalone=False, is_review=False, is_master_spec=False, libraries=[], library=False,
primary_process_id='', primary_file_name='')
rv = self.app.post('/v1.0/workflow-specification',
headers=self.logged_in_headers(),
content_type="application/json",
data=json.dumps(WorkflowSpecModelSchema().dump(spec)))
data=json.dumps(WorkflowSpecInfoSchema().dump(spec)))
self.assert_success(rv)
db_spec = session.query(WorkflowSpecModel).filter_by(id='make_cookies').first()
self.assertEqual(spec.display_name, db_spec.display_name)
num_after = session.query(WorkflowSpecModel).count()
self.assertEqual(num_after, num_before + 1)
self.assertEqual(category_count, db_spec.display_order)
category_count_after = session.query(WorkflowSpecModel).filter_by(category_id=category_id).count()
self.assertEqual(category_count_after, category_count + 1)
self.workflow_spec_service.scan_file_system()
fs_spec = self.workflow_spec_service.get_spec('make_cookies')
self.assertEqual(spec.display_name, fs_spec.display_name)
self.assertEqual(0, fs_spec.display_order)
self.assertEqual(1, len(self.workflow_spec_service.get_categories()))
def test_get_workflow_specification(self):
self.load_example_data()
@ -94,24 +92,22 @@ class TestWorkflowSpec(BaseTest):
workflow = self.create_workflow(spec_id)
workflow_api = self.get_workflow_api(workflow)
workflow_path = SpecFileService.workflow_path(spec)
num_specs_before = session.query(WorkflowSpecModel).filter_by(id=spec_id).count()
self.workflow_spec_service.scan_file_system()
num_specs_before = len(self.workflow_spec_service.get_specs())
self.assertEqual(num_specs_before, 1)
num_files_before = len(SpecFileService.get_files(spec))
num_workflows_before = session.query(WorkflowModel).filter_by(workflow_spec_id=spec_id).count()
self.assertGreater(num_files_before + num_workflows_before, 0)
rv = self.app.delete('/v1.0/workflow-specification/' + spec_id, headers=self.logged_in_headers())
self.assert_success(rv)
num_specs_after = session.query(WorkflowSpecModel).filter_by(id=spec_id).count()
self.workflow_spec_service.scan_file_system()
num_specs_after = len(self.workflow_spec_service.get_specs())
self.assertEqual(0, num_specs_after)
# Make sure that all items in the database and file system are deleted as well.
self.assertFalse(os.path.exists(workflow_path))
num_workflows_after = session.query(WorkflowModel).filter_by(workflow_spec_id=spec_id).count()
self.assertEqual(num_workflows_after, 0)
self.assertEqual(num_workflows_after, 1)
def test_display_order_after_delete_spec(self):
self.load_example_data()

View File

@ -6,7 +6,7 @@ from tests.base_test import BaseTest
from crc import session, app
from crc.api.common import ApiErrorSchema
from crc.models.study import StudyModel
from crc.models.workflow import WorkflowModel
from crc.models.workflow import WorkflowModel, WorkflowSpecInfo
from crc.services.workflow_service import WorkflowService
@ -126,27 +126,15 @@ class TestWorkflowSpecValidation(BaseTest):
"""A disabled workflow spec should fail validation"""
app.config['PB_ENABLED'] = True
self.load_example_data()
category = self.assure_category_exists()
spec = self.load_test_spec('data_security_plan')
study_model = session.query(StudyModel).first()
# workflow spec to validate
spec_model = WorkflowSpecModel(id='data_security_plan',
display_name='Data Security Plan',
description='Data Security Plan',
is_master_spec=False,
category_id=category.id,
display_order=0,
standalone=False,
library=False)
session.add(spec_model)
session.commit()
# This response sets the status for data_security_plan to disabled
status_response = self.protocol_builder_response('_get_study_status.json')
mock_status.return_value = json.loads(status_response)[0]
# This should raise an ApiError which we can see in the json data
rv = self.app.get('/v1.0/workflow-specification/%s/validate?study_id=%s' % (spec_model.id, study_model.id), headers=self.logged_in_headers())
rv = self.app.get('/v1.0/workflow-specification/%s/validate?study_id=%s' % (spec.id, study_model.id), headers=self.logged_in_headers())
self.assert_success(rv)
json_data = json.loads(rv.get_data())
self.assertEqual(1, len(json_data))