def test_auto_pair_called(self): pid_numeric = from_client_participant_id(self.participant_id) participant_dao = ParticipantDao() self.send_consent(self.participant_id) self.send_consent(self.participant_id_2) self.assertEquals(participant_dao.get(pid_numeric).hpoId, UNSET_HPO_ID) self._insert_measurements(datetime.datetime.utcnow().isoformat()) self.assertNotEqual(participant_dao.get(pid_numeric).hpoId, UNSET_HPO_ID)
def test_metrics_redaction(self): self._create_data() with FakeClock(TIME): PublicMetricsExport.export('123') # Withdraw particpant. pdao = ParticipantDao() p1 = pdao.get(1) p1.withdrawalStatus = WithdrawalStatus.NO_USE pdao.update(p1) PublicMetricsExport.export('123') self.assert_total_count_per_key(2) # now, 2 qualified participants
class MySqlReconciliationTest(FlaskTestBase): """Biobank samples pipeline tests requiring slower MySQL (not SQLite).""" def setUp(self): super(MySqlReconciliationTest, self).setUp(use_mysql=True) self.participant_dao = ParticipantDao() self.summary_dao = ParticipantSummaryDao() self.order_dao = BiobankOrderDao() self.sample_dao = BiobankStoredSampleDao() def _withdraw(self, participant, withdrawal_time): with FakeClock(withdrawal_time): participant.withdrawalStatus = WithdrawalStatus.NO_USE self.participant_dao.update(participant) def _insert_participant(self, race_codes=[]): participant = self.participant_dao.insert(Participant()) # satisfies the consent requirement self.summary_dao.insert(self.participant_summary(participant)) if race_codes: self._submit_race_questionnaire_response( to_client_participant_id(participant.participantId), race_codes) return participant def _insert_order(self, participant, order_id, tests, order_time, finalized_tests=None, kit_id=None, tracking_number=None): order = BiobankOrder(biobankOrderId=order_id, participantId=participant.participantId, sourceSiteId=1, finalizedSiteId=1, finalizedUsername='******', created=order_time, samples=[]) id_1 = BiobankOrderIdentifier( system="https://orders.mayomedicallaboratories.com", value=order_id) id_2 = BiobankOrderIdentifier(system="https://www.pmi-ops.org", value='O%s' % order_id) order.identifiers.append(id_1) order.identifiers.append(id_2) if kit_id: order.identifiers.append( BiobankOrderIdentifier(system=_KIT_ID_SYSTEM, value=kit_id)) if tracking_number: order.identifiers.append( BiobankOrderIdentifier(system=_TRACKING_NUMBER_SYSTEM, value=tracking_number)) for test_code in tests: finalized_time = order_time if finalized_tests and not test_code in finalized_tests: finalized_time = None order.samples.append( BiobankOrderedSample(biobankOrderId=order.biobankOrderId, test=test_code, description=u'test', processingRequired=False, collected=order_time, processed=order_time, finalized=finalized_time)) return self.order_dao.insert(order) def _insert_samples(self, participant, tests, sample_ids, confirmed_time, created_time): for test_code, sample_id in zip(tests, sample_ids): self.sample_dao.insert( BiobankStoredSample(biobankStoredSampleId=sample_id, biobankId=participant.biobankId, test=test_code, confirmed=confirmed_time, created=created_time)) def _submit_race_questionnaire_response(self, participant_id, race_answers): code_answers = [] for answer in race_answers: _add_code_answer(code_answers, "race", answer) qr = make_questionnaire_response_json(participant_id, self._questionnaire_id, code_answers=code_answers) self.send_post('Participant/%s/QuestionnaireResponse' % participant_id, qr) def test_reconciliation_query(self): self.setup_codes([RACE_QUESTION_CODE], CodeType.QUESTION) self.setup_codes([RACE_AIAN_CODE, RACE_WHITE_CODE], CodeType.ANSWER) self._questionnaire_id = self.create_questionnaire( 'questionnaire3.json') # MySQL and Python sub-second rounding differs, so trim micros from generated times. order_time = clock.CLOCK.now().replace(microsecond=0) old_order_time = order_time - datetime.timedelta(days=10) within_24_hours = order_time + datetime.timedelta(hours=23) old_within_24_hours = old_order_time + datetime.timedelta(hours=23) late_time = order_time + datetime.timedelta(hours=25) old_late_time = old_order_time + datetime.timedelta(hours=25) file_time = order_time + datetime.timedelta( hours=23) + datetime.timedelta(minutes=59) two_days_ago = file_time - datetime.timedelta(days=2) # On time, recent order and samples; shows up in rx p_on_time = self._insert_participant() # Extra samples ordered now aren't considered missing or late. self._insert_order(p_on_time, 'GoodOrder', BIOBANK_TESTS[:4], order_time, finalized_tests=BIOBANK_TESTS[:3], kit_id='kit1', tracking_number='t1') self._insert_samples(p_on_time, BIOBANK_TESTS[:2], ['GoodSample1', 'GoodSample2'], within_24_hours, within_24_hours - datetime.timedelta(hours=1)) # On time order and samples from 10 days ago; shows up in rx p_old_on_time = self._insert_participant(race_codes=[RACE_AIAN_CODE]) # Old missing samples from 10 days ago don't show up in missing or late. self._insert_order(p_old_on_time, 'OldGoodOrder', BIOBANK_TESTS[:3], old_order_time, kit_id='kit2') self._insert_samples(p_old_on_time, BIOBANK_TESTS[:2], ['OldGoodSample1', 'OldGoodSample2'], old_within_24_hours, old_within_24_hours - datetime.timedelta(hours=1)) # Late, recent order and samples; shows up in rx and late. (But not missing, as it hasn't been # 24 hours since the order.) p_late_and_missing = self._insert_participant() # Extra missing sample doesn't show up as missing as it hasn't been 24 hours yet. o_late_and_missing = self._insert_order(p_late_and_missing, 'SlowOrder', BIOBANK_TESTS[:3], order_time) self._insert_samples(p_late_and_missing, [BIOBANK_TESTS[0]], ['LateSample'], late_time, late_time - datetime.timedelta(minutes=59)) # Late order and samples from 10 days ago; shows up in rx (but not missing, as it was too # long ago. p_old_late_and_missing = self._insert_participant() self._insert_order(p_old_late_and_missing, 'OldSlowOrder', BIOBANK_TESTS[:2], old_order_time) self._insert_samples(p_old_late_and_missing, [BIOBANK_TESTS[0]], ['OldLateSample'], old_late_time, old_late_time - datetime.timedelta(minutes=59)) # Order with missing sample from 2 days ago; shows up in rx and missing. p_two_days_missing = self._insert_participant() # The third test doesn't wind up in missing, as it was never finalized. self._insert_order(p_two_days_missing, 'TwoDaysMissingOrder', BIOBANK_TESTS[:3], two_days_ago, finalized_tests=BIOBANK_TESTS[:2]) # Recent samples with no matching order; shows up in missing. p_extra = self._insert_participant(race_codes=[RACE_WHITE_CODE]) self._insert_samples(p_extra, [BIOBANK_TESTS[-1]], ['NobodyOrderedThisSample'], order_time, order_time - datetime.timedelta(minutes=59)) # Old samples with no matching order; shows up in rx. p_old_extra = self._insert_participant(race_codes=[RACE_AIAN_CODE]) self._insert_samples(p_old_extra, [BIOBANK_TESTS[-1]], ['OldNobodyOrderedThisSample'], old_order_time, old_order_time - datetime.timedelta(hours=1)) # Withdrawn participants don't show up in any reports except withdrawal report. p_withdrawn_old_on_time = self._insert_participant( race_codes=[RACE_AIAN_CODE]) # This updates the version of the participant and its HPO ID. self._insert_order(p_withdrawn_old_on_time, 'OldWithdrawnGoodOrder', BIOBANK_TESTS[:2], old_order_time) p_withdrawn_old_on_time = self.participant_dao.get( p_withdrawn_old_on_time.participantId) self._insert_samples( p_withdrawn_old_on_time, BIOBANK_TESTS[:2], ['OldWithdrawnGoodSample1', 'OldWithdrawnGoodSample2'], old_within_24_hours, old_within_24_hours - datetime.timedelta(hours=1)) self._withdraw(p_withdrawn_old_on_time, within_24_hours) p_withdrawn_late_and_missing = self._insert_participant() self._insert_order(p_withdrawn_late_and_missing, 'WithdrawnSlowOrder', BIOBANK_TESTS[:2], order_time) self._insert_samples(p_withdrawn_late_and_missing, [BIOBANK_TESTS[0]], ['WithdrawnLateSample'], late_time, late_time - datetime.timedelta(minutes=59)) p_withdrawn_late_and_missing = (self.participant_dao.get( p_withdrawn_late_and_missing.participantId)) self._withdraw(p_withdrawn_late_and_missing, within_24_hours) p_withdrawn_old_late_and_missing = self._insert_participant() self._insert_order(p_withdrawn_old_late_and_missing, 'WithdrawnOldSlowOrder', BIOBANK_TESTS[:2], old_order_time) self._insert_samples(p_withdrawn_old_late_and_missing, [BIOBANK_TESTS[0]], ['WithdrawnOldLateSample'], old_late_time, old_late_time - datetime.timedelta(minutes=59)) p_withdrawn_old_late_and_missing = (self.participant_dao.get( p_withdrawn_old_late_and_missing.participantId)) self._withdraw(p_withdrawn_old_late_and_missing, old_late_time) p_withdrawn_extra = self._insert_participant( race_codes=[RACE_WHITE_CODE]) self._insert_samples(p_withdrawn_extra, [BIOBANK_TESTS[-1]], ['WithdrawnNobodyOrderedThisSample'], order_time, order_time - datetime.timedelta(hours=1)) self._withdraw(p_withdrawn_extra, within_24_hours) p_withdrawn_old_extra = self._insert_participant( race_codes=[RACE_AIAN_CODE]) self._insert_samples(p_withdrawn_old_extra, [BIOBANK_TESTS[-1]], ['WithdrawnOldNobodyOrderedThisSample'], old_order_time, old_order_time - datetime.timedelta(hours=1)) self._withdraw(p_withdrawn_old_extra, within_24_hours) p_withdrawn_race_change = self._insert_participant( race_codes=[RACE_AIAN_CODE]) p_withdrawn_race_change_id = to_client_participant_id( p_withdrawn_race_change.participantId) self._submit_race_questionnaire_response(p_withdrawn_race_change_id, [RACE_WHITE_CODE]) self._withdraw(p_withdrawn_race_change, within_24_hours) # for the same participant/test, 3 orders sent and only 2 samples received. Shows up in both # missing (we are missing one sample) and late (the two samples that were received were after # 24 hours.) p_repeated = self._insert_participant() for repetition in xrange(3): self._insert_order( p_repeated, 'RepeatedOrder%d' % repetition, [BIOBANK_TESTS[0]], two_days_ago + datetime.timedelta(hours=repetition)) if repetition != 2: self._insert_samples( p_repeated, [BIOBANK_TESTS[0]], ['RepeatedSample%d' % repetition], within_24_hours + datetime.timedelta(hours=repetition), within_24_hours + datetime.timedelta(hours=repetition - 1)) received, late, missing, withdrawals = 'rx.csv', 'late.csv', 'missing.csv', 'withdrawals.csv' exporter = InMemorySqlExporter(self) biobank_samples_pipeline._query_and_write_reports( exporter, file_time, received, late, missing, withdrawals) exporter.assertFilesEqual((received, late, missing, withdrawals)) # sent-and-received: 4 on-time, 2 late, none of the missing/extra/repeated ones; # includes orders/samples from more than 7 days ago exporter.assertRowCount(received, 6) exporter.assertColumnNamesEqual(received, _CSV_COLUMN_NAMES) row = exporter.assertHasRow( received, { 'biobank_id': to_client_biobank_id(p_on_time.biobankId), 'sent_test': BIOBANK_TESTS[0], 'received_test': BIOBANK_TESTS[0] }) # Also check the values of all remaining fields on one row. self.assertEquals(row['source_site_name'], 'Monroeville Urgent Care Center') self.assertEquals(row['source_site_consortium'], 'Pittsburgh') self.assertEquals(row['source_site_mayolink_client_number'], '7035769') self.assertEquals(row['source_site_hpo'], 'PITT') self.assertEquals(row['source_site_hpo_type'], 'HPO') self.assertEquals(row['finalized_site_name'], 'Monroeville Urgent Care Center') self.assertEquals(row['finalized_site_consortium'], 'Pittsburgh') self.assertEquals(row['finalized_site_mayolink_client_number'], '7035769') self.assertEquals(row['finalized_site_hpo'], 'PITT') self.assertEquals(row['finalized_site_hpo_type'], 'HPO') self.assertEquals(row['finalized_username'], '*****@*****.**') self.assertEquals(row['sent_finalized_time'], database_utils.format_datetime(order_time)) self.assertEquals(row['sent_collection_time'], database_utils.format_datetime(order_time)) self.assertEquals(row['sent_processed_time'], database_utils.format_datetime(order_time)) self.assertEquals(row['received_time'], database_utils.format_datetime(within_24_hours)) self.assertEquals( row['Sample Family Create Date'], database_utils.format_datetime(within_24_hours - datetime.timedelta(hours=1))) self.assertEquals(row['sent_count'], '1') self.assertEquals(row['received_count'], '1') self.assertEquals(row['sent_order_id'], 'OGoodOrder') self.assertEquals(row['received_sample_id'], 'GoodSample1') self.assertEquals(row['biospecimen_kit_id'], 'kit1') self.assertEquals(row['fedex_tracking_number'], 't1') # the other sent-and-received rows exporter.assertHasRow( received, { 'biobank_id': to_client_biobank_id(p_on_time.biobankId), 'sent_test': BIOBANK_TESTS[1] }) exporter.assertHasRow( received, { 'biobank_id': to_client_biobank_id( p_late_and_missing.biobankId), 'sent_test': BIOBANK_TESTS[0] }) exporter.assertHasRow( received, { 'biobank_id': to_client_biobank_id(p_old_on_time.biobankId), 'sent_test': BIOBANK_TESTS[0] }) exporter.assertHasRow( received, { 'biobank_id': to_client_biobank_id(p_old_on_time.biobankId), 'sent_test': BIOBANK_TESTS[1] }) exporter.assertHasRow( received, { 'biobank_id': to_client_biobank_id(p_old_late_and_missing.biobankId), 'sent_test': BIOBANK_TESTS[0] }) # sent-and-received: 2 late; don't include orders/samples from more than 7 days ago exporter.assertRowCount(late, 2) exporter.assertColumnNamesEqual(late, _CSV_COLUMN_NAMES) exporter.assertHasRow( late, { 'biobank_id': to_client_biobank_id( p_late_and_missing.biobankId), 'sent_order_id': 'O%s' % o_late_and_missing.biobankOrderId, 'elapsed_hours': '24' }) exporter.assertHasRow( late, { 'biobank_id': to_client_biobank_id(p_repeated.biobankId), 'elapsed_hours': '45' }) # orders/samples where something went wrong; don't include orders/samples from more than 7 # days ago, or where 24 hours hasn't elapsed yet. exporter.assertRowCount(missing, 4) exporter.assertColumnNamesEqual(missing, _CSV_COLUMN_NAMES) # sample received, nothing ordered exporter.assertHasRow( missing, { 'biobank_id': to_client_biobank_id(p_extra.biobankId), 'sent_order_id': '' }) # order received, no sample exporter.assertHasRow( missing, { 'biobank_id': to_client_biobank_id( p_two_days_missing.biobankId), 'sent_order_id': 'OTwoDaysMissingOrder', 'sent_test': BIOBANK_TESTS[0] }) exporter.assertHasRow( missing, { 'biobank_id': to_client_biobank_id( p_two_days_missing.biobankId), 'sent_order_id': 'OTwoDaysMissingOrder', 'sent_test': BIOBANK_TESTS[1] }) # 3 orders sent, only 2 received multi_sample_row = exporter.assertHasRow( missing, { 'biobank_id': to_client_biobank_id(p_repeated.biobankId), 'sent_count': '3', 'received_count': '2' }) # Also verify the comma-joined fields of the row with multiple orders/samples. self.assertItemsEqual( multi_sample_row['sent_order_id'].split(','), ['ORepeatedOrder1', 'ORepeatedOrder0', 'ORepeatedOrder2']) self.assertItemsEqual( multi_sample_row['received_sample_id'].split(','), ['RepeatedSample0', 'RepeatedSample1']) # We don't include the old withdrawal. exporter.assertRowCount(withdrawals, 5) exporter.assertHasRow( withdrawals, { 'biobank_id': to_client_biobank_id(p_withdrawn_old_on_time.biobankId), 'withdrawal_time': database_utils.format_datetime(within_24_hours), 'is_native_american': 'Y' }) exporter.assertHasRow( withdrawals, { 'biobank_id': to_client_biobank_id(p_withdrawn_late_and_missing.biobankId), 'withdrawal_time': database_utils.format_datetime(within_24_hours), 'is_native_american': 'N' }) exporter.assertHasRow( withdrawals, { 'biobank_id': to_client_biobank_id( p_withdrawn_extra.biobankId), 'withdrawal_time': database_utils.format_datetime(within_24_hours), 'is_native_american': 'N' }) exporter.assertHasRow( withdrawals, { 'biobank_id': to_client_biobank_id( p_withdrawn_old_extra.biobankId), 'withdrawal_time': database_utils.format_datetime(within_24_hours), 'is_native_american': 'Y' }) exporter.assertHasRow( withdrawals, { 'biobank_id': to_client_biobank_id(p_withdrawn_race_change.biobankId), 'withdrawal_time': database_utils.format_datetime(within_24_hours), 'is_native_american': 'N' })
class ParticipantDaoTest(SqlTestBase): def setUp(self): super(ParticipantDaoTest, self).setUp() self.dao = ParticipantDao() self.participant_summary_dao = ParticipantSummaryDao() self.participant_history_dao = ParticipantHistoryDao() def test_get_before_insert(self): self.assertIsNone(self.dao.get(1)) self.assertIsNone(self.participant_summary_dao.get(1)) self.assertIsNone(self.participant_history_dao.get([1, 1])) def test_insert(self): p = Participant() time = datetime.datetime(2016, 1, 1) with random_ids([1, 2]): with FakeClock(time): self.dao.insert(p) expected_participant = self._participant_with_defaults( participantId=1, version=1, biobankId=2, lastModified=time, signUpTime=time) self.assertEquals(expected_participant.asdict(), p.asdict()) p2 = self.dao.get(1) self.assertEquals(p.asdict(), p2.asdict()) # Creating a participant also creates a ParticipantHistory row, but not a ParticipantSummary row ps = self.participant_summary_dao.get(1) self.assertIsNone(ps) ph = self.participant_history_dao.get([1, 1]) expected_ph = self._participant_history_with_defaults( participantId=1, biobankId=2, lastModified=time, signUpTime=time) self.assertEquals(expected_ph.asdict(), ph.asdict()) def test_insert_with_external_id(self): p = Participant(externalId=3) time = datetime.datetime(2016, 1, 1) with random_ids([1, 2]): with FakeClock(time): self.dao.insert(p) expected_participant = self._participant_with_defaults( participantId=1, externalId=3, version=1, biobankId=2, lastModified=time, signUpTime=time) self.assertEquals(expected_participant.asdict(), p.asdict()) p2 = self.dao.get(1) self.assertEquals(p.asdict(), p2.asdict()) # Creating a participant also creates a ParticipantHistory row, but not a ParticipantSummary row ps = self.participant_summary_dao.get(1) self.assertIsNone(ps) ph = self.participant_history_dao.get([1, 1]) expected_ph = self._participant_history_with_defaults( participantId=1, externalId=3, biobankId=2, lastModified=time, signUpTime=time) self.assertEquals(expected_ph.asdict(), ph.asdict()) def test_insert_duplicate_participant_id_retry(self): p = Participant() with random_ids([1, 2]): self.dao.insert(p) p2 = Participant() time = datetime.datetime(2016, 1, 1) with random_ids([1, 3, 2, 3]): with FakeClock(time): p2 = self.dao.insert(p2) expected_participant = self._participant_with_defaults( participantId=2, version=1, biobankId=3, lastModified=time, signUpTime=time) self.assertEquals(expected_participant.asdict(), p2.asdict()) def test_insert_duplicate_participant_id_give_up(self): p = Participant() with random_ids([1, 2]): self.dao.insert(p) rand_ints = [] for i in range(0, MAX_INSERT_ATTEMPTS): rand_ints.append(1) rand_ints.append(i) p2 = Participant() with random_ids(rand_ints): with self.assertRaises(ServiceUnavailable): self.dao.insert(p2) def test_insert_duplicate_biobank_id_give_up(self): p = Participant() with random_ids([1, 2]): self.dao.insert(p) rand_ints = [] for i in range(0, MAX_INSERT_ATTEMPTS): rand_ints.append(i + 2) rand_ints.append(2) p2 = Participant() with random_ids(rand_ints): with self.assertRaises(ServiceUnavailable): self.dao.insert(p2) def test_update_no_expected_version_no_ps(self): p = Participant() time = datetime.datetime(2016, 1, 1) with random_ids([1, 2]): with FakeClock(time): self.dao.insert(p) p.providerLink = make_primary_provider_link_for_name('PITT') time2 = datetime.datetime(2016, 1, 2) with FakeClock(time2): self.dao.update(p) # lastModified, hpoId, version is updated on p after being passed in p2 = self.dao.get(1) expected_participant = self._participant_with_defaults( participantId=1, version=2, biobankId=2, lastModified=time2, signUpTime=time, hpoId=PITT_HPO_ID, providerLink=p2.providerLink) self.assertEquals(expected_participant.asdict(), p2.asdict()) self.assertEquals(p.asdict(), p2.asdict()) ps = self.participant_summary_dao.get(1) self.assertIsNone(ps) expected_ph = self._participant_history_with_defaults( participantId=1, biobankId=2, lastModified=time, signUpTime=time) # Updating the participant adds a new ParticipantHistory row. ph = self.participant_history_dao.get([1, 1]) self.assertEquals(expected_ph.asdict(), ph.asdict()) ph2 = self.participant_history_dao.get([1, 2]) expected_ph2 = self._participant_history_with_defaults( participantId=1, version=2, biobankId=2, lastModified=time2, signUpTime=time, hpoId=PITT_HPO_ID, providerLink=p2.providerLink) self.assertEquals(expected_ph2.asdict(), ph2.asdict()) def test_update_no_expected_version_with_ps(self): p = Participant() time = datetime.datetime(2016, 1, 1) with random_ids([1, 2]): with FakeClock(time): self.dao.insert(p) p.providerLink = make_primary_provider_link_for_name('PITT') time2 = datetime.datetime(2016, 1, 2) with FakeClock(time2): self.dao.update(p) summary = self.participant_summary(p) self.participant_summary_dao.insert(summary) # lastModified, hpoId, version is updated on p after being passed in p2 = self.dao.get(1) expected_participant = self._participant_with_defaults( participantId=1, version=2, biobankId=2, lastModified=time2, signUpTime=time, hpoId=PITT_HPO_ID, providerLink=p2.providerLink) self.assertEquals(expected_participant.asdict(), p2.asdict()) self.assertEquals(p.asdict(), p2.asdict()) # Updating the participant provider link also updates the HPO ID on the participant summary. ps = self.participant_summary_dao.get(1) expected_ps = self._participant_summary_with_defaults( participantId=1, biobankId=2, signUpTime=time, hpoId=PITT_HPO_ID, lastModified=time2, firstName=summary.firstName, lastName=summary.lastName, email=summary.email) self.assertEquals(expected_ps.asdict(), ps.asdict()) p2_last_modified = p2.lastModified p2.hpoId = 2 self.dao.update(p2) p2_update = self.dao.get(1) self.assertNotEquals(p2_last_modified, p2_update.lastModified) self.assertEquals(p2_update.lastModified, p2.lastModified) expected_ph = self._participant_history_with_defaults( participantId=1, biobankId=2, lastModified=time, signUpTime=time) # And updating the participant adds a new ParticipantHistory row. ph = self.participant_history_dao.get([1, 1]) self.assertEquals(expected_ph.asdict(), ph.asdict()) ph2 = self.participant_history_dao.get([1, 2]) expected_ph2 = self._participant_history_with_defaults( participantId=1, version=2, biobankId=2, lastModified=time2, signUpTime=time, hpoId=PITT_HPO_ID, providerLink=p2.providerLink) self.assertEquals(expected_ph2.asdict(), ph2.asdict()) def test_update_right_expected_version(self): p = Participant() time = datetime.datetime(2016, 1, 1) with random_ids([1, 2]): with FakeClock(time): self.dao.insert(p) p.version = 1 p.providerLink = make_primary_provider_link_for_name('PITT') time2 = datetime.datetime(2016, 1, 2) with FakeClock(time2): self.dao.update(p) p2 = self.dao.get(1) expected_participant = self._participant_with_defaults( participantId=1, version=2, biobankId=2, lastModified=time2, signUpTime=time, hpoId=PITT_HPO_ID, providerLink=p2.providerLink) self.assertEquals(expected_participant.asdict(), p2.asdict()) def test_update_withdraw(self): p = Participant() time = datetime.datetime(2016, 1, 1) with random_ids([1, 2]): with FakeClock(time): self.dao.insert(p) p.version = 1 p.withdrawalStatus = WithdrawalStatus.NO_USE time2 = datetime.datetime(2016, 1, 2) with FakeClock(time2): self.dao.update(p) p2 = self.dao.get(1) expected_participant = self._participant_with_defaults( participantId=1, version=2, biobankId=2, lastModified=time2, signUpTime=time, withdrawalStatus=WithdrawalStatus.NO_USE, withdrawalTime=time2) self.assertEquals(expected_participant.asdict(), p2.asdict()) p.version = 2 p.providerLink = make_primary_provider_link_for_name('PITT') p.withdrawalTime = None time3 = datetime.datetime(2016, 1, 3) with FakeClock(time3): self.dao.update(p) # Withdrawal time should get copied over. p2 = self.dao.get(1) expected_participant = self._participant_with_defaults( participantId=1, version=3, biobankId=2, lastModified=time3, signUpTime=time, withdrawalStatus=WithdrawalStatus.NO_USE, withdrawalTime=time2, hpoId=PITT_HPO_ID, providerLink=p2.providerLink) self.assertEquals(expected_participant.asdict(), p2.asdict()) def test_update_suspend(self): p = Participant() time = datetime.datetime(2016, 1, 1) with random_ids([1, 2]): with FakeClock(time): self.dao.insert(p) p.version = 1 p.suspensionStatus = SuspensionStatus.NO_CONTACT time2 = datetime.datetime(2016, 1, 2) with FakeClock(time2): self.dao.update(p) p2 = self.dao.get(1) expected_participant = self._participant_with_defaults( participantId=1, version=2, biobankId=2, lastModified=time2, signUpTime=time, suspensionStatus=SuspensionStatus.NO_CONTACT, suspensionTime=time2) self.assertEquals(expected_participant.asdict(), p2.asdict()) p.version = 2 p.providerLink = make_primary_provider_link_for_name('PITT') p.suspensionTime = None time3 = datetime.datetime(2016, 1, 3) with FakeClock(time3): self.dao.update(p) # Withdrawal time should get copied over. p2 = self.dao.get(1) expected_participant = self._participant_with_defaults( participantId=1, version=3, biobankId=2, lastModified=time3, signUpTime=time, suspensionStatus=SuspensionStatus.NO_CONTACT, suspensionTime=time2, hpoId=PITT_HPO_ID, providerLink=p2.providerLink) self.assertEquals(expected_participant.asdict(), p2.asdict()) def test_update_wrong_expected_version(self): p = Participant() time = datetime.datetime(2016, 1, 1) with random_ids([1, 2]): with FakeClock(time): self.dao.insert(p) p.version = 2 p.providerLink = make_primary_provider_link_for_name('PITT') time2 = datetime.datetime(2016, 1, 2) with FakeClock(time2): with self.assertRaises(PreconditionFailed): self.dao.update(p) def test_update_withdrawn_hpo_succeeds(self): p = Participant(withdrawalStatus=WithdrawalStatus.NO_USE) time = datetime.datetime(2016, 1, 1) with random_ids([1, 2]): with FakeClock(time): self.dao.insert(p) expected_participant = self._participant_with_defaults( participantId=1, version=1, biobankId=2, lastModified=time, signUpTime=time, withdrawalStatus=WithdrawalStatus.NO_USE) self.assertEquals(expected_participant.asdict(), p.asdict()) p2 = self.dao.get(1) self.assertEquals(p.asdict(), p2.asdict()) p.version = 1 p.providerLink = make_primary_provider_link_for_name('PITT') self.dao.update(p) def test_update_withdrawn_status_fails(self): p = Participant(withdrawalStatus=WithdrawalStatus.NO_USE) time = datetime.datetime(2016, 1, 1) with random_ids([1, 2]): with FakeClock(time): self.dao.insert(p) expected_participant = self._participant_with_defaults( participantId=1, version=1, biobankId=2, lastModified=time, signUpTime=time, withdrawalStatus=WithdrawalStatus.NO_USE) self.assertEquals(expected_participant.asdict(), p.asdict()) p2 = self.dao.get(1) self.assertEquals(p.asdict(), p2.asdict()) p.version = 1 p.withdrawalStatus = WithdrawalStatus.NOT_WITHDRAWN with self.assertRaises(Forbidden): self.dao.update(p) def test_update_not_exists(self): p = self._participant_with_defaults(participantId=1, biobankId=2) with self.assertRaises(NotFound): self.dao.update(p) def test_bad_hpo_insert(self): p = Participant( participantId=1, version=1, biobankId=2, providerLink=make_primary_provider_link_for_name('FOO')) with self.assertRaises(BadRequest): self.dao.insert(p) def test_bad_hpo_update(self): p = Participant(participantId=1, biobankId=2) time = datetime.datetime(2016, 1, 1) with FakeClock(time): self.dao.insert(p) p.providerLink = make_primary_provider_link_for_name('FOO') with self.assertRaises(BadRequest): self.dao.update(p) def test_pairs_unset(self): participant_id = 22 self.dao.insert(Participant(participantId=participant_id, biobankId=2)) refetched = self.dao.get(participant_id) self.assertEquals(refetched.hpoId, UNSET_HPO_ID) # sanity check self.participant_summary_dao.insert( self.participant_summary(refetched)) with self.dao.session() as session: self.dao.add_missing_hpo_from_site(session, participant_id, self._test_db.site_id) paired = self.dao.get(participant_id) self.assertEquals(paired.hpoId, self._test_db.hpo_id) self.assertEquals( paired.providerLink, make_primary_provider_link_for_id(self._test_db.hpo_id)) self.assertEquals( self.participant_summary_dao.get(participant_id).hpoId, self._test_db.hpo_id) self.assertEquals(paired.organizationId, self._test_db.organization_id) self.assertEquals(paired.siteId, self._test_db.site_id) def test_overwrite_existing_pairing(self): participant_id = 99 created = self.dao.insert( Participant(participantId=participant_id, biobankId=2, hpoId=self._test_db.hpo_id, providerLink=make_primary_provider_link_for_id( self._test_db.hpo_id))) self.participant_summary_dao.insert(self.participant_summary(created)) self.assertEquals(created.hpoId, self._test_db.hpo_id) # sanity check other_hpo = HPODao().insert( HPO(hpoId=PITT_HPO_ID + 1, name='DIFFERENT_HPO')) other_site = SiteDao().insert( Site(hpoId=other_hpo.hpoId, siteName='Arbitrary Site', googleGroup='*****@*****.**')) with self.dao.session() as session: self.dao.add_missing_hpo_from_site(session, participant_id, other_site.siteId) # Original Participant + summary is affected. refetched = self.dao.get(participant_id) self.assertEquals(refetched.hpoId, other_hpo.hpoId) self.assertEquals(refetched.providerLink, make_primary_provider_link_for_id(other_hpo.hpoId)) self.assertEquals( self.participant_summary_dao.get(participant_id).hpoId, other_hpo.hpoId) def test_pairing_at_different_levels(self): p = Participant() time = datetime.datetime(2016, 1, 1) with random_ids([1, 2]): with FakeClock(time): self.dao.insert(p) p.version = 1 p.siteId = 1 time2 = datetime.datetime(2016, 1, 2) with FakeClock(time2): self.dao.update(p) p2 = self.dao.get(1) ep = self._participant_with_defaults(participantId=1, version=2, biobankId=2, lastModified=time2, signUpTime=time, hpoId=PITT_HPO_ID, siteId=1, organizationId=PITT_ORG_ID, providerLink=p2.providerLink) self.assertEquals(ep.siteId, p2.siteId) # ensure that p2 get paired with expected awardee and organization from update(). self.assertEquals(ep.hpoId, p2.hpoId) self.assertEquals(ep.organizationId, p2.organizationId)
class SiteDaoTest(SqlTestBase): def setUp(self): super(SiteDaoTest, self).setUp() self.site_dao = SiteDao() self.participant_dao = ParticipantDao() self.ps_dao = ParticipantSummaryDao() self.ps_history = ParticipantHistoryDao() def test_get_no_sites(self): self.assertIsNone(self.site_dao.get(9999)) self.assertIsNone( self.site_dao.get_by_google_group('*****@*****.**')) def test_insert(self): site = Site(siteName='site', googleGroup='*****@*****.**', mayolinkClientNumber=12345, hpoId=PITT_HPO_ID) created_site = self.site_dao.insert(site) new_site = self.site_dao.get(created_site.siteId) site.siteId = created_site.siteId self.assertEquals(site.asdict(), new_site.asdict()) self.assertEquals( site.asdict(), self.site_dao.get_by_google_group( '*****@*****.**').asdict()) def test_update(self): site = Site(siteName='site', googleGroup='*****@*****.**', mayolinkClientNumber=12345, hpoId=PITT_HPO_ID) created_site = self.site_dao.insert(site) new_site = Site(siteId=created_site.siteId, siteName='site2', googleGroup='*****@*****.**', mayolinkClientNumber=123456, hpoId=UNSET_HPO_ID) self.site_dao.update(new_site) fetched_site = self.site_dao.get(created_site.siteId) self.assertEquals(new_site.asdict(), fetched_site.asdict()) self.assertEquals( new_site.asdict(), self.site_dao.get_by_google_group( '*****@*****.**').asdict()) self.assertIsNone( self.site_dao.get_by_google_group('*****@*****.**')) def test_participant_pairing_updates_on_change(self): TIME = datetime.datetime(2018, 1, 1) TIME2 = datetime.datetime(2018, 1, 2) provider_link = '[{"organization": {"reference": "Organization/AZ_TUCSON"}, "primary": true}]' site = Site(siteName='site', googleGroup='*****@*****.**', mayolinkClientNumber=12345, hpoId=PITT_HPO_ID, organizationId=PITT_ORG_ID) created_site = self.site_dao.insert(site) with FakeClock(TIME): p = Participant(participantId=1, biobankId=2, siteId=created_site.siteId) self.participant_dao.insert(p) fetch_p = self.participant_dao.get(p.participantId) updated_p = self.participant_dao.get(fetch_p.participantId) p_summary = self.ps_dao.insert(self.participant_summary(updated_p)) with FakeClock(TIME2): update_site_parent = Site(siteId=created_site.siteId, siteName='site2', googleGroup='*****@*****.**', mayolinkClientNumber=123456, hpoId=AZ_HPO_ID, organizationId=AZ_ORG_ID) self.site_dao.update(update_site_parent) updated_p = self.participant_dao.get(fetch_p.participantId) ps = self.ps_dao.get(p_summary.participantId) ph = self.ps_history.get([updated_p.participantId, 1]) self.assertEquals(update_site_parent.hpoId, updated_p.hpoId) self.assertEquals(update_site_parent.organizationId, updated_p.organizationId) self.assertEquals(ps.organizationId, update_site_parent.organizationId) self.assertEquals(ps.hpoId, update_site_parent.hpoId) self.assertEquals(ps.organizationId, update_site_parent.organizationId) self.assertEquals(ph.organizationId, update_site_parent.organizationId) self.assertEquals(updated_p.providerLink, provider_link) self.assertEquals(ps.lastModified, TIME2)
class MarkGhostParticipantsTest(CloudStorageSqlTestBase, NdbTestBase): """Tests setting a flag on participants as a ghost account with date added. """ def setUp(self): super(MarkGhostParticipantsTest, self).setUp(use_mysql=True) NdbTestBase.doSetUp(self) TestBase.setup_fake(self) config.override_setting(config.GHOST_ID_BUCKET, [_FAKE_BUCKET]) self.participant_dao = ParticipantDao() self.p_history = ParticipantHistoryDao() def _write_cloud_csv(self, file_name, contents_str): with cloudstorage_api.open('/%s/%s' % (_FAKE_BUCKET, file_name), mode='w') as cloud_file: cloud_file.write(contents_str.encode('utf-8')) def _setup_participants(self): self.participant1 = Participant(participantId=1, biobankId=1) self.participant2 = Participant(participantId=2, biobankId=2) self.participant_dao.insert(self.participant1) self.participant_dao.insert(self.participant2) self.assertEqual(self.participant1.isGhostId, None) self.assertEqual(self.participant1.dateAddedGhost, None) self.assertEqual(self.participant2.isGhostId, None) self.assertEqual(self.participant2.dateAddedGhost, None) def _setup_file(self, wrong_pid=False): # mock up a ghost pid csv header = 'participant_id, regisered_date' if not wrong_pid: row1 = str(self.participant1.participantId) + ',' + str(TIME) row2 = str(self.participant2.participantId) + ',' + str(TIME_2) else: row1 = 'P12345' row2 = 'P67890' csv_contents = '\n'.join([header, row1, row2]) self._write_cloud_csv('ghost_pids.csv', csv_contents) def tearDown(self): super(MarkGhostParticipantsTest, self).tearDown() def test_mark_ghost_participant(self): self._setup_participants() self._setup_file() with FakeClock(TIME_3): exclude_ghost_participants.mark_ghost_participants() person1 = self.participant_dao.get(self.participant1.participantId) person2 = self.participant_dao.get(self.participant2.participantId) self.assertEqual(person1.isGhostId, 1) self.assertEqual(person1.dateAddedGhost, TIME_3) self.assertEqual(person2.isGhostId, 1) self.assertEqual(person2.dateAddedGhost, TIME_3) def test_participant_history_is_updated(self): self._setup_participants() self._setup_file() with FakeClock(TIME_3): exclude_ghost_participants.mark_ghost_participants() # version 2 should have ghost id flag set. history = self.p_history.get([1, 2]) self.assertEqual(history.isGhostId, 1) self.assertEqual(history.dateAddedGhost, TIME_3) def test_find_latest_csv(self): # The cloud storage testbed does not expose an injectable time function. # Creation time is stored at second granularity. self._write_cloud_csv('a_lex_first_created_first.csv', 'any contents') time.sleep(1.0) self._write_cloud_csv('z_lex_last_created_middle.csv', 'any contents') time.sleep(1.0) created_last = 'b_lex_middle_created_last.csv' self._write_cloud_csv(created_last, 'any contents') _, latest_filename = exclude_ghost_participants.get_latest_pid_file( _FAKE_BUCKET) self.assertEquals(latest_filename, '/%s/%s' % (_FAKE_BUCKET, created_last)) def test_no_participant_to_mark(self): # make sure a csv with bad PIDS doesn't blow up. self._setup_participants() self._setup_file(wrong_pid=True) with FakeClock(TIME_3): exclude_ghost_participants.mark_ghost_participants()
class BiobankOrderApiTest(FlaskTestBase): def setUp(self): super(BiobankOrderApiTest, self).setUp(use_mysql=True) self.participant = Participant(participantId=123, biobankId=555) self.participant_dao = ParticipantDao() self.participant_dao.insert(self.participant) self.summary_dao = ParticipantSummaryDao() self.bio_dao = BiobankOrderDao() self.path = ('Participant/%s/BiobankOrder' % to_client_participant_id(self.participant.participantId)) def test_cancel_order(self): self.summary_dao.insert(self.participant_summary(self.participant)) order_json = load_biobank_order_json(self.participant.participantId, filename='biobank_order_2.json') result = self.send_post(self.path, order_json) full_order_json = load_biobank_order_json( self.participant.participantId, filename='biobank_order_1.json') _strip_fields(result) _strip_fields(full_order_json) self.assertEquals(full_order_json, result) biobank_order_id = result['identifier'][1]['value'] path = self.path + '/' + biobank_order_id request_data = { "amendedReason": "Its all wrong", "cancelledInfo": { "author": { "system": "https://www.pmi-ops.org/healthpro-username", "value": "*****@*****.**" }, "site": { "system": "https://www.pmi-ops.org/site-id", "value": "hpo-site-monroeville" } }, "status": "cancelled" } cancelled_order = self.send_patch(path, request_data=request_data, headers={'If-Match': 'W/"1"'}) get_cancelled_order = self.send_get(path) get_summary = self.summary_dao.get(self.participant.participantId) self.assertEqual(get_summary.biospecimenSourceSiteId, None) self.assertEqual(get_summary.biospecimenCollectedSiteId, None) self.assertEqual(get_summary.biospecimenOrderTime, None) self.assertEqual(get_summary.biospecimenStatus, None) self.assertEqual(get_summary.biospecimenFinalizedSiteId, None) self.assertEqual(get_summary.biospecimenProcessedSiteId, None) self.assertEqual(get_summary.sampleOrderStatus2ED10, None) self.assertEqual(get_summary.sampleOrderStatus2ED10Time, None) self.assertEqual(get_summary.sampleStatus2ED10, None) self.assertEqual(get_summary.sampleStatus2ED10Time, None) self.assertEqual(get_summary.sampleOrderStatus1PST8, None) self.assertEqual(get_summary.sampleOrderStatus1PST8Time, None) self.assertEqual(get_summary.sampleStatus1PST8, None) self.assertEqual(get_summary.sampleStatus1PST8Time, None) self.assertEqual(get_summary.sampleOrderStatus1PS08, None) self.assertEqual(get_summary.sampleOrderStatus1PS08Time, None) self.assertEqual(get_summary.sampleStatus1PS08, None) self.assertEqual(get_summary.sampleStatus1PS08Time, None) self.assertEqual(get_summary.sampleOrderStatus2PST8, None) self.assertEqual(get_summary.sampleOrderStatus2PST8Time, None) self.assertEqual(get_summary.sampleStatus2PST8, None) self.assertEqual(get_summary.sampleStatus2PST8Time, None) self.assertEqual(get_summary.sampleOrderStatus1PXR2, None) self.assertEqual(get_summary.sampleOrderStatus1PXR2Time, None) self.assertEqual(get_summary.sampleStatus1PXR2, None) self.assertEqual(get_summary.sampleStatus1PXR2Time, None) self.assertEqual(get_summary.sampleOrderStatus1CFD9, None) self.assertEqual(get_summary.sampleOrderStatus1CFD9Time, None) self.assertEqual(get_summary.sampleStatus1CFD9, None) self.assertEqual(get_summary.sampleStatus1CFD9Time, None) self.assertEqual(get_summary.sampleOrderStatus1ED02, None) self.assertEqual(get_summary.sampleOrderStatus1ED02Time, None) self.assertEqual(get_summary.sampleStatus1ED02, None) self.assertEqual(get_summary.sampleStatus1ED02Time, None) self.assertEqual(cancelled_order, get_cancelled_order) self.assertEqual(get_cancelled_order['status'], 'CANCELLED') self.assertEqual(get_cancelled_order['amendedReason'], 'Its all wrong') self.assertEqual( get_cancelled_order['cancelledInfo']['author']['value'], '*****@*****.**') self.assertEqual(get_cancelled_order['cancelledInfo']['site']['value'], 'hpo-site-monroeville') def test_cancel_one_order_with_another_good_order(self): self.summary_dao.insert(self.participant_summary(self.participant)) order_json = load_biobank_order_json(self.participant.participantId, filename="biobank_order_1.json") order_json2 = load_biobank_order_json(self.participant.participantId, filename="biobank_order_2.json") order_json2['identifier'][0]['value'] = 'healthpro-order-id-1231234' order_json2['identifier'][1]['value'] = 'WEB1YLHV1234' result = self.send_post(self.path, order_json) self.send_post(self.path, order_json2) biobank_order_id = result["identifier"][1]["value"] path = self.path + "/" + biobank_order_id request_data = { "amendedReason": "Its all wrong", "cancelledInfo": { "author": { "system": "https://www.pmi-ops.org/healthpro-username", "value": "*****@*****.**" }, "site": { "system": "https://www.pmi-ops.org/site-id", "value": "hpo-site-monroeville" }, }, "status": "cancelled", } self.send_patch(path, request_data=request_data, headers={"If-Match": 'W/"1"'}) get_summary = self.summary_dao.get(self.participant.participantId) self.assertEqual(get_summary.biospecimenSourceSiteId, 1) self.assertEqual(get_summary.biospecimenCollectedSiteId, 1) self.assertEqual(get_summary.biospecimenFinalizedSiteId, 2) def test_you_can_not_cancel_a_cancelled_order(self): self.summary_dao.insert(self.participant_summary(self.participant)) order_json = load_biobank_order_json(self.participant.participantId, filename='biobank_order_2.json') result = self.send_post(self.path, order_json) biobank_order_id = result['identifier'][1]['value'] path = self.path + '/' + biobank_order_id request_data = { "amendedReason": "Its all wrong", "cancelledInfo": { "author": { "system": "https://www.pmi-ops.org/healthpro-username", "value": "*****@*****.**" }, "site": { "system": "https://www.pmi-ops.org/site-id", "value": "hpo-site-monroeville" } }, "status": "cancelled" } self.send_patch(path, request_data=request_data, headers={'If-Match': 'W/"1"'}) self.send_patch(path, request_data=request_data, headers={'If-Match': 'W/"2"'}, expected_status=httplib.BAD_REQUEST) def test_you_can_not_restore_a_not_cancelled_order(self): self.summary_dao.insert(self.participant_summary(self.participant)) order_json = load_biobank_order_json(self.participant.participantId, filename='biobank_order_2.json') result = self.send_post(self.path, order_json) biobank_order_id = result['identifier'][1]['value'] path = self.path + '/' + biobank_order_id request_data = { "amendedReason": "Its all wrong", "restoredInfo": { "author": { "system": "https://www.pmi-ops.org/healthpro-username", "value": "*****@*****.**" }, "site": { "system": "https://www.pmi-ops.org/site-id", "value": "hpo-site-monroeville" } }, "status": "restored" } self.send_patch(path, request_data=request_data, headers={'If-Match': 'W/"1"'}, expected_status=httplib.BAD_REQUEST) def test_restore_an_order(self): self.summary_dao.insert(self.participant_summary(self.participant)) order_json = load_biobank_order_json(self.participant.participantId, filename='biobank_order_2.json') result = self.send_post(self.path, order_json) full_order_json = load_biobank_order_json( self.participant.participantId, filename='biobank_order_1.json') _strip_fields(result) _strip_fields(full_order_json) self.assertEquals(full_order_json, result) biobank_order_id = result['identifier'][1]['value'] path = self.path + '/' + biobank_order_id request_data = { "amendedReason": "Its all wrong", "cancelledInfo": { "author": { "system": "https://www.pmi-ops.org/healthpro-username", "value": "*****@*****.**" }, "site": { "system": "https://www.pmi-ops.org/site-id", "value": "hpo-site-monroeville" } }, "status": "cancelled" } self.send_patch(path, request_data=request_data, headers={'If-Match': 'W/"1"'}) request_data = { "amendedReason": "I didnt mean to cancel", "restoredInfo": { "author": { "system": "https://www.pmi-ops.org/healthpro-username", "value": "*****@*****.**" }, "site": { "system": "https://www.pmi-ops.org/site-id", "value": "hpo-site-monroeville" } }, "status": "restored" } self.send_patch(path, request_data=request_data, headers={'If-Match': 'W/"2"'}) restored_order = self.send_get(path) get_summary = self.summary_dao.get(self.participant.participantId) self.assertEqual(get_summary.sampleOrderStatus1SST8, OrderStatus.CREATED) self.assertEqual(get_summary.sampleOrderStatus2ED10, OrderStatus.CREATED) self.assertEqual(get_summary.sampleOrderStatus1SAL, OrderStatus.CREATED) self.assertEqual(get_summary.sampleOrderStatus1UR10, OrderStatus.CREATED) self.assertEqual(get_summary.sampleOrderStatus1CFD9, OrderStatus.FINALIZED) self.assertEqual(get_summary.sampleOrderStatus1ED02, OrderStatus.FINALIZED) self.assertEqual(get_summary.sampleOrderStatus2SST8, OrderStatus.FINALIZED) self.assertEqual(get_summary.sampleOrderStatus2PST8, OrderStatus.FINALIZED) self.assertEqual(restored_order['status'], 'UNSET') self.assertEqual(restored_order['restoredInfo']['author']['value'], '*****@*****.**') self.assertEqual(restored_order['restoredInfo']['site']['value'], 'hpo-site-monroeville') self.assertEqual(restored_order['amendedReason'], 'I didnt mean to cancel') def test_amending_an_order(self): # pylint: disable=unused-variable self.summary_dao.insert(self.participant_summary(self.participant)) order_json = load_biobank_order_json(self.participant.participantId, filename='biobank_order_2.json') result = self.send_post(self.path, order_json) biobank_order_id = result['identifier'][1]['value'] path = self.path + '/' + biobank_order_id request_data = { "amendedReason": "Its all better", "amendedInfo": { "author": { "system": "https://www.pmi-ops.org/healthpro-username", "value": "*****@*****.**" }, "site": { "system": "https://www.pmi-ops.org/site-id", "value": "hpo-site-bannerphoenix" } } } biobank_order_identifiers = { "created": "2018-02-21T16:25:12", "createdInfo": { "author": { "system": "https://www.pmi-ops.org/healthpro-username", "value": "*****@*****.**" }, "site": { "system": "https://www.pmi-ops.org/site-id", "value": "hpo-site-clinic-phoenix" } } } get_order = self.send_get(path) full_order = get_order.copy() full_order.update(request_data) full_order.update(biobank_order_identifiers) self.assertEqual(len(full_order['samples']), 16) del full_order['samples'][0] self.send_put(path, request_data=full_order, headers={'If-Match': 'W/"1"'}) get_amended_order = self.send_get(path) get_summary = self.summary_dao.get(self.participant.participantId) self.assertEqual(get_summary.biospecimenProcessedSiteId, 1) self.assertEqual(get_summary.biospecimenFinalizedSiteId, 2) self.assertEqual(get_summary.biospecimenCollectedSiteId, 1) self.assertEqual(get_summary.sampleOrderStatus2PST8, OrderStatus.FINALIZED) self.assertEqual(get_summary.sampleOrderStatus1PS08, OrderStatus.FINALIZED) self.assertEqual(get_summary.sampleOrderStatus1PST8, OrderStatus.FINALIZED) self.assertEqual(get_summary.sampleOrderStatus1SST8, OrderStatus.CREATED) self.assertEqual(get_summary.sampleOrderStatus2ED10, OrderStatus.CREATED) self.assertEqual(len(get_amended_order['samples']), 15) self.assertEqual(get_amended_order['meta'], {'versionId': 'W/"2"'}) self.assertEqual(get_amended_order['amendedReason'], 'Its all better') self.assertEqual(get_amended_order['amendedInfo']['author']['value'], '*****@*****.**') self.assertEqual(get_amended_order['amendedInfo']['site']['value'], 'hpo-site-bannerphoenix') self.assertEqual(get_amended_order['createdInfo']['site']['value'], 'hpo-site-clinic-phoenix') self.assertEqual(get_amended_order['createdInfo']['author']['value'], '*****@*****.**') self.assertEqual(get_amended_order['created'], "2018-02-21T16:25:12") self.assertEqual(get_amended_order['status'], "AMENDED") def test_amend_a_restored_order(self): self.summary_dao.insert(self.participant_summary(self.participant)) order_json = load_biobank_order_json(self.participant.participantId, filename='biobank_order_2.json') result = self.send_post(self.path, order_json) full_order_json = load_biobank_order_json( self.participant.participantId, filename='biobank_order_1.json') _strip_fields(result) _strip_fields(full_order_json) biobank_order_id = result['identifier'][1]['value'] path = self.path + '/' + biobank_order_id request_data = { "amendedReason": "Its all wrong", "cancelledInfo": { "author": { "system": "https://www.pmi-ops.org/healthpro-username", "value": "*****@*****.**" }, "site": { "system": "https://www.pmi-ops.org/site-id", "value": "hpo-site-monroeville" } }, "status": "cancelled" } self.send_patch(path, request_data=request_data, headers={'If-Match': 'W/"1"'}) self.send_get(path) request_data = { "amendedReason": "I didnt mean to cancel", "restoredInfo": { "author": { "system": "https://www.pmi-ops.org/healthpro-username", "value": "*****@*****.**" }, "site": { "system": "https://www.pmi-ops.org/site-id", "value": "hpo-site-monroeville" } }, "status": "restored" } self.send_patch(path, request_data=request_data, headers={'If-Match': 'W/"2"'}) request_data = { "amendedReason": "Its all better", "samples": [{ "test": "1ED10", "description": "EDTA 10 mL (1)", "processingRequired": False, "collected": "2016-01-04T09:45:49Z", "finalized": "2016-01-04T10:55:41Z" }, { "test": "1PST8", "description": "Plasma Separator 8 mL", "collected": "2016-01-04T09:45:49Z", "processingRequired": True, "processed": "2016-01-04T10:28:50Z", "finalized": "2016-01-04T10:55:41Z" }], "amendedInfo": { "author": { "system": "https://www.pmi-ops.org/healthpro-username", "value": "*****@*****.**" }, "site": { "system": "https://www.pmi-ops.org/site-id", "value": "hpo-site-monroeville" } } } get_order = self.send_get(path) full_order = get_order.copy() full_order.update(request_data) self.send_put(path, request_data=full_order, headers={'If-Match': 'W/"3"'}) get_amended_order = self.send_get(path) self.assertEqual(len(get_amended_order['samples']), 2) self.assertEqual(get_amended_order['amendedInfo']['author']['value'], '*****@*****.**') self.assertEqual(get_amended_order['status'], 'AMENDED') self.assertEqual(get_amended_order.get('restoredSiteId'), None) self.assertEqual(get_amended_order.get('restoredUsername'), None) self.assertEqual(get_amended_order.get('restoredTime'), None) self.assertEqual(get_amended_order['meta'], {'versionId': 'W/"4"'}) def test_insert_and_refetch(self): self.summary_dao.insert(self.participant_summary(self.participant)) self.create_and_verify_created_obj( self.path, load_biobank_order_json(self.participant.participantId)) def test_insert_new_order(self): self.summary_dao.insert(self.participant_summary(self.participant)) order_json = load_biobank_order_json(self.participant.participantId, filename='biobank_order_2.json') result = self.send_post(self.path, order_json) full_order_json = load_biobank_order_json( self.participant.participantId, filename='biobank_order_1.json') _strip_fields(result) _strip_fields(full_order_json) self.assertEquals(full_order_json, result) def test_biobank_history_on_insert(self): with self.bio_dao.session() as session: self.summary_dao.insert(self.participant_summary(self.participant)) order_json = load_biobank_order_json( self.participant.participantId, filename='biobank_order_2.json') result = self.send_post(self.path, order_json) load_biobank_order_json(self.participant.participantId, filename='biobank_order_1.json') order_history = session.query(BiobankOrderHistory).first() identifier_history = session.query( BiobankOrderIdentifierHistory).first() sample_history = session.query(BiobankOrderedSampleHistory).first() self.assertEqual(result['id'], order_history.biobankOrderId) self.assertEqual(identifier_history.biobankOrderId, result['id']) self.assertEqual(sample_history.biobankOrderId, result['id']) self.assertEqual(result['meta']['versionId'], 'W/"1"') self.assertEqual(order_history.version, 1) # Test history on updates... biobank_order_id = result['identifier'][1]['value'] path = self.path + '/' + biobank_order_id request_data = { "amendedReason": "Its all better", "amendedInfo": { "author": { "system": "https://www.pmi-ops.org/healthpro-username", "value": "*****@*****.**" }, "site": { "system": "https://www.pmi-ops.org/site-id", "value": "hpo-site-bannerphoenix" } } } biobank_order_identifiers = { "created": "2018-02-21T16:25:12", "createdInfo": { "author": { "system": "https://www.pmi-ops.org/healthpro-username", "value": "*****@*****.**" }, "site": { "system": "https://www.pmi-ops.org/site-id", "value": "hpo-site-clinic-phoenix" } } } get_order = self.send_get(path) full_order = get_order.copy() full_order.update(request_data) full_order.update(biobank_order_identifiers) self.assertEqual(len(full_order['samples']), 16) del full_order['samples'][0] self.send_put(path, request_data=full_order, headers={'If-Match': 'W/"1"'}) with self.bio_dao.session() as session: amended_order = self.send_get(path) second_order_history = session.query( BiobankOrderHistory).filter_by(version=2).first() second_order_samples = session.query( BiobankOrderedSampleHistory).filter_by(version=2).first() second_order_identifier = session.query(BiobankOrderIdentifierHistory).filter_by(version=2)\ .first() self.assertEqual(second_order_history.biobankOrderId, amended_order['id']) self.assertEqual(second_order_identifier.biobankOrderId, amended_order['id']) self.assertEqual(second_order_samples.biobankOrderId, amended_order['id']) # Check that original order hasn't changed in history original = session.query(BiobankOrderHistory).filter_by( version=1).first() self.assertEqual(original.asdict(), order_history.asdict()) def test_error_no_summary(self): order_json = load_biobank_order_json(self.participant.participantId) self.send_post(self.path, order_json, expected_status=httplib.BAD_REQUEST) def test_error_missing_required_fields(self): order_json = load_biobank_order_json(self.participant.participantId) del order_json['identifier'] self.send_post(self.path, order_json, expected_status=httplib.BAD_REQUEST) def test_no_duplicate_test_within_order(self): order_json = load_biobank_order_json(self.participant.participantId) order_json['samples'].extend(list(order_json['samples'])) self.send_post(self.path, order_json, expected_status=httplib.BAD_REQUEST) def test_auto_pair_updates_participant_and_summary(self): self.summary_dao.insert(self.participant_summary(self.participant)) # Sanity check: No HPO yet. p_unpaired = self.participant_dao.get(self.participant.participantId) self.assertEquals(p_unpaired.hpoId, UNSET_HPO_ID) self.assertIsNone(p_unpaired.providerLink) s_unpaired = self.summary_dao.get(self.participant.participantId) self.assertEquals(s_unpaired.hpoId, UNSET_HPO_ID) self.send_post(self.path, load_biobank_order_json(self.participant.participantId)) # Some HPO has been set. (ParticipantDao tests cover more detailed cases / specific values.) p_paired = self.participant_dao.get(self.participant.participantId) self.assertNotEqual(p_paired.hpoId, UNSET_HPO_ID) self.assertIsNotNone(p_paired.providerLink) s_paired = self.summary_dao.get(self.participant.participantId) self.assertNotEqual(s_paired.hpoId, UNSET_HPO_ID) self.assertEqual(s_paired.biospecimenCollectedSiteId, s_paired.siteId) self.assertNotEqual(s_paired.biospecimenCollectedSiteId, s_paired.biospecimenFinalizedSiteId) self.assertNotEqual(s_paired.siteId, s_paired.physicalMeasurementsCreatedSiteId) self.assertNotEqual(s_paired.siteId, s_paired.physicalMeasurementsFinalizedSiteId) def test_not_pairing_at_pm_when_has_bio(self): self.participant_id = self.create_participant() _id = int(self.participant_id[1:]) self.path = ('Participant/%s/BiobankOrder' % to_client_participant_id(_id)) pid_numeric = from_client_participant_id(self.participant_id) self.send_consent(self.participant_id) self.send_post(self.path, load_biobank_order_json(pid_numeric)) participant_paired = self.summary_dao.get(pid_numeric) self.assertEqual(participant_paired.siteId, participant_paired.biospecimenCollectedSiteId) self.path = ('Participant/%s/PhysicalMeasurements' % to_client_participant_id(pid_numeric)) self._insert_measurements(datetime.datetime.utcnow().isoformat()) self.assertNotEqual( participant_paired.siteId, participant_paired.physicalMeasurementsFinalizedSiteId) def test_bio_after_cancelled_pm(self): self.participant_id = self.create_participant() self.send_consent(self.participant_id) measurement = load_measurement_json(self.participant_id) measurement2 = load_measurement_json(self.participant_id) # send both PM's pm_path = 'Participant/%s/PhysicalMeasurements' % self.participant_id response = self.send_post(pm_path, measurement) self.send_post(pm_path, measurement2) # cancel the 1st PM pm_path = pm_path + '/' + response['id'] cancel_info = get_restore_or_cancel_info() self.send_patch(pm_path, cancel_info) # set up questionnaires to hit the calculate_max_core_sample_time in participant summary questionnaire_id = self.create_questionnaire('questionnaire3.json') questionnaire_id_1 = self.create_questionnaire( 'all_consents_questionnaire.json') questionnaire_id_2 = self.create_questionnaire('questionnaire4.json') self._submit_consent_questionnaire_response( self.participant_id, questionnaire_id_1, CONSENT_PERMISSION_YES_CODE, time=TIME_6) self.submit_questionnaire_response(self.participant_id, questionnaire_id, RACE_NONE_OF_THESE_CODE, None, None, datetime.date(1978, 10, 10)) self._submit_empty_questionnaire_response(self.participant_id, questionnaire_id_2) # send a biobank order _id = int(self.participant_id[1:]) self.path = ('Participant/%s/BiobankOrder' % to_client_participant_id(_id)) pid_numeric = from_client_participant_id(self.participant_id) self.send_post(self.path, load_biobank_order_json(pid_numeric)) # fetch participant summary ps = self.send_get('ParticipantSummary?participantId=%s' % _id) self.assertTrue( ps['entry'][0]['resource']["physicalMeasurementsFinalizedTime"]) self.assertEquals( ps['entry'][0]['resource']["physicalMeasurementsFinalizedSite"], 'hpo-site-bannerphoenix') self.assertIsNotNone('biobankId', ps['entry'][0]['resource']) def _insert_measurements(self, now=None): measurements_1 = load_measurement_json(self.participant_id, now) path_1 = 'Participant/%s/PhysicalMeasurements' % self.participant_id self.send_post(path_1, measurements_1) def _submit_consent_questionnaire_response(self, participant_id, questionnaire_id, ehr_consent_answer, time=TIME_1): code_answers = [] _add_code_answer(code_answers, "ehrConsent", ehr_consent_answer) qr = make_questionnaire_response_json(participant_id, questionnaire_id, code_answers=code_answers) with FakeClock(time): self.send_post( 'Participant/%s/QuestionnaireResponse' % participant_id, qr) def _submit_empty_questionnaire_response(self, participant_id, questionnaire_id, time=TIME_1): qr = make_questionnaire_response_json(participant_id, questionnaire_id) with FakeClock(time): self.send_post( 'Participant/%s/QuestionnaireResponse' % participant_id, qr)
class OrganizationDaoTest(SqlTestBase): def setUp(self): super(OrganizationDaoTest, self).setUp() self.organization_dao = OrganizationDao() self.participant_dao = ParticipantDao() self.ps_dao = ParticipantSummaryDao() self.ps_history = ParticipantHistoryDao() def test_insert(self): organization = Organization(externalId='myorg', displayName='myorg_display', hpoId=PITT_HPO_ID, isObsolete=1) created_organization = self.organization_dao.insert(organization) new_organization = self.organization_dao.get(created_organization.organizationId) organization.organizationId = created_organization.organizationId organization.isObsolete = new_organization.isObsolete self.assertEquals(organization.asdict(), new_organization.asdict()) def test_participant_pairing_updates_onchange(self): provider_link = '[{"organization": {"reference": "Organization/AZ_TUCSON"}, "primary": true}]' TIME = datetime.datetime(2018, 1, 1) TIME2 = datetime.datetime(2018, 1, 2) insert_org = self.organization_dao.insert( Organization(externalId='tardis', displayName='bluebox', hpoId=PITT_HPO_ID)) with FakeClock(TIME): self.participant_dao.insert(Participant(participantId=1, biobankId=2)) participant = self.participant_dao.get(1) participant.organizationId = insert_org.organizationId self.participant_dao.update(participant) self.assertEquals(participant.hpoId, insert_org.hpoId) participant = self.participant_dao.get(1) p_summary = self.ps_dao.insert(self.participant_summary(participant)) with FakeClock(TIME2): insert_org.hpoId = AZ_HPO_ID self.organization_dao.update(insert_org) new_org = self.organization_dao.get_by_external_id('tardis') ps = self.ps_dao.get(p_summary.participantId) ph = self.ps_history.get([participant.participantId, 2]) participant = self.participant_dao.get(1) self.assertEquals(ps.lastModified, TIME2) self.assertEquals(ps.hpoId, new_org.hpoId) self.assertEquals(ph.hpoId, insert_org.hpoId) self.assertEquals(ph.organizationId, insert_org.organizationId) self.assertEquals(new_org.hpoId, participant.hpoId) self.assertEquals(new_org.organizationId, participant.organizationId) self.assertIsNone(participant.siteId) self.assertEquals(participant.providerLink, provider_link) def test_participant_different_hpo_does_not_change(self): insert_org = self.organization_dao.insert( Organization(externalId='stark_industries', displayName='ironman', hpoId=PITT_HPO_ID)) self.participant_dao.insert(Participant(participantId=1, biobankId=2)) participant = self.participant_dao.get(1) participant.hpoId = UNSET_HPO_ID self.participant_dao.update(participant) insert_org.hpoId = AZ_HPO_ID self.organization_dao.update(insert_org) new_org = self.organization_dao.get_by_external_id('stark_industries') participant = self.participant_dao.get(1) self.assertNotEqual(new_org.hpoId, participant.hpoId) self.assertEqual(new_org.hpoId, AZ_HPO_ID) self.assertEqual(participant.hpoId, UNSET_HPO_ID)
class BiobankOrderApiTest(FlaskTestBase): def setUp(self): super(BiobankOrderApiTest, self).setUp() self.participant = Participant(participantId=123, biobankId=555) self.participant_dao = ParticipantDao() self.participant_dao.insert(self.participant) self.summary_dao = ParticipantSummaryDao() self.path = ('Participant/%s/BiobankOrder' % to_client_participant_id(self.participant.participantId)) def test_insert_and_refetch(self): self.summary_dao.insert(self.participant_summary(self.participant)) self.create_and_verify_created_obj( self.path, load_biobank_order_json(self.participant.participantId)) def test_insert_new_order(self): self.summary_dao.insert(self.participant_summary(self.participant)) order_json = load_biobank_order_json(self.participant.participantId, filename='biobank_order_2.json') result = self.send_post(self.path, order_json) full_order_json = load_biobank_order_json( self.participant.participantId, filename='biobank_order_1.json') _strip_fields(result) _strip_fields(full_order_json) self.assertEquals(full_order_json, result) def test_error_no_summary(self): order_json = load_biobank_order_json(self.participant.participantId) self.send_post(self.path, order_json, expected_status=httplib.BAD_REQUEST) def test_error_missing_required_fields(self): order_json = load_biobank_order_json(self.participant.participantId) del order_json['identifier'] self.send_post(self.path, order_json, expected_status=httplib.BAD_REQUEST) def test_no_duplicate_test_within_order(self): order_json = load_biobank_order_json(self.participant.participantId) order_json['samples'].extend(list(order_json['samples'])) self.send_post(self.path, order_json, expected_status=httplib.BAD_REQUEST) def test_auto_pair_updates_participant_and_summary(self): self.summary_dao.insert(self.participant_summary(self.participant)) # Sanity check: No HPO yet. p_unpaired = self.participant_dao.get(self.participant.participantId) self.assertEquals(p_unpaired.hpoId, UNSET_HPO_ID) self.assertIsNone(p_unpaired.providerLink) s_unpaired = self.summary_dao.get(self.participant.participantId) self.assertEquals(s_unpaired.hpoId, UNSET_HPO_ID) self.send_post(self.path, load_biobank_order_json(self.participant.participantId)) # Some HPO has been set. (ParticipantDao tests cover more detailed cases / specific values.) p_paired = self.participant_dao.get(self.participant.participantId) self.assertNotEqual(p_paired.hpoId, UNSET_HPO_ID) self.assertIsNotNone(p_paired.providerLink) s_paired = self.summary_dao.get(self.participant.participantId) self.assertNotEqual(s_paired.hpoId, UNSET_HPO_ID)
class BiobankOrderApiTest(FlaskTestBase): def setUp(self): super(BiobankOrderApiTest, self).setUp() self.participant = Participant(participantId=123, biobankId=555) self.participant_dao = ParticipantDao() self.participant_dao.insert(self.participant) self.summary_dao = ParticipantSummaryDao() self.path = ( 'Participant/%s/BiobankOrder' % to_client_participant_id(self.participant.participantId)) def test_insert_and_refetch(self): self.summary_dao.insert(self.participant_summary(self.participant)) self.create_and_verify_created_obj( self.path, load_biobank_order_json(self.participant.participantId)) def test_insert_new_order(self): self.summary_dao.insert(self.participant_summary(self.participant)) order_json = load_biobank_order_json(self.participant.participantId, filename='biobank_order_2.json') result = self.send_post(self.path, order_json) full_order_json = load_biobank_order_json(self.participant.participantId, filename='biobank_order_1.json') _strip_fields(result) _strip_fields(full_order_json) self.assertEquals(full_order_json, result) def test_error_no_summary(self): order_json = load_biobank_order_json(self.participant.participantId) self.send_post(self.path, order_json, expected_status=httplib.BAD_REQUEST) def test_error_missing_required_fields(self): order_json = load_biobank_order_json(self.participant.participantId) del order_json['identifier'] self.send_post(self.path, order_json, expected_status=httplib.BAD_REQUEST) def test_no_duplicate_test_within_order(self): order_json = load_biobank_order_json(self.participant.participantId) order_json['samples'].extend(list(order_json['samples'])) self.send_post(self.path, order_json, expected_status=httplib.BAD_REQUEST) def test_auto_pair_updates_participant_and_summary(self): self.summary_dao.insert(self.participant_summary(self.participant)) # Sanity check: No HPO yet. p_unpaired = self.participant_dao.get(self.participant.participantId) self.assertEquals(p_unpaired.hpoId, UNSET_HPO_ID) self.assertIsNone(p_unpaired.providerLink) s_unpaired = self.summary_dao.get(self.participant.participantId) self.assertEquals(s_unpaired.hpoId, UNSET_HPO_ID) self.send_post(self.path, load_biobank_order_json(self.participant.participantId)) # Some HPO has been set. (ParticipantDao tests cover more detailed cases / specific values.) p_paired = self.participant_dao.get(self.participant.participantId) self.assertNotEqual(p_paired.hpoId, UNSET_HPO_ID) self.assertIsNotNone(p_paired.providerLink) s_paired = self.summary_dao.get(self.participant.participantId) self.assertNotEqual(s_paired.hpoId, UNSET_HPO_ID) self.assertEqual(s_paired.biospecimenCollectedSiteId, s_paired.siteId) self.assertNotEqual(s_paired.biospecimenCollectedSiteId, s_paired.biospecimenFinalizedSiteId) self.assertNotEqual(s_paired.siteId, s_paired.physicalMeasurementsCreatedSiteId ) self.assertNotEqual(s_paired.siteId, s_paired.physicalMeasurementsFinalizedSiteId ) def test_not_pairing_at_pm_when_has_bio(self): self.participant_id = self.create_participant() _id = int(self.participant_id[1:]) self.path = ( 'Participant/%s/BiobankOrder' % to_client_participant_id(_id)) pid_numeric = from_client_participant_id(self.participant_id) self.send_consent(self.participant_id) self.send_post(self.path, load_biobank_order_json(pid_numeric)) participant_paired = self.summary_dao.get(pid_numeric) self.assertEqual(participant_paired.siteId, participant_paired.biospecimenCollectedSiteId) self.path = ( 'Participant/%s/PhysicalMeasurements' % to_client_participant_id(pid_numeric)) self._insert_measurements(datetime.datetime.utcnow().isoformat()) self.assertNotEqual(participant_paired.siteId, participant_paired.physicalMeasurementsFinalizedSiteId) def _insert_measurements(self, now=None): measurements_1 = load_measurement_json(self.participant_id, now) path_1 = 'Participant/%s/PhysicalMeasurements' % self.participant_id self.send_post(path_1, measurements_1)