def test_do_task(self): self.load_example_data() workflow = self.create_workflow('empty_workflow') processor = WorkflowProcessor(workflow) task = processor.next_task() details = Box({ "title": "My New Title", "short_title": "My New Short Title", "pi": "dhf8r", "short_name": "My Short Name", "proposal_name": "My Proposal Name" }) script = UpdateStudy() # note that we changed where the argument gets evaluated # previsously, it took the arguments and then evaluated them within the script # now, it evaluates the arugments in the context of the main script so they get # evaluated before they are passed to the script - # this allows us to do a lot more things like strings, functions, etc. # and it makes the arguments less confusing to use. script.do_task(task, workflow.study_id, workflow.id, title=details.title, short_title=details.short_title, pi=details.pi, short_name=details.short_name, proposal_name=details.proposal_name) self.assertEqual(details.title, workflow.study.title) self.assertEqual(details.short_title, workflow.study.short_title) self.assertEqual(details.pi, workflow.study.primary_investigator_id) self.assertEqual(details.short_name, workflow.study.short_name) self.assertEqual(details.proposal_name, workflow.study.proposal_name)
def test_file_data_set_changes_irb_code(self, mock_get): mock_get.return_value.ok = True mock_get.return_value.text = self.protocol_builder_response( 'required_docs.json') self.load_example_data() study = session.query(StudyModel).first() workflow_spec_model = self.load_test_spec("two_forms") workflow_model = StudyService._create_workflow_model( study, workflow_spec_model) irb_code = "UVACompl_PRCAppr" # The first file referenced in pb required docs. file = FileService.add_workflow_file(workflow_id=workflow_model.id, task_spec_name='TaskSpec01', name="anything.png", content_type="text", binary_data=b'1234', irb_doc_code=irb_code) processor = WorkflowProcessor(workflow_model) task = processor.next_task() FileDataSet().do_task(task, study.id, workflow_model.id, key="irb_code", value="Study_App_Doc", file_id=file.id) docs = StudyInfo().do_task(task, study.id, workflow_model.id, "documents") self.assertTrue(isinstance(docs, Box)) self.assertEqual(1, len(docs.Study_App_Doc.files)) self.assertEqual("Study_App_Doc", docs.Study_App_Doc.files[0].data_store.irb_code)
def test_file_data_set_invalid_irb_code_fails(self, mock_get): mock_get.return_value.ok = True mock_get.return_value.text = self.protocol_builder_response( 'required_docs.json') self.load_example_data() study = session.query(StudyModel).first() workflow_spec_model = self.load_test_spec("two_forms") workflow_model = StudyService._create_workflow_model( study, workflow_spec_model) irb_code = "UVACompl_PRCAppr" # The first file referenced in pb required docs. file = FileService.add_workflow_file(workflow_id=workflow_model.id, task_spec_name='Activity01', name="anything.png", content_type="text", binary_data=b'1234', irb_doc_code=irb_code) processor = WorkflowProcessor(workflow_model) task = processor.next_task() with self.assertRaises(ApiError): FileDataSet().do_task(task, study.id, workflow_model.id, key="irb_code", value="My_Pretty_Pony", file_id=file.id)
def test_study_sponsors_script_ensure_delete(self, mock_get): mock_get.return_value.ok = True mock_get.return_value.text = self.protocol_builder_response( 'sponsors.json') flask.g.user = UserModel(uid='dhf8r') app.config['PB_ENABLED'] = True self.load_example_data() study = session.query(StudyModel).first() workflow_spec_model = self.load_test_spec( "study_sponsors_associates_delete") workflow_model = StudyService._create_workflow_model( study, workflow_spec_model) WorkflowService.test_spec("study_sponsors_associates_delete") processor = WorkflowProcessor(workflow_model) processor.do_engine_steps() # change user and make sure we can access the study flask.g.user = UserModel(uid='lb3dp') flask.g.token = 'my spiffy token' app.config['PB_ENABLED'] = False output = user_studies() self.assertEqual(len(output), 0) flask.g.token = 'my spiffy token' app.config['PB_ENABLED'] = False output = user_studies() self.assertEqual(len(output), 0)
def test_add_file_from_task_and_form_errors_on_invalid_form_field_name( self): self.load_example_data() self.create_reference_document() workflow = self.create_workflow('file_upload_form') processor = WorkflowProcessor(workflow) task = processor.next_task() data = {'file': (io.BytesIO(b"abcdef"), 'random_fact.svg')} correct_name = task.task_spec.form.fields[0].id rv = self.app.post( '/v1.0/file?study_id=%i&workflow_id=%s&task_id=%i&form_field_key=%s' % (workflow.study_id, workflow.id, task.id, "not_a_known_file"), data=data, follow_redirects=True, content_type='multipart/form-data', headers=self.logged_in_headers()) self.assert_failure(rv, error_code="invalid_form_field_key") data = {'file': (io.BytesIO(b"abcdef"), 'random_fact.svg')} rv = self.app.post( '/v1.0/file?study_id=%i&workflow_id=%s&task_id=%i&form_field_key=%s' % (workflow.study_id, workflow.id, task.id, correct_name), data=data, follow_redirects=True, content_type='multipart/form-data', headers=self.logged_in_headers()) self.assert_success(rv)
def set_current_task(workflow_id, task_id): workflow_model = session.query(WorkflowModel).filter_by( id=workflow_id).first() processor = WorkflowProcessor(workflow_model) task_id = uuid.UUID(task_id) spiff_task = processor.bpmn_workflow.get_task(task_id) _verify_user_and_role(processor, spiff_task) user_uid = g.user.uid if spiff_task.state != spiff_task.COMPLETED and spiff_task.state != spiff_task.READY: raise ApiError( "invalid_state", "You may not move the token to a task who's state is not " "currently set to COMPLETE or READY.") # Only reset the token if the task doesn't already have it. if spiff_task.state == spiff_task.COMPLETED: spiff_task.reset_token( reset_data=True ) # Don't try to copy the existing data back into this task. processor.save() WorkflowService.log_task_action(user_uid, processor, spiff_task, WorkflowService.TASK_ACTION_TOKEN_RESET) WorkflowService.update_task_assignments(processor) workflow_api_model = WorkflowService.processor_to_workflow_api( processor, spiff_task) return WorkflowApiSchema().dump(workflow_api_model)
def test_get_logs_for_study(self): self.load_example_data() study = session.query(StudyModel).first() workflow = self.create_workflow('hello_world', study=study) processor = WorkflowProcessor(workflow) task = processor.next_task() TaskLog().do_task(task, study.id, workflow.id, level='critical', code='critical_code', message='This is my critical message.') TaskLog().do_task(task, study.id, workflow.id, level='debug', code='debug_code', message='This is my debug message.') # This workflow adds 3 logs # some_text = 'variable' # log('info', 'some_code', 'Some longer message') # log('info', 'some_other_code', 'Another really long message') # log('debug', 'debug_code', f'This message has a { some_text }!') workflow = self.create_workflow('get_logging_for_study', study=study) workflow_api = self.get_workflow_api(workflow) task_api = workflow_api.next_task workflow_api = self.complete_form(workflow, task_api, {}) task_api = workflow_api.next_task workflow_logs = task_api.data['workflow_logs'] study_logs = task_api.data['study_logs'] self.assertEqual(3, len(workflow_logs)) self.assertEqual(5, len(study_logs))
def test_documentation_processing_handles_replacements(self): self.load_example_data() workflow = self.create_workflow('random_fact') processor = WorkflowProcessor(workflow) processor.do_engine_steps() task = processor.next_task() task.task_spec.documentation = "Some simple docs" docs = WorkflowService._process_documentation(task) self.assertEqual("Some simple docs", docs) task.data = {"replace_me": "new_thing"} task.task_spec.documentation = "{{replace_me}}" docs = WorkflowService._process_documentation(task) self.assertEqual("new_thing", docs) documentation = """ # Bigger Test * bullet one * bullet two has {{replace_me}} # other stuff. """ expected = """ # Bigger Test * bullet one * bullet two has new_thing # other stuff. """ task.task_spec.documentation = documentation result = WorkflowService._process_documentation(task) self.assertEqual(expected, result)
def test_get_study_has_details_about_files(self): # Set up the study and attach a file to it. self.load_example_data() self.create_reference_document() workflow = self.create_workflow('file_upload_form') processor = WorkflowProcessor(workflow) task = processor.next_task() irb_code = "UVACompl_PRCAppr" # The first file referenced in pb required docs. FileService.add_workflow_file(workflow_id=workflow.id, name="anything.png", content_type="png", binary_data=b'1234', irb_doc_code=irb_code) api_response = self.app.get('/v1.0/study/%i' % workflow.study_id, headers=self.logged_in_headers(), content_type="application/json") self.assert_success(api_response) study = StudySchema().loads(api_response.get_data(as_text=True)) self.assertEqual(1, len(study.files)) self.assertEqual("UVA Compliance/PRC Approval", study.files[0]["category"]) self.assertEqual("Cancer Center's PRC Approval Form", study.files[0]["description"]) self.assertEqual("UVA Compliance/PRC Approval.png", study.files[0]["download_name"])
def test_add_file_from_task_increments_version_and_replaces_on_subsequent_add( self): self.load_example_data() self.create_reference_document() workflow = self.create_workflow('file_upload_form') processor = WorkflowProcessor(workflow) task = processor.next_task() irb_code = "UVACompl_PRCAppr" # The first file referenced in pb required docs. FileService.add_workflow_file(workflow_id=workflow.id, name="anything.png", content_type="text", binary_data=b'1234', irb_doc_code=irb_code) # Add the file again with different data FileService.add_workflow_file(workflow_id=workflow.id, name="anything.png", content_type="text", binary_data=b'5678', irb_doc_code=irb_code) file_models = FileService.get_workflow_files(workflow_id=workflow.id) self.assertEqual(1, len(file_models)) file_data = FileService.get_workflow_data_files( workflow_id=workflow.id) self.assertEqual(1, len(file_data)) self.assertEqual(2, file_data[0].version)
def test_archive_file_no_longer_shows_up(self): self.load_example_data() self.create_reference_document() workflow = self.create_workflow('file_upload_form') processor = WorkflowProcessor(workflow) task = processor.next_task() data = {'file': (io.BytesIO(b"abcdef"), 'random_fact.svg')} correct_name = task.task_spec.form.fields[0].id data = {'file': (io.BytesIO(b"abcdef"), 'random_fact.svg')} rv = self.app.post( '/v1.0/file?study_id=%i&workflow_id=%s&task_id=%i&form_field_key=%s' % (workflow.study_id, workflow.id, task.id, correct_name), data=data, follow_redirects=True, content_type='multipart/form-data', headers=self.logged_in_headers()) self.assert_success(rv) rv = self.app.get('/v1.0/file?workflow_id=%s' % workflow.id, headers=self.logged_in_headers()) self.assert_success(rv) self.assertEqual(1, len(json.loads(rv.get_data(as_text=True)))) file_model = db.session.query(FileModel).filter( FileModel.workflow_id == workflow.id).all() self.assertEqual(1, len(file_model)) file_model[0].archived = True db.session.commit() rv = self.app.get('/v1.0/file?workflow_id=%s' % workflow.id, headers=self.logged_in_headers()) self.assert_success(rv) self.assertEqual(0, len(json.loads(rv.get_data(as_text=True))))
def test_validate_returns_error_if_reference_files_do_not_exist( self, mock_get): mock_get.return_value.ok = True mock_get.return_value.text = self.protocol_builder_response( 'required_docs.json') self.load_example_data() self.create_reference_document() study = session.query(StudyModel).first() workflow_spec_model = self.load_test_spec("two_forms") workflow_model = StudyService._create_workflow_model( study, workflow_spec_model) processor = WorkflowProcessor(workflow_model) task = processor.next_task() # Remove the reference file. file_model = db.session.query(FileModel). \ filter(FileModel.is_reference == True). \ filter(FileModel.name == FileService.DOCUMENT_LIST).first() if file_model: db.session.query(FileDataModel).filter( FileDataModel.file_model_id == file_model.id).delete() db.session.query(FileModel).filter( FileModel.id == file_model.id).delete() db.session.commit() db.session.flush() with self.assertRaises(ApiError): StudyInfo().do_task_validate_only(task, study.id, "documents")
def setUp(self): self.load_example_data() self.study = session.query(StudyModel).first() self.workflow_spec_model = self.load_test_spec("two_forms") self.workflow_model = StudyService._create_workflow_model( self.study, self.workflow_spec_model) self.processor = WorkflowProcessor(self.workflow_model) self.task = self.processor.next_task()
def restart_workflow(workflow_id, clear_data=False, delete_files=False): """Restart a workflow with the latest spec. Clear data allows user to restart the workflow without previous data.""" workflow_model: WorkflowModel = session.query(WorkflowModel).filter_by( id=workflow_id).first() WorkflowProcessor.reset(workflow_model, clear_data=clear_data, delete_files=delete_files) return get_workflow(workflow_model.id)
def test_random_data_populate_form_on_auto_complete(self): self.load_example_data() workflow = self.create_workflow('enum_options_with_search') processor = WorkflowProcessor(workflow) processor.do_engine_steps() task = processor.next_task() task_api = WorkflowService.spiff_task_to_api_task(task, add_docs_and_forms=True) WorkflowService.populate_form_with_random_data(task, task_api, required_only=False) self.assertTrue(isinstance(task.data["sponsor"], dict))
def test_enum_options_from_file(self): self.load_example_data() workflow = self.create_workflow('enum_options_from_file') processor = WorkflowProcessor(workflow) processor.do_engine_steps() task = processor.next_task() WorkflowService.process_options(task, task.task_spec.form.fields[0]) options = task.task_spec.form.fields[0].options self.assertEqual(29, len(options)) self.assertEqual('0', options[0].id) self.assertEqual("Other", options[0].name)
def test_enum_options_from_file(self): self.load_example_data() workflow = self.create_workflow('enum_options_from_file') processor = WorkflowProcessor(workflow) processor.do_engine_steps() task = processor.next_task() WorkflowService.process_options(task, task.task_spec.form.fields[0]) options = task.task_spec.form.fields[0].options self.assertEqual(28, len(options)) self.assertEqual('1000', options[0]['id']) self.assertEqual("UVA - INTERNAL - GM USE ONLY", options[0]['name'])
def test_get_current_user_details(self): self.load_example_data() workflow = self.create_workflow('empty_workflow') processor = WorkflowProcessor(workflow) task = processor.next_task() script = Ldap() g.user = db.session.query(UserModel).filter( UserModel.uid == 'dhf8r').first() user_details = script.do_task(task, workflow.study_id, workflow.id) self.assertEqual(user_details['display_name'], 'Dan Funk')
def test_do_task_with_incorrect_argument(self): """This script should raise an error if it can't figure out the approvers.""" self.load_example_data() self.create_reference_document() workflow = self.create_workflow('empty_workflow') processor = WorkflowProcessor(workflow) task = processor.next_task() task.data = {"approvals": {'dhf8r':["invalid"], 'lb3dp':"invalid"}} script = RequestApproval() with self.assertRaises(ApiError): script.do_task(task, workflow.study_id, workflow.id, "approvals")
def test_do_task_validate_only(self): self.load_example_data() self.create_reference_document() workflow = self.create_workflow('empty_workflow') processor = WorkflowProcessor(workflow) task = processor.next_task() task.data = {"study": {"approval1": "dhf8r", 'approval2':'lb3dp'}} script = RequestApproval() script.do_task_validate_only(task, workflow.study_id, workflow.id, "study.approval1") self.assertEqual(0, db.session.query(ApprovalModel).count())
def test_get_invalid_user_details(self): self.load_example_data() workflow = self.create_workflow('empty_workflow') processor = WorkflowProcessor(workflow) task = processor.next_task() task.data = {'PIComputingID': 'rec3z'} script = Ldap() user_details = script.do_task(task, workflow.study_id, workflow.id, "PIComputingID") self.assertEqual({}, user_details)
def setUp(self): self.load_example_data() self.workflow = self.create_workflow('enum_options_all') self.workflow_api = self.get_workflow_api(self.workflow) # Assure the form has been loaded at least once. processor = WorkflowProcessor(self.workflow) processor.do_engine_steps() self.task = processor.next_task() self.assertEqual(self.task.get_name(), 'myFormTask') self.labelScript = EnumLabel()
def test_jinja_service_element_documentation(self): self.load_example_data() workflow = self.create_workflow('random_fact') processor = WorkflowProcessor(workflow) processor.do_engine_steps() task = processor.next_task() task.data = {"my_template": "Hi {{name}}, This is a jinja template too!", "name": "Dan"} task.task_spec.documentation = """{% include 'my_template' %} Cool Right?""" docs = WorkflowService._process_documentation(task) self.assertEqual("Hi Dan, This is a jinja template too! Cool Right?", docs)
def test_default_values_for_enum_as_checkbox(self): self.load_test_spec('enum_results') workflow = self.create_workflow('enum_results') processor = WorkflowProcessor(workflow) processor.do_engine_steps() task = processor.next_task() service = WorkflowService() checkbox_enum_field = task.task_spec.form.fields[0] radio_enum_field = task.task_spec.form.fields[1] self.assertEqual([], service.get_default_value(checkbox_enum_field, task)) self.assertEqual(None, service.get_default_value(radio_enum_field, task))
def test_do_task(self): self.load_example_data() self.create_reference_document() workflow = self.create_workflow('empty_workflow') processor = WorkflowProcessor(workflow) task = processor.next_task() task.data = {"details": {"label": "My New Title", "value": "dhf8r"}} script = UpdateStudy() script.do_task(task, workflow.study_id, workflow.id, "title:details.label", "pi:details.value") self.assertEqual("My New Title", workflow.study.title) self.assertEqual("dhf8r", workflow.study.primary_investigator_id)
def update_task(workflow_id, task_id, body, terminate_loop=None, update_all=False): workflow_model = session.query(WorkflowModel).filter_by( id=workflow_id).first() if workflow_model is None: raise ApiError("invalid_workflow_id", "The given workflow id is not valid.", status_code=404) processor = WorkflowProcessor(workflow_model) task_id = uuid.UUID(task_id) spiff_task = processor.bpmn_workflow.get_task(task_id) _verify_user_and_role(processor, spiff_task) user = UserService.current_user( allow_admin_impersonate=False) # Always log as the real user. if not spiff_task: raise ApiError("empty_task", "Processor failed to obtain task.", status_code=404) if spiff_task.state != spiff_task.READY: raise ApiError( "invalid_state", "You may not update a task unless it is in the READY state. " "Consider calling a token reset to make this task Ready.") if terminate_loop and spiff_task.is_looping(): spiff_task.terminate_loop() # Extract the details specific to the form submitted form_data = WorkflowService().extract_form_data(body, spiff_task) # Update the task __update_task(processor, spiff_task, form_data, user) # If we need to update all tasks, then get the next ready task and if it a multi-instance with the same # task spec, complete that form as well. if update_all: last_index = spiff_task.task_info()["mi_index"] next_task = processor.next_task() while next_task and next_task.task_info()["mi_index"] > last_index: __update_task(processor, next_task, form_data, user) last_index = next_task.task_info()["mi_index"] next_task = processor.next_task() WorkflowService.update_task_assignments(processor) workflow_api_model = WorkflowService.processor_to_workflow_api(processor) return WorkflowApiSchema().dump(workflow_api_model)
def test_do_task_with_blank_second_approver(self): self.load_example_data() self.create_reference_document() workflow = self.create_workflow('empty_workflow') processor = WorkflowProcessor(workflow) task = processor.next_task() task.data = {"study": {"approval1": "dhf8r", 'approval2':''}} FileService.add_workflow_file(workflow_id=workflow.id, irb_doc_code="UVACompl_PRCAppr", name="anything.png", content_type="text", binary_data=b'1234') script = RequestApproval() script.do_task(task, workflow.study_id, workflow.id, "study.approval1", "study.approval2") self.assertEqual(1, db.session.query(ApprovalModel).count())
def test_no_validation_error_when_correct_file_exists(self, mock_get): mock_get.return_value.ok = True mock_get.return_value.text = self.protocol_builder_response( 'required_docs.json') self.load_example_data() study = session.query(StudyModel).first() workflow_spec_model = self.load_test_spec("two_forms") workflow_model = StudyService._create_workflow_model( study, workflow_spec_model) processor = WorkflowProcessor(workflow_model) task = processor.next_task() StudyInfo().do_task_validate_only(task, study.id, workflow_model.id, "documents")
def test_find_by_id(self): spec = BaseTest.load_test_spec('enum_options_from_file') workflow = self.create_workflow('enum_options_from_file') processor = WorkflowProcessor(workflow) processor.do_engine_steps() result = LookupService.lookup(workflow, "TaskEnumLookup", "AllTheNames", None, value="1000") first_result = result[0] self.assertEquals(1000, first_result['CUSTOMER_NUMBER']) self.assertEquals('UVA - INTERNAL - GM USE ONLY', first_result['CUSTOMER_NAME'])
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)