def test_thankyou_on_expired(self): """If baseline expired and other QB's done, should see thank you""" ae = INTERVENTION.ASSESSMENT_ENGINE ae_id = ae.id # backdate so baseline is expired self.bless_with_basics(backdate=timedelta(days=60)) # generate questionnaire banks and associate user with # metastatic organization mock_questionnairebanks() metastatic_org = Organization.query.filter_by(name='metastatic').one() self.test_user.organizations.append(metastatic_org) # Add a fake assessment only to non-expired one from indefinite mock_qr(user_id=TEST_USER_ID, instrument_id='irondemog') with SessionScope(db): d = {'function': 'update_card_html_on_completion', 'kwargs': []} strat = AccessStrategy( name="update assessment_engine card_html on completion", intervention_id=ae_id, function_details=json.dumps(d)) db.session.add(strat) db.session.commit() user, ae = map(db.session.merge, (self.test_user, ae)) self.assertTrue("Thank you" in ae.display_for_user(user).card_html)
def test_change_before_start_rp_w_result(self): now = datetime.utcnow() back7, nowish = associative_backdate(now=now, backdate=relativedelta(months=7)) back14, nowish = associative_backdate( now=now, backdate=relativedelta(months=14)) org = self.setup_org_qbs(rp_name='v2', retired_as_of=back14) org_id = org.id self.setup_org_qbs(org=org, rp_name='v3') self.consent_with_org(org_id=org_id, setdate=back7) # submit a mock response for baseline QB on old RP # which should result in v2 for baseline and v3 thereafter qb_name = "CRV Baseline v2" baseline = QuestionnaireBank.query.filter( QuestionnaireBank.name == qb_name).one() mock_qr('epic_26_v2', qb=baseline, iteration=None) user = db.session.merge(self.test_user) gen = ordered_qbs(user) # expect everything in v3 post baseline expect_baseline = next(gen) assert visit_name(expect_baseline) == 'Baseline' assert ( expect_baseline.questionnaire_bank.research_protocol.name == 'v2') for n in (3, 6, 9, 15, 18, 21, 30): qbd = next(gen) assert visit_name(qbd) == 'Month {}'.format(n) assert qbd.questionnaire_bank.research_protocol.name == 'v3' with pytest.raises(StopIteration): next(gen)
def test_indef_change_before_start_rp_w_result(self): now = datetime.utcnow() back7, nowish = associative_backdate(now=now, backdate=relativedelta(months=7)) back14, nowish = associative_backdate( now=now, backdate=relativedelta(months=14)) org = self.setup_org_qbs(rp_name='v2', retired_as_of=back14, include_indef=True) org_id = org.id self.setup_org_qbs(org=org, rp_name='v3', include_indef=True) self.consent_with_org(org_id=org_id, setdate=back7) # submit a mock response for indef QB on old RP # which should result in v2 qb_name = "indef_v2" i_v2 = QuestionnaireBank.query.filter( QuestionnaireBank.name == qb_name).one() mock_qr("irondemog_v2", qb=i_v2, iteration=None) user = db.session.merge(self.test_user) gen = ordered_qbs(user, classification='indefinite') # expect only v2 given submission expect_v2 = next(gen) assert (expect_v2.questionnaire_bank.research_protocol.name == 'v2') with pytest.raises(StopIteration): next(gen)
def test_completed_input(self): # Basic w/ one complete QB crv = self.setup_org_qbs() self.bless_with_basics() # pick up a consent, etc. self.test_user = db.session.merge(self.test_user) self.test_user.organizations.append(crv) # submit a mock response for all q's in 3 mo qb # which should result in completed status qb_name = "CRV_recurring_3mo_period v2" threeMo = QuestionnaireBank.query.filter( QuestionnaireBank.name == qb_name).one() for q in threeMo.questionnaires: q = db.session.merge(q) mock_qr(q.name, qb=threeMo, iteration=0) self.test_user = db.session.merge(self.test_user) update_users_QBT(TEST_USER_ID) # for the 8 QBs and verify counts # given the partial results, we find one in progress and one # partially completed, matching expectations assert QBT.query.filter(QBT.status == OverallStatus.due).count() == 8 # should be one less overdue as it became in_progress assert QBT.query.filter( QBT.status == OverallStatus.overdue).count() == 7 # should be one less expired as it became partially_completed assert QBT.query.filter( QBT.status == OverallStatus.expired).count() == 7 assert QBT.query.filter(QBT.status == OverallStatus.in_progress).one() assert QBT.query.filter(QBT.status == OverallStatus.completed).one()
def test_indef_change_before_start_rp_w_result(self): now = datetime.utcnow() back7, nowish = associative_backdate( now=now, backdate=relativedelta(months=7)) back14, nowish = associative_backdate( now=now, backdate=relativedelta(months=14)) org = self.setup_org_qbs( rp_name='v2', retired_as_of=back14, include_indef=True) org_id = org.id self.setup_org_qbs( org=org, rp_name='v3', include_indef=True) self.consent_with_org(org_id=org_id, setdate=back7) # submit a mock response for indef QB on old RP # which should result in v2 qb_name = "indef_v2" i_v2 = QuestionnaireBank.query.filter( QuestionnaireBank.name == qb_name).one() mock_qr("irondemog_v2", qb=i_v2, iteration=None) user = db.session.merge(self.test_user) gen = ordered_qbs(user, classification='indefinite') # expect only v2 given submission expect_v2 = next(gen) assert ( expect_v2.questionnaire_bank.research_protocol.name == 'v2') with pytest.raises(StopIteration): next(gen)
def test_partial_post_overdue_input(self): crv = self.setup_org_qbs() self.bless_with_basics() # pick up a consent, etc. self.test_user = db.session.merge(self.test_user) self.test_user.organizations.append(crv) # submit a mock response for 3 month QB after overdue # before expired post_overdue = datetime.now() + relativedelta(months=4, weeks=1) qb_name = "CRV_recurring_3mo_period v2" threeMo = QuestionnaireBank.query.filter( QuestionnaireBank.name == qb_name).one() mock_qr('epic26_v2', qb=threeMo, iteration=0, timestamp=post_overdue) self.test_user = db.session.merge(self.test_user) update_users_QBT(TEST_USER_ID) # for the 8 QBs and verify counts # given the partial results, we find one in progress and one # partially completed, matching expectations assert QBT.query.filter(QBT.status == OverallStatus.due).count() == 8 assert QBT.query.filter( QBT.status == OverallStatus.overdue).count() == 8 # should be one less expired as it became partially_completed assert QBT.query.filter( QBT.status == OverallStatus.expired).count() == 7 assert QBT.query.filter(QBT.status == OverallStatus.in_progress).one() assert QBT.query.filter( QBT.status == OverallStatus.partially_completed).one()
def test_change_before_start_rp_w_result(self): now = datetime.utcnow() back7, nowish = associative_backdate( now=now, backdate=relativedelta(months=7)) back14, nowish = associative_backdate( now=now, backdate=relativedelta(months=14)) org = self.setup_org_qbs(rp_name='v2', retired_as_of=back14) org_id = org.id self.setup_org_qbs(org=org, rp_name='v3') self.consent_with_org(org_id=org_id, setdate=back7) # submit a mock response for baseline QB on old RP # which should result in v2 for baseline and v3 thereafter qb_name = "CRV Baseline v2" baseline = QuestionnaireBank.query.filter( QuestionnaireBank.name == qb_name).one() mock_qr('epic_26_v2', qb=baseline, iteration=None) user = db.session.merge(self.test_user) gen = ordered_qbs(user) # expect everything in v3 post baseline expect_baseline = next(gen) assert visit_name(expect_baseline) == 'Baseline' assert ( expect_baseline.questionnaire_bank.research_protocol.name == 'v2') for n in (3, 6, 9, 15, 18, 21, 30): qbd = next(gen) assert visit_name(qbd) == 'Month {}'.format(n) assert qbd.questionnaire_bank.research_protocol.name == 'v3' with pytest.raises(StopIteration): next(gen)
def test_intervention_in_progress(self): # testing intervention-based QBs q = self.add_questionnaire('q') interv = Intervention(name='interv', description='test') with SessionScope(db): db.session.add(interv) db.session.commit() q, interv, self.test_user = map(db.session.merge, (q, interv, self.test_user)) qb = QuestionnaireBank( name='qb', intervention_id=interv.id, classification='baseline', start='{"days": 0}', expired='{"days": 2}') qbq = QuestionnaireBankQuestionnaire(rank=0, questionnaire=q) qb.questionnaires.append(qbq) # user with biopsy should return biopsy date self.login() self.test_user.save_observation( codeable_concept=CC.BIOPSY, value_quantity=CC.TRUE_VALUE, audit=Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID), status='', issued=now) self.promote_user(role_name=ROLE.PATIENT.value) self.test_user = db.session.merge(self.test_user) obs = self.test_user.observations.first() assert obs.codeable_concept.codings[0].display == 'biopsy' assert trigger_date(self.test_user, qb) == obs.issued # add mock in-process QB - confirm current qb is still correct mock_qr('q', 'in-progress', qb=qb) self.test_user, qb = map(db.session.merge, (self.test_user, qb)) qb_stat = QB_Status(user=self.test_user, as_of_date=now) assert qb_stat.current_qbd().questionnaire_bank == qb
def test_completed_input(self): # Basic w/ one complete QB crv = self.setup_org_qbs() self.bless_with_basics() # pick up a consent, etc. self.test_user = db.session.merge(self.test_user) self.test_user.organizations.append(crv) # submit a mock response for all q's in 3 mo qb # which should result in completed status qb_name = "CRV_recurring_3mo_period v2" threeMo = QuestionnaireBank.query.filter( QuestionnaireBank.name == qb_name).one() for q in threeMo.questionnaires: q = db.session.merge(q) mock_qr(q.name, qb=threeMo, iteration=0) self.test_user = db.session.merge(self.test_user) update_users_QBT(TEST_USER_ID) # for the 8 QBs and verify counts # given the partial results, we find one in progress and one # partially completed, matching expectations assert QBT.query.filter(QBT.status == OverallStatus.due).count() == 8 # should be one less overdue as it became in_progress assert QBT.query.filter( QBT.status == OverallStatus.overdue).count() == 7 # should be one less expired as it became partially_completed assert QBT.query.filter( QBT.status == OverallStatus.expired).count() == 7 assert QBT.query.filter(QBT.status == OverallStatus.in_progress).one() assert QBT.query.filter(QBT.status == OverallStatus.completed).one()
def test_partial_post_overdue_input(self): crv = self.setup_org_qbs() self.bless_with_basics() # pick up a consent, etc. self.test_user = db.session.merge(self.test_user) self.test_user.organizations.append(crv) # submit a mock response for 3 month QB after overdue # before expired post_overdue = datetime.now() + relativedelta(months=4, weeks=1) qb_name = "CRV_recurring_3mo_period v2" threeMo = QuestionnaireBank.query.filter( QuestionnaireBank.name == qb_name).one() mock_qr('epic26_v2', qb=threeMo, iteration=0, timestamp=post_overdue) self.test_user = db.session.merge(self.test_user) update_users_QBT(TEST_USER_ID) # for the 8 QBs and verify counts # given the partial results, we find one in progress and one # partially completed, matching expectations assert QBT.query.filter(QBT.status == OverallStatus.due).count() == 8 assert QBT.query.filter( QBT.status == OverallStatus.overdue).count() == 8 # should be one less expired as it became partially_completed assert QBT.query.filter( QBT.status == OverallStatus.expired).count() == 7 assert QBT.query.filter(QBT.status == OverallStatus.in_progress).one() assert QBT.query.filter( QBT.status == OverallStatus.partially_completed).one()
def test_completed_older_rp(self): """If current qb completed on older rp, should show as done""" fourmonthsago = now - timedelta(days=120) weekago = now - timedelta(weeks=1) twoweeksago = now - timedelta(weeks=2) org = self.setup_qbs(rp_name='v2', retired_as_of=weekago) org_id = org.id self.setup_qbs(org=org, rp_name='v3') self.test_user.organizations.append(org) audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID) uc = UserConsent(user_id=TEST_USER_ID, organization_id=org_id, audit=audit, agreement_url='http://no.com', acceptance_date=fourmonthsago) with SessionScope(db): db.session.add(audit) db.session.add(uc) db.session.commit() # Two weeks ago, still on rp v2, should be in 3mo recurrence user = db.session.merge(self.test_user) a_s = AssessmentStatus(user=user, as_of_date=twoweeksago) v2qb = a_s.qb_data.qbd.questionnaire_bank self.assertEqual('CRV_recurring_3mo_period v2', a_s.qb_data.qbd.questionnaire_bank.name) self.assertEqual('CRV_recurring_3mo_period v2', a_s.qb_name) self.assertEqual(['epic26_v2'], a_s.instruments_needing_full_assessment()) # Now, should still be rp v3, 3mo recurrence a_s = AssessmentStatus(user=user, as_of_date=now) self.assertEqual('CRV_recurring_3mo_period v3', a_s.qb_data.qbd.questionnaire_bank.name) self.assertEqual(['epic26_v3'], a_s.instruments_needing_full_assessment()) # Complete the questionnaire from the 3mo v2 QB mock_qr('epic26_v2', timestamp=twoweeksago, qb=v2qb, iteration=0) # Two weeks ago, should be completed user = db.session.merge(user) a_s = AssessmentStatus(user=user, as_of_date=twoweeksago) self.assertEqual('Completed', a_s.overall_status) # Current should also be completed, even tho protocol changed a_s = AssessmentStatus(user=user, as_of_date=now) self.assertEqual('Completed', a_s.overall_status) # Should see both as candidates qbds = QuestionnaireBank.qbs_for_user(user, classification='recurring', as_of_date=now) self.assertEqual(len(qbds), 2)
def test_completed_older_rp(self): """If current qb completed on older rp, should show as done""" fourmonthsago = now - timedelta(days=120) weekago = now - timedelta(weeks=1) twoweeksago = now - timedelta(weeks=2) org = self.setup_org_qbs(rp_name='v2', retired_as_of=weekago) org_id = org.id self.setup_org_qbs(org=org, rp_name='v3') self.promote_user(role_name=ROLE.PATIENT.value) self.test_user = db.session.merge(self.test_user) self.test_user.organizations.append(org) audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID) uc = UserConsent(user_id=TEST_USER_ID, organization_id=org_id, audit=audit, agreement_url='http://no.com', acceptance_date=fourmonthsago) with SessionScope(db): db.session.add(audit) db.session.add(uc) db.session.commit() user = db.session.merge(self.test_user) # Now, should still be rp v3, 3mo recurrence a_s = QB_Status(user=user, as_of_date=now) assert (a_s.current_qbd().questionnaire_bank.name == 'CRV_recurring_3mo_period v3') assert a_s.instruments_needing_full_assessment() == [ 'epic26_v3', 'eortc_v3' ] # Complete the questionnaire from the 3mo v2 QB v2qb = QuestionnaireBank.query.filter( QuestionnaireBank.name == 'CRV_recurring_3mo_period v2').one() mock_qr('epic26_v2', timestamp=twoweeksago, qb=v2qb, iteration=0) mock_qr('eortc_v2', timestamp=twoweeksago, qb=v2qb, iteration=0) # Two weeks ago, should be completed user = db.session.merge(user) a_s = QB_Status(user=user, as_of_date=twoweeksago) assert a_s.overall_status == OverallStatus.completed # Current should also be completed, even tho protocol changed a_s = QB_Status(user=user, as_of_date=now) assert a_s.overall_status == OverallStatus.completed
def test_completed_older_rp(self): """If current qb completed on older rp, should show as done""" fourmonthsago = now - timedelta(days=120) weekago = now - timedelta(weeks=1) twoweeksago = now - timedelta(weeks=2) org = self.setup_org_qbs(rp_name='v2', retired_as_of=weekago) org_id = org.id self.setup_org_qbs(org=org, rp_name='v3') self.promote_user(role_name=ROLE.PATIENT.value) self.test_user = db.session.merge(self.test_user) self.test_user.organizations.append(org) audit = Audit( user_id=TEST_USER_ID, subject_id=TEST_USER_ID) uc = UserConsent( user_id=TEST_USER_ID, organization_id=org_id, audit=audit, agreement_url='http://no.com', acceptance_date=fourmonthsago) with SessionScope(db): db.session.add(audit) db.session.add(uc) db.session.commit() user = db.session.merge(self.test_user) # Now, should still be rp v3, 3mo recurrence a_s = QB_Status(user=user, as_of_date=now) assert (a_s.current_qbd().questionnaire_bank.name == 'CRV_recurring_3mo_period v3') assert a_s.instruments_needing_full_assessment() == [ 'epic26_v3', 'eortc_v3'] # Complete the questionnaire from the 3mo v2 QB v2qb = QuestionnaireBank.query.filter( QuestionnaireBank.name == 'CRV_recurring_3mo_period v2').one() mock_qr('epic26_v2', timestamp=twoweeksago, qb=v2qb, iteration=0) mock_qr('eortc_v2', timestamp=twoweeksago, qb=v2qb, iteration=0) # Two weeks ago, should be completed user = db.session.merge(user) a_s = QB_Status(user=user, as_of_date=twoweeksago) assert a_s.overall_status == OverallStatus.completed # Current should also be completed, even tho protocol changed a_s = QB_Status(user=user, as_of_date=now) assert a_s.overall_status == OverallStatus.completed
def test_st_done(self): # Symptom Tracker QB with completed shouldn't fire mock_communication_request('symptom_tracker', '{"days": 90}') self.promote_user(role_name=ROLE.PATIENT.value) self.login() self.add_required_clinical_data(backdate=relativedelta(days=91)) self.test_user = db.session.merge(self.test_user) # Confirm test user qualifies for ST QB qbstatus = QB_Status(self.test_user, as_of_date=datetime.utcnow()) assert qbstatus.enrolled_in_classification('baseline') for instrument in symptom_tracker_instruments: mock_qr(instrument_id=instrument) # With all q's done, shouldn't generate a message update_patient_loop(update_cache=False, queue_messages=True) expected = Communication.query.first() assert not expected
def test_st_done(self): # Symptom Tracker QB with completed shouldn't fire mock_communication_request('symptom_tracker', '{"days": 90}') self.promote_user(role_name=ROLE.PATIENT.value) self.login() self.add_required_clinical_data(backdate=relativedelta(days=91)) self.test_user = db.session.merge(self.test_user) # Confirm test user qualifies for ST QB qbstatus = QB_Status(self.test_user, as_of_date=datetime.utcnow()) assert qbstatus.enrolled_in_classification('baseline') for instrument in symptom_tracker_instruments: mock_qr(instrument_id=instrument) # With all q's done, shouldn't generate a message update_patient_loop(update_cache=False, queue_messages=True) expected = Communication.query.first() assert not expected
def test_st_undone(self): # Symptom Tracker QB with incompleted should generate communication mock_communication_request('symptom_tracker', '{"days": 30}') self.app.config['NO_CHALLENGE_WO_DATA'] = False self.promote_user(role_name=ROLE.PATIENT.value) self.login() self.add_required_clinical_data(backdate=relativedelta(days=31)) self.test_user = db.session.merge(self.test_user) self.test_user.birthdate = '1969-07-16' # Confirm test user qualifies for ST QB assert QuestionnaireBank.qbs_for_user(self.test_user, 'baseline', as_of_date=datetime.utcnow()) # With most q's undone, should generate a message mock_qr(instrument_id='epic26') a_s, _ = overall_assessment_status(TEST_USER_ID) assert 'In Progress' == a_s update_patient_loop(update_cache=False, queue_messages=True) expected = Communication.query.first() assert expected
def test_change_midstream_results_rp(self): now = datetime.utcnow() back1, nowish = associative_backdate( now=now, backdate=relativedelta(months=1)) back10, nowish = associative_backdate( now=now, backdate=relativedelta(months=10)) org = self.setup_org_qbs(rp_name='v2', retired_as_of=back1) org_id = org.id self.setup_org_qbs(org=org, rp_name='v3') self.consent_with_org(org_id=org_id, setdate=back10) # submit a mock response for 9 month QB on old RP # which should result in v2 for up to 9 month and v3 thereafter qb_name = "CRV_recurring_3mo_period v2" nineMo = QuestionnaireBank.query.filter( QuestionnaireBank.name == qb_name).one() mock_qr('epic_26_v2', qb=nineMo, iteration=1) user = db.session.merge(self.test_user) gen = ordered_qbs(user) # expect baseline and 3 month in v2, rest in v3 expect_baseline = next(gen) assert visit_name(expect_baseline) == 'Baseline' assert ( expect_baseline.questionnaire_bank.research_protocol.name == 'v2') for n in (3, 6, 9): qbd = next(gen) assert visit_name(qbd) == 'Month {}'.format(n) assert qbd.questionnaire_bank.research_protocol.name == 'v2' for n in (15, 18, 21, 30): qbd = next(gen) assert visit_name(qbd) == 'Month {}'.format(n) assert qbd.questionnaire_bank.research_protocol.name == 'v3' with pytest.raises(StopIteration): next(gen)
def test_change_midstream_results_rp(self): now = datetime.utcnow() back1, nowish = associative_backdate(now=now, backdate=relativedelta(months=1)) back10, nowish = associative_backdate( now=now, backdate=relativedelta(months=10)) org = self.setup_org_qbs(rp_name='v2', retired_as_of=back1) org_id = org.id self.setup_org_qbs(org=org, rp_name='v3') self.consent_with_org(org_id=org_id, setdate=back10) # submit a mock response for 9 month QB on old RP # which should result in v2 for up to 9 month and v3 thereafter qb_name = "CRV_recurring_3mo_period v2" nineMo = QuestionnaireBank.query.filter( QuestionnaireBank.name == qb_name).one() mock_qr('epic_26_v2', qb=nineMo, iteration=1) user = db.session.merge(self.test_user) gen = ordered_qbs(user) # expect baseline and 3 month in v2, rest in v3 expect_baseline = next(gen) assert visit_name(expect_baseline) == 'Baseline' assert ( expect_baseline.questionnaire_bank.research_protocol.name == 'v2') for n in (3, 6, 9): qbd = next(gen) assert visit_name(qbd) == 'Month {}'.format(n) assert qbd.questionnaire_bank.research_protocol.name == 'v2' for n in (15, 18, 21, 30): qbd = next(gen) assert visit_name(qbd) == 'Month {}'.format(n) assert qbd.questionnaire_bank.research_protocol.name == 'v3' with pytest.raises(StopIteration): next(gen)
def test_st_undone(self): # Symptom Tracker QB with incompleted should generate communication mock_communication_request('symptom_tracker', '{"days": 30}') self.app.config['NO_CHALLENGE_WO_DATA'] = False self.promote_user(role_name=ROLE.PATIENT.value) self.login() self.add_required_clinical_data(backdate=relativedelta(days=31)) self.test_user = db.session.merge(self.test_user) self.test_user.birthdate = '1969-07-16' # Confirm test user qualifies for ST QB qstats = QB_Status(self.test_user, as_of_date=datetime.utcnow()) assert qstats.enrolled_in_classification('baseline') # With most q's undone, should generate a message mock_qr(instrument_id='epic26') invalidate_users_QBT(TEST_USER_ID) self.test_user = db.session.merge(self.test_user) qstats = QB_Status(self.test_user, as_of_date=datetime.utcnow()) assert OverallStatus.in_progress == qstats.overall_status update_patient_loop(update_cache=False, queue_messages=True) expected = Communication.query.first() assert expected
def test_st_metastatic(self): # Symptom Tracker QB on metastatic patient shouldn't qualify mock_communication_request('symptom_tracker', '{"days": 90}') self.promote_user(role_name=ROLE.PATIENT.value) self.login() self.add_required_clinical_data(backdate=relativedelta(days=91)) self.test_user = db.session.merge(self.test_user) self.test_user.save_observation(codeable_concept=CC.PCaLocalized, value_quantity=CC.FALSE_VALUE, audit=Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID), status='final', issued=None) # Confirm test user doesn't qualify for ST QB assert not QuestionnaireBank.qbs_for_user( self.test_user, 'baseline', as_of_date=datetime.utcnow()) # shouldn't generate a message either mock_qr(instrument_id='epic26') update_patient_loop(update_cache=False, queue_messages=True) expected = Communication.query.first() assert not expected
def test_st_undone(self): # Symptom Tracker QB with incompleted should generate communication mock_communication_request('symptom_tracker', '{"days": 30}') self.app.config['NO_CHALLENGE_WO_DATA'] = False self.promote_user(role_name=ROLE.PATIENT.value) self.login() self.add_required_clinical_data(backdate=relativedelta(days=31)) self.test_user = db.session.merge(self.test_user) self.test_user.birthdate = '1969-07-16' # Confirm test user qualifies for ST QB qstats = QB_Status(self.test_user, as_of_date=datetime.utcnow()) assert qstats.enrolled_in_classification('baseline') # With most q's undone, should generate a message mock_qr(instrument_id='epic26') invalidate_users_QBT(TEST_USER_ID) self.test_user = db.session.merge(self.test_user) qstats = QB_Status(self.test_user, as_of_date=datetime.utcnow()) assert OverallStatus.in_progress == qstats.overall_status update_patient_loop(update_cache=False, queue_messages=True) expected = Communication.query.first() assert expected
def test_intervention_in_progress(self): # testing intervention-based QBs q = self.add_questionnaire('q') interv = Intervention(name='interv', description='test') with SessionScope(db): db.session.add(interv) db.session.commit() q, interv, self.test_user = map(db.session.merge, (q, interv, self.test_user)) qb = QuestionnaireBank(name='qb', intervention_id=interv.id, classification='baseline', start='{"days": 0}', expired='{"days": 2}') qbq = QuestionnaireBankQuestionnaire(rank=0, questionnaire=q) qb.questionnaires.append(qbq) # user with biopsy should return biopsy date self.login() self.test_user.save_observation(codeable_concept=CC.BIOPSY, value_quantity=CC.TRUE_VALUE, audit=Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID), status='', issued=now) self.promote_user(role_name=ROLE.PATIENT.value) self.test_user = db.session.merge(self.test_user) obs = self.test_user.observations.first() assert obs.codeable_concept.codings[0].display == 'biopsy' assert trigger_date(self.test_user, qb) == obs.issued # add mock in-process QB - confirm current qb is still correct mock_qr('q', 'in-progress', qb=qb) self.test_user, qb = map(db.session.merge, (self.test_user, qb)) qb_stat = QB_Status(user=self.test_user, as_of_date=now) assert qb_stat.current_qbd().questionnaire_bank == qb
def test_done_message(self): # At 14 days with all work done, should not generate message mock_communication_request('localized', '{"days": 14}') # Fake a user associated with localized org # and mark all baseline questionnaires as in-progress self.bless_with_basics( backdate=relativedelta(days=14), local_metastatic='localized') mock_qr(instrument_id='eproms_add') mock_qr(instrument_id='epic26') mock_qr(instrument_id='comorb') update_patient_loop(update_cache=False, queue_messages=True) expected = Communication.query.first() assert not expected
def test_done_message(self): # At 14 days with all work done, should not generate message mock_communication_request('localized', '{"days": 14}') # Fake a user associated with localized org # and mark all baseline questionnaires as in-progress self.bless_with_basics(backdate=relativedelta(days=14), local_metastatic='localized') mock_qr(instrument_id='eproms_add') mock_qr(instrument_id='epic26') mock_qr(instrument_id='comorb') update_patient_loop(update_cache=False, queue_messages=True) expected = Communication.query.first() assert not expected
def test_nearready_message(self): # At 13 days with all work in-progress, shouldn't generate message mock_communication_request('localized', '{"days": 14}') # Fake a user associated with localized org # and mark all baseline questionnaires as in-progress self.bless_with_basics(backdate=relativedelta(days=13)) self.promote_user(role_name=ROLE.PATIENT.value) self.mark_localized() mock_qr(instrument_id='eproms_add', status='in-progress') mock_qr(instrument_id='epic26', status='in-progress') mock_qr(instrument_id='comorb', status='in-progress') update_patient_loop(update_cache=False, queue_messages=True) expected = Communication.query.first() assert not expected
def test_ready_message(self): # At 14 days with all work in-progress, should generate message mock_communication_request( 'localized', '{"days": 14}', communication_request_name="Symptom Tracker | 3 Mo Reminder (1)") # Fake a user associated with localized org # and mark all baseline questionnaires as in-progress self.bless_with_basics( backdate=relativedelta(days=14), local_metastatic='localized') mock_qr(instrument_id='eproms_add', status='in-progress') mock_qr(instrument_id='epic26', status='in-progress') mock_qr(instrument_id='comorb', status='in-progress') update_patient_loop(update_cache=False, queue_messages=True) expected = Communication.query.first() assert expected.user_id == TEST_USER_ID
def test_ready_message(self): # At 14 days with all work in-progress, should generate message mock_communication_request( 'localized', '{"days": 14}', communication_request_name="Symptom Tracker | 3 Mo Reminder (1)") # Fake a user associated with localized org # and mark all baseline questionnaires as in-progress self.bless_with_basics(backdate=relativedelta(days=14), local_metastatic='localized') mock_qr(instrument_id='eproms_add', status='in-progress') mock_qr(instrument_id='epic26', status='in-progress') mock_qr(instrument_id='comorb', status='in-progress') update_patient_loop(update_cache=False, queue_messages=True) expected = Communication.query.first() assert expected.user_id == TEST_USER_ID
def test_outdated_inprogress_qb(self): # create base QB/RP org, rp, rp_id = self.setup_org_n_rp(org_name='testorg') qn = self.add_questionnaire(name='epic26') qn, org, self.test_user = map(db.session.merge, (qn, org, self.test_user)) org_id = org.id qb = QuestionnaireBank(name='Test Questionnaire Bank', classification='baseline', research_protocol_id=rp_id, start='{"days": 0}', overdue='{"days": 7}', expired='{"days": 90}') qbq = QuestionnaireBankQuestionnaire(questionnaire=qn, rank=0) qb.questionnaires.append(qbq) self.test_user.organizations.append(org) self.promote_user(role_name=ROLE.PATIENT.value) audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID) uc = UserConsent(user_id=TEST_USER_ID, organization=org, audit=audit, agreement_url='http://no.com', acceptance_date=now) with SessionScope(db): db.session.add(qb) db.session.add(self.test_user) db.session.add(audit) db.session.add(uc) db.session.commit() qb = db.session.merge(qb) # create in-progress QNR for User/QB/RP mock_qr(instrument_id='epic26', status='in-progress', timestamp=now, qb=qb) # User associated with CRV org should generate appropriate # questionnaires self.test_user = db.session.merge(self.test_user) qb_stat = QB_Status(self.test_user, now) qb = qb_stat.current_qbd().questionnaire_bank assert qb.research_protocol.name == 'proto' # Pointing the User's org to a new QB/RP # marking the old RP as retired as of yesterday old_rp = OrganizationResearchProtocol.query.filter( OrganizationResearchProtocol.organization_id == org_id, OrganizationResearchProtocol.research_protocol_id == rp_id).one() old_rp.retired_as_of = now - timedelta(days=1) rp2 = ResearchProtocol(name='new_proto') qn2 = self.add_questionnaire(name='epic27') with SessionScope(db): db.session.add(rp2) db.session.commit() rp2 = db.session.merge(rp2) rp2_id = rp2.id qn2, org = map(db.session.merge, (qn2, org)) qb2 = QuestionnaireBank(name='Test Questionnaire Bank 2', classification='baseline', research_protocol_id=rp2_id, start='{"days": 0}', overdue='{"days": 7}', expired='{"days": 90}') qbq2 = QuestionnaireBankQuestionnaire(questionnaire=qn2, rank=0) qb2.questionnaires.append(qbq2) org.research_protocols.append(rp2) with SessionScope(db): db.session.add(qb2) db.session.add(org) db.session.commit() qb2 = db.session.merge(qb2) # outdated QB/RP should be used as long as User has in-progress QNR self.test_user = db.session.merge(self.test_user) qb_stat = QB_Status(self.test_user, now) qb = qb_stat.current_qbd().questionnaire_bank assert qb.name == 'Test Questionnaire Bank' assert qb.research_protocol.name == 'proto' # completing QNR should result in completed status # shouldn't pick up new protocol till next iteration mock_qr(instrument_id='epic26', status='completed', timestamp=now, qb=qb) self.test_user = db.session.merge(self.test_user) invalidate_users_QBT(TEST_USER_ID) qb_stat = QB_Status(self.test_user, now) qb = qb_stat.current_qbd().questionnaire_bank assert qb.name == 'Test Questionnaire Bank' assert qb_stat.overall_status == OverallStatus.completed
def test_outdated_done_indef(self): """Confirm completed indefinite counts after RP switch""" # boiler plate to create baseline and indef with retired RP yesterday = now - timedelta(days=1) weekago = now - timedelta(weeks=1) org, rp2, rp2_id = self.setup_org_n_rp( org_name='testorg', rp_name='v2', retired_as_of=yesterday) org, rp3, rp3_id = self.setup_org_n_rp(org=org, rp_name='v3') org_id = org.id self.promote_user(role_name=ROLE.PATIENT.value) self.test_user = db.session.merge(self.test_user) self.test_user.organizations.append(org) audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID) uc = UserConsent( user_id=TEST_USER_ID, organization_id=org_id, audit=audit, agreement_url='http://no.com', acceptance_date=weekago) with SessionScope(db): db.session.add(audit) db.session.add(uc) db.session.commit() self.setup_qb( questionnaire_name='epic23', qb_name='baseline v2', classification='baseline', rp_id=rp2_id) self.setup_qb( questionnaire_name='epic26', qb_name='baseline v3', classification='baseline', rp_id=rp3_id) qb2_indef = self.setup_qb( questionnaire_name='irondemog', qb_name='indef v2', classification='indefinite', rp_id=rp2_id) self.setup_qb( questionnaire_name='irondemog_v3', qb_name='indef v3', classification='indefinite', rp_id=rp3_id) # for today, should get the v3 baseline user = db.session.merge(self.test_user) a_s = QB_Status(user=user, as_of_date=now) assert (['epic26', 'irondemog_v3'] == a_s.instruments_needing_full_assessment(classification='all')) # create done QNR for indefinite dated prior to rp transition # belonging to older qb - confirm that clears indef work as of then mock_qr('irondemog', timestamp=weekago, qb=qb2_indef) user = db.session.merge(self.test_user) invalidate_users_QBT(user_id=TEST_USER_ID) a_s = QB_Status(user=user, as_of_date=weekago) assert (a_s.instruments_needing_full_assessment( classification='indefinite') == []) # move forward in time; user should no longer need indefinite, even # tho RP changed qb2_indef = db.session.merge(qb2_indef) a_s = QB_Status(user=user, as_of_date=now) assert qb2_indef == a_s.current_qbd( classification='indefinite').questionnaire_bank assert (a_s.instruments_needing_full_assessment( classification='indefinite') == []) assert (a_s.instruments_needing_full_assessment( classification='all') == ['epic26'])
def test_outdated_inprogress_qb(self): # create base QB/RP org, rp, rp_id = self.setup_org_n_rp(org_name='testorg') qn = self.add_questionnaire(name='epic26') qn, org, self.test_user = map( db.session.merge, (qn, org, self.test_user)) org_id = org.id qb = QuestionnaireBank( name='Test Questionnaire Bank', classification='baseline', research_protocol_id=rp_id, start='{"days": 0}', overdue='{"days": 7}', expired='{"days": 90}') qbq = QuestionnaireBankQuestionnaire(questionnaire=qn, rank=0) qb.questionnaires.append(qbq) self.test_user.organizations.append(org) self.promote_user(role_name=ROLE.PATIENT.value) audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID) uc = UserConsent( user_id=TEST_USER_ID, organization=org, audit=audit, agreement_url='http://no.com', acceptance_date=now) with SessionScope(db): db.session.add(qb) db.session.add(self.test_user) db.session.add(audit) db.session.add(uc) db.session.commit() qb = db.session.merge(qb) # create in-progress QNR for User/QB/RP mock_qr( instrument_id='epic26', status='in-progress', timestamp=now, qb=qb) # User associated with CRV org should generate appropriate # questionnaires self.test_user = db.session.merge(self.test_user) qb_stat = QB_Status(self.test_user, now) qb = qb_stat.current_qbd().questionnaire_bank assert qb.research_protocol.name == 'proto' # Pointing the User's org to a new QB/RP # marking the old RP as retired as of yesterday old_rp = OrganizationResearchProtocol.query.filter( OrganizationResearchProtocol.organization_id == org_id, OrganizationResearchProtocol.research_protocol_id == rp_id).one() old_rp.retired_as_of = now - timedelta(days=1) rp2 = ResearchProtocol(name='new_proto') qn2 = self.add_questionnaire(name='epic27') with SessionScope(db): db.session.add(rp2) db.session.commit() rp2 = db.session.merge(rp2) rp2_id = rp2.id qn2, org = map(db.session.merge, (qn2, org)) qb2 = QuestionnaireBank( name='Test Questionnaire Bank 2', classification='baseline', research_protocol_id=rp2_id, start='{"days": 0}', overdue='{"days": 7}', expired='{"days": 90}') qbq2 = QuestionnaireBankQuestionnaire(questionnaire=qn2, rank=0) qb2.questionnaires.append(qbq2) org.research_protocols.append(rp2) with SessionScope(db): db.session.add(qb2) db.session.add(org) db.session.commit() qb2 = db.session.merge(qb2) # outdated QB/RP should be used as long as User has in-progress QNR self.test_user = db.session.merge(self.test_user) qb_stat = QB_Status(self.test_user, now) qb = qb_stat.current_qbd().questionnaire_bank assert qb.name == 'Test Questionnaire Bank' assert qb.research_protocol.name == 'proto' # completing QNR should result in completed status # shouldn't pick up new protocol till next iteration mock_qr( instrument_id='epic26', status='completed', timestamp=now, qb=qb) self.test_user = db.session.merge(self.test_user) invalidate_users_QBT(TEST_USER_ID) qb_stat = QB_Status(self.test_user, now) qb = qb_stat.current_qbd().questionnaire_bank assert qb.name == 'Test Questionnaire Bank' assert qb_stat.overall_status == OverallStatus.completed
def test_results(self): from portal.system_uri import TRUENTH_EXTERNAL_STUDY_SYSTEM # Generate a few patients with differing results org = self.setup_org_qbs() org_id, org_name = org.id, org.name user2 = self.add_user('user2') user3 = self.add_user('user3') user4 = self.add_user('user4') with SessionScope(db): db.session.add(user2) db.session.add(user3) db.session.add(user4) db.session.commit() user2 = db.session.merge(user2) user3 = db.session.merge(user3) user4 = db.session.merge(user4) user4_id = user4.id self.add_user_identifier( user=user2, system=TRUENTH_EXTERNAL_STUDY_SYSTEM, value='study user 2') self.add_user_identifier( user=user3, system=TRUENTH_EXTERNAL_STUDY_SYSTEM, value='study user 3') now = datetime.utcnow() back15, nowish = associative_backdate(now, relativedelta(days=15)) back45, nowish = associative_backdate(now, relativedelta(days=45)) back115, nowish = associative_backdate(now, relativedelta(days=115)) self.bless_with_basics( user=user2, setdate=back15, local_metastatic=org_name) self.bless_with_basics( user=user3, setdate=back45, local_metastatic=org_name) self.bless_with_basics( user=user4, setdate=back115, local_metastatic=org_name) # submit a mock response for all q's in 3 mo qb # which should result in completed status for user4 qb_name = "CRV_recurring_3mo_period v2" threeMo = QuestionnaireBank.query.filter( QuestionnaireBank.name == qb_name).one() for q in threeMo.questionnaires: q = db.session.merge(q) mock_qr( q.name, qb=threeMo, iteration=0, user_id=user4_id, timestamp=back15, entry_method=EC.INTERVIEW_ASSISTED) self.test_user = db.session.merge(self.test_user) self.promote_user(role_name=ROLE.STAFF.value) self.consent_with_org(org_id=org_id) self.login() response = self.client.get("/api/report/questionnaire_status") assert response.status_code == 200 # expect baseline for each plus 3 mo for user4 assert response.json['total'] == 4 expect = {'Due', 'Overdue', 'Completed', 'Expired'} found = set([item['status'] for item in response.json['entry']]) assert expect == found # the one done should have entry method set above for item in response.json['entry']: if item['status'] == 'Completed': assert item['entry_method'] == 'interview_assisted' else: assert 'entry_method' not in item
def test_results(self): from portal.system_uri import TRUENTH_EXTERNAL_STUDY_SYSTEM # Generate a few patients with differing results org = self.setup_org_qbs() org_id, org_name = org.id, org.name user2 = self.add_user('user2') user3 = self.add_user('user3') user4 = self.add_user('user4') with SessionScope(db): db.session.add(user2) db.session.add(user3) db.session.add(user4) db.session.commit() user2 = db.session.merge(user2) user3 = db.session.merge(user3) user4 = db.session.merge(user4) user4_id = user4.id self.add_user_identifier(user=user2, system=TRUENTH_EXTERNAL_STUDY_SYSTEM, value='study user 2') self.add_user_identifier(user=user3, system=TRUENTH_EXTERNAL_STUDY_SYSTEM, value='study user 3') now = datetime.utcnow() back15, nowish = associative_backdate(now, relativedelta(days=15)) back45, nowish = associative_backdate(now, relativedelta(days=45)) back115, nowish = associative_backdate(now, relativedelta(days=115)) self.bless_with_basics(user=user2, setdate=back15, local_metastatic=org_name) self.bless_with_basics(user=user3, setdate=back45, local_metastatic=org_name) self.bless_with_basics(user=user4, setdate=back115, local_metastatic=org_name) # submit a mock response for all q's in 3 mo qb # which should result in completed status for user4 qb_name = "CRV_recurring_3mo_period v2" threeMo = QuestionnaireBank.query.filter( QuestionnaireBank.name == qb_name).one() for q in threeMo.questionnaires: q = db.session.merge(q) mock_qr(q.name, qb=threeMo, iteration=0, user_id=user4_id, timestamp=back15) self.test_user = db.session.merge(self.test_user) self.promote_user(role_name=ROLE.STAFF.value) self.consent_with_org(org_id=org_id) self.login() response = self.client.get("/api/report/questionnaire_status") assert response.status_code == 200 # expect baseline for each plus 3 mo for user4 assert response.json['total'] == 4 expect = {'Due', 'Overdue', 'Completed', 'Expired'} found = set([item['status'] for item in response.json['entry']]) assert expect == found
def test_outdated_done_indef(self): """Confirm completed indefinite counts after RP switch""" # boiler plate to create baseline and indef with retired RP yesterday = now - timedelta(days=1) weekago = now - timedelta(weeks=1) org, rp2, rp2_id = self.setup_org_n_rp(org_name='testorg', rp_name='v2', retired_as_of=yesterday) org, rp3, rp3_id = self.setup_org_n_rp(org=org, rp_name='v3') org_id = org.id self.promote_user(role_name=ROLE.PATIENT.value) self.test_user = db.session.merge(self.test_user) self.test_user.organizations.append(org) audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID) uc = UserConsent(user_id=TEST_USER_ID, organization_id=org_id, audit=audit, agreement_url='http://no.com', acceptance_date=weekago) with SessionScope(db): db.session.add(audit) db.session.add(uc) db.session.commit() self.setup_qb(questionnaire_name='epic23', qb_name='baseline v2', classification='baseline', rp_id=rp2_id) self.setup_qb(questionnaire_name='epic26', qb_name='baseline v3', classification='baseline', rp_id=rp3_id) qb2_indef = self.setup_qb(questionnaire_name='irondemog', qb_name='indef v2', classification='indefinite', rp_id=rp2_id) self.setup_qb(questionnaire_name='irondemog_v3', qb_name='indef v3', classification='indefinite', rp_id=rp3_id) # for today, should get the v3 baseline user = db.session.merge(self.test_user) a_s = QB_Status(user=user, as_of_date=now) assert ([ 'epic26', 'irondemog_v3' ] == a_s.instruments_needing_full_assessment(classification='all')) # create done QNR for indefinite dated prior to rp transition # belonging to older qb - confirm that clears indef work as of then mock_qr('irondemog', timestamp=weekago, qb=qb2_indef) user = db.session.merge(self.test_user) invalidate_users_QBT(user_id=TEST_USER_ID) a_s = QB_Status(user=user, as_of_date=weekago) assert (a_s.instruments_needing_full_assessment( classification='indefinite') == []) # move forward in time; user should no longer need indefinite, even # tho RP changed qb2_indef = db.session.merge(qb2_indef) a_s = QB_Status(user=user, as_of_date=now) assert qb2_indef == a_s.current_qbd( classification='indefinite').questionnaire_bank assert (a_s.instruments_needing_full_assessment( classification='indefinite') == []) assert (a_s.instruments_needing_full_assessment( classification='all') == ['epic26'])
def test_card_html_update(self): """Test strategy with side effects - card_html update""" ae = INTERVENTION.ASSESSMENT_ENGINE ae_id = ae.id self.bless_with_basics() # generate questionnaire banks and associate user with # metastatic organization mock_questionnairebanks() metastatic_org = Organization.query.filter_by(name='metastatic').one() self.test_user.organizations.append(metastatic_org) with SessionScope(db): d = {'function': 'update_card_html_on_completion', 'kwargs': []} strat = AccessStrategy( name="update assessment_engine card_html on completion", intervention_id=ae_id, function_details=json.dumps(d)) db.session.add(strat) db.session.commit() user, ae = map(db.session.merge, (self.test_user, ae)) # without completing an assessment, card_html should includ username self.assertTrue( user.display_name in ae.display_for_user(user).card_html) # Add a fake assessments and see a change mock_qr(user_id=TEST_USER_ID, instrument_id='eortc') mock_qr(user_id=TEST_USER_ID, instrument_id='ironmisc') mock_qr(user_id=TEST_USER_ID, instrument_id='factfpsi') mock_qr(user_id=TEST_USER_ID, instrument_id='epic26') mock_qr(user_id=TEST_USER_ID, instrument_id='prems') mock_qr(user_id=TEST_USER_ID, instrument_id='irondemog') user, ae = map(db.session.merge, (self.test_user, ae)) self.assertTrue("Thank you" in ae.display_for_user(user).card_html)