def setUp(self): super(ParticipantSummaryDaoTest, self).setUp(use_mysql=True) self.dao = ParticipantSummaryDao() self.order_dao = BiobankOrderDao() self.measurement_dao = PhysicalMeasurementsDao() self.participant_dao = ParticipantDao() self.no_filter_query = Query([], None, 2, None) self.one_filter_query = Query( [FieldFilter("participantId", Operator.EQUALS, 1)], None, 2, None) self.two_filter_query = Query([ FieldFilter("participantId", Operator.EQUALS, 1), FieldFilter("hpoId", Operator.EQUALS, PITT_HPO_ID) ], None, 2, None) self.ascending_biobank_id_query = Query([], OrderBy("biobankId", True), 2, None) self.descending_biobank_id_query = Query([], OrderBy("biobankId", False), 2, None) self.enrollment_status_order_query = Query([], OrderBy( "enrollmentStatus", True), 2, None) self.hpo_id_order_query = Query([], OrderBy("hpoId", True), 2, None) self.first_name_order_query = Query([], OrderBy("firstName", True), 2, None)
def generate_samples(fraction_missing): """Creates fake sample CSV data in GCS. Args: fraction_missing: This many samples which exist as BiobankStoredSamples will not have rows generated in the fake CSV. """ bucket_name = config.getSetting(config.BIOBANK_SAMPLES_BUCKET_NAME) now = clock.CLOCK.now() file_name = '/%s/fake_%s.csv' % (bucket_name, now.strftime(INPUT_CSV_TIME_FORMAT)) num_rows = 0 sample_id_start = random.randint(1000000, 10000000) with cloudstorage_api.open(file_name, mode='w') as dest: writer = csv.writer(dest, delimiter="\t") writer.writerow(_HEADERS) biobank_order_dao = BiobankOrderDao() with biobank_order_dao.session() as session: rows = biobank_order_dao.get_ordered_samples_sample( session, 1 - fraction_missing, _BATCH_SIZE) for biobank_id, collected_time, test in rows: if collected_time is None: logging.warning( 'biobank_id=%s test=%s skipped (collected=%s)', biobank_id, test, collected_time) continue minutes_delta = random.randint( 0, _MAX_MINUTES_BETWEEN_SAMPLE_COLLECTED_AND_CONFIRMED) confirmed_time = collected_time + datetime.timedelta( minutes=minutes_delta) writer.writerow([ sample_id_start + num_rows, None, # no parent confirmed_time.strftime(_TIME_FORMAT), to_client_biobank_id(biobank_id), test, confirmed_time.strftime(_TIME_FORMAT), 'KIT' ]) # reuse confirmed time as created time num_rows += 1 participant_dao = ParticipantDao() with participant_dao.session() as session: rows = participant_dao.get_biobank_ids_sample( session, _PARTICIPANTS_WITH_ORPHAN_SAMPLES, _BATCH_SIZE) for biobank_id, sign_up_time in rows: minutes_delta = random.randint( 0, _MAX_MINUTES_BETWEEN_PARTICIPANT_CREATED_AND_CONFIRMED) confirmed_time = sign_up_time + datetime.timedelta( minutes=minutes_delta) tests = random.sample(BIOBANK_TESTS, random.randint(1, len(BIOBANK_TESTS))) for test in tests: writer.writerow([ sample_id_start + num_rows, None, confirmed_time.strftime(_TIME_FORMAT), to_client_biobank_id(biobank_id), test, confirmed_time.strftime(_TIME_FORMAT), 'KIT' ]) num_rows += 1 logging.info("Generated %d samples in %s.", num_rows, file_name)
def test_generate_samples(self): participant_id = self.send_post('Participant', {})['participantId'] self.send_consent(participant_id) self.send_post( 'Participant/%s/BiobankOrder' % participant_id, load_biobank_order_json( from_client_participant_id(participant_id))) # Sanity check that the orders were created correctly. bo_dao = BiobankOrderDao() self.assertEquals(1, bo_dao.count()) order = bo_dao.get_all()[0] self.assertEquals( 11, len(bo_dao.get_with_children(order.biobankOrderId).samples)) self.send_post('DataGen', { 'create_biobank_samples': True, 'samples_missing_fraction': 0.0 }) upsert_from_latest_csv( ) # Run the (usually offline) Biobank CSV import job. self.assertEquals(11, BiobankStoredSampleDao().count()) ps = ParticipantSummaryDao().get( from_client_participant_id(participant_id)) self.assertEquals(SampleStatus.RECEIVED, ps.samplesToIsolateDNA) self.assertEquals(10, ps.numBaselineSamplesArrived)
def test_to_json(self): order = self._make_biobank_order() order_json = BiobankOrderDao().to_client_json(order) expected_order_json = load_biobank_order_json( self.participant.participantId) for key in ('createdInfo', 'collectedInfo', 'processedInfo', 'finalizedInfo'): self.assertEquals(expected_order_json[key], order_json.get(key))
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 _make_biobank_order(self, **kwargs): """Makes a new BiobankOrder (same values every time) with valid/complete defaults. Kwargs pass through to BiobankOrder constructor, overriding defaults. """ participant_id = kwargs['participantId'] for k, default_value in ( ('biobankOrderId', u'1'), ('created', clock.CLOCK.now()), ('sourceSiteId', 1), ('sourceUsername', u'*****@*****.**'), ('collectedSiteId', 1), ('collectedUsername', u'*****@*****.**'), ('processedSiteId', 1), ('processedUsername', u'*****@*****.**'), ('finalizedSiteId', 2), ('finalizedUsername', u'*****@*****.**'), ('version', 1), ('identifiers', [BiobankOrderIdentifier(system=u'a', value=u'c')]), ('samples', [ BiobankOrderedSample(test=u'1SAL2', description=u'description', processingRequired=True) ]), ('dvOrders', [BiobankDVOrder(participantId=participant_id, version=1)])): if k not in kwargs: kwargs[k] = default_value biobank_order = BiobankOrderDao().insert(BiobankOrder(**kwargs)) return biobank_order
def test_dv_order_sample_update(self): """ Test Biobank Direct Volunteer order """ participant = self.participant_dao.insert(Participant()) self.summary_dao.insert(self.participant_summary(participant)) created_ts = datetime.datetime(2019, 03, 22, 18, 30, 45) confirmed_ts = datetime.datetime(2019, 03, 23, 12, 13, 00) bo = self._make_biobank_order(participantId=participant.participantId) BiobankOrderDao().insert(bo) boi = bo.identifiers[0] bss = BiobankStoredSample(biobankStoredSampleId=u'23523523', biobankId=participant.biobankId, test=u'1SAL2', created=created_ts, biobankOrderIdentifier=boi.value, confirmed=confirmed_ts) with self.participant_dao.session() as session: session.add(bss) ps = self.summary_dao.get(participant.participantId) self.assertIsNone(ps.sampleStatusDV1SAL2) self.assertIsNone(ps.sampleStatusDV1SAL2Time) self.summary_dao.update_from_biobank_stored_samples() ps = self.summary_dao.get(participant.participantId) self.assertEqual(ps.sampleStatus1SAL2, SampleStatus.RECEIVED) self.assertEqual(ps.sampleStatus1SAL2Time, confirmed_ts)
def test_read_from_csv_file(self): participant = self.participant_dao.insert(Participant(participantId=123, biobankId=1234)) self.summary_dao.insert(self.participant_summary(participant)) bo = self._make_biobank_order(participantId=participant.participantId, biobankOrderId='123', identifiers=[BiobankOrderIdentifier( system=u'https://www.pmi-ops.org', value=u'12345678')]) BiobankOrderDao().insert(bo) participant2 = self.participant_dao.insert(Participant(participantId=124, biobankId=1235)) self.summary_dao.insert(self.participant_summary(participant2)) bo2 = self._make_biobank_order(participantId=participant2.participantId, biobankOrderId='124', identifiers=[BiobankOrderIdentifier( system=u'https://www.pmi-ops.org', value=u'12345679')]) BiobankOrderDao().insert(bo2) participant3 = self.participant_dao.insert(Participant(participantId=125, biobankId=1236)) self.summary_dao.insert(self.participant_summary(participant3)) bo3 = self._make_biobank_order(participantId=participant3.participantId, biobankOrderId='125', identifiers=[BiobankOrderIdentifier( system=u'https://www.pmi-ops.org', value=u'12345680')]) BiobankOrderDao().insert(bo3) samples_file = test_data.open_genomic_set_file('Genomic-Test-Set-test-1.csv') input_filename = 'cloud%s.csv' % self._naive_utc_to_naive_central(clock.CLOCK.now()).strftime( genomic_set_file_handler.INPUT_CSV_TIME_FORMAT) self._write_cloud_csv(input_filename, samples_file) genomic_set_file_handler.read_genomic_set_from_bucket() set_dao = GenomicSetDao() obj = set_dao.get_all()[0] self.assertEqual(obj.genomicSetName, 'name_xxx') self.assertEqual(obj.genomicSetCriteria, 'criteria_xxx') self.assertEqual(obj.genomicSetVersion, 1) member_dao = GenomicSetMemberDao() items = member_dao.get_all() for item in items: self.assertIn(item.participantId, [123, 124, 125]) self.assertIn(item.biobankOrderId, ['123', '124', '125']) self.assertIn(item.biobankId, ['1234', '1235', '1236']) self.assertIn(item.biobankOrderClientId, ['12345678', '12345679', '12345680']) self.assertEqual(item.genomicSetId, 1) self.assertIn(item.genomeType, ['aou_wgs', 'aou_array']) self.assertIn(item.nyFlag, [0, 1]) self.assertIn(item.sexAtBirth, ['F', 'M'])
def calculate_distinct_visits(self, pid, finalized_time, id_, amendment=False): """ Participants may get PM or biobank samples on same day. This should be considered as a single visit in terms of program payment to participant. return Boolean: true if there has not been an order on same date.""" from dao.biobank_order_dao import BiobankOrderDao from dao.physical_measurements_dao import PhysicalMeasurementsDao day_has_order, day_has_measurement = False, False existing_orders = BiobankOrderDao().get_biobank_orders_for_participant( pid) ordered_samples = BiobankOrderDao( ).get_ordered_samples_for_participant(pid) existing_measurements = PhysicalMeasurementsDao( ).get_measuremnets_for_participant(pid) order_id_to_finalized_date = { sample.biobankOrderId: sample.finalized.date() for sample in ordered_samples if sample.finalized } if existing_orders and finalized_time: for order in existing_orders: order_finalized_date = order_id_to_finalized_date.get( order.biobankOrderId) if order_finalized_date == finalized_time.date() and order.biobankOrderId != id_ and \ order.orderStatus != BiobankOrderStatus.CANCELLED: day_has_order = True elif order.biobankOrderId == id_ and order.orderStatus == BiobankOrderStatus.AMENDED: day_has_order = True elif not finalized_time and amendment: day_has_order = True if existing_measurements and finalized_time: for measurement in existing_measurements: if not measurement.finalized: continue if measurement.finalized.date() == finalized_time.date() and measurement.physicalMeasurementsId\ != id_: day_has_measurement = True is_distinct_visit = not (day_has_order or day_has_measurement) return is_distinct_visit
def insert_biobank_order(self, pid, resource): obj = BiobankOrder() obj.participantId = long(pid) obj.created = clock.CLOCK.now() obj.created = datetime.datetime.now() obj.orderStatus = BiobankOrderStatus.UNSET obj.biobankOrderId = resource['biobankOrderId'] test = self.get(resource['id']) obj.dvOrders = [test] bod = BiobankOrderDao() obj.samples = [ BiobankOrderedSample(test='1SAL2', processingRequired=False, description=u'salivary pilot kit') ] self._add_identifiers_and_main_id(obj, ObjectView(resource)) bod.insert(obj)
def setUp(self): super(PhysicalMeasurementsDaoTest, self).setUp() self.participant = Participant(participantId=1, biobankId=2) ParticipantDao().insert(self.participant) self.dao = PhysicalMeasurementsDao() self.participant_summary_dao = ParticipantSummaryDao() self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId, TIME_1.isoformat())) self.biobank = BiobankOrderDao()
def setUp(self): super(BigQuerySyncDaoTest, self).setUp(use_mysql=True, with_consent_codes=True) self.dao = ParticipantDao() with self.dao.session() as session: self.site = session.query(Site).filter( Site.googleGroup == 'hpo-site-monroeville').first() self.hpo = session.query(HPO).filter(HPO.name == 'PITT').first() with clock.FakeClock(self.TIME_1): self.participant = Participant(participantId=123, biobankId=555) self.participant.hpoId = self.hpo.hpoId self.participant.siteId = self.site.siteId self.dao.insert(self.participant) ps = ParticipantSummary( participantId=123, biobankId=555, firstName='john', lastName='doe', withdrawalStatus=WithdrawalStatus.NOT_WITHDRAWN, suspensionStatus=SuspensionStatus.NOT_SUSPENDED) ps.hpoId = self.hpo.hpoId ps.siteId = self.site.siteId self.summary = ParticipantSummaryDao().insert(ps) self.pm_json = json.dumps( load_measurement_json(self.participant.participantId, self.TIME_1.isoformat())) self.pm = PhysicalMeasurementsDao().insert( self._make_physical_measurements()) with clock.FakeClock(self.TIME_2): self.dao = BiobankOrderDao() self.bio_order = BiobankOrderDao().insert( self._make_biobank_order( participantId=self.participant.participantId))
def test_from_json(self): ParticipantSummaryDao().insert( self.participant_summary(self.participant)) order_json = load_biobank_order_json(self.participant.participantId) order = BiobankOrderDao().from_client_json( order_json, participant_id=self.participant.participantId) self.assertEquals(1, order.sourceSiteId) self.assertEquals('*****@*****.**', order.sourceUsername) self.assertEquals(1, order.collectedSiteId) self.assertEquals('*****@*****.**', order.collectedUsername) self.assertEquals(1, order.processedSiteId) self.assertEquals('*****@*****.**', order.processedUsername) self.assertEquals(2, order.finalizedSiteId) self.assertEquals('*****@*****.**', order.finalizedUsername)
def test_from_json(self): ParticipantSummaryDao().insert(self.participant_summary(self.participant)) order_json = load_biobank_order_json(self.participant.participantId) order = BiobankOrderDao().from_client_json(order_json, participant_id=self.participant.participantId) self.assertEquals(1, order.sourceSiteId) self.assertEquals('*****@*****.**', order.sourceUsername) self.assertEquals(1, order.collectedSiteId) self.assertEquals('*****@*****.**', order.collectedUsername) self.assertEquals(1, order.processedSiteId) self.assertEquals('*****@*****.**', order.processedUsername) self.assertEquals(2, order.finalizedSiteId) self.assertEquals('*****@*****.**', order.finalizedUsername) # testing finalized_time samples_finalized_time = None for sample in order_json['samples']: samples_finalized_time = parse_date(sample['finalized']) break self.assertEquals(samples_finalized_time, order.finalizedTime)
def __init__(self): super(BiobankOrderApi, self).__init__(BiobankOrderDao(), get_returns_children=True)
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()
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' })
def test_create_genomic_set_result_file(self): participant = self.participant_dao.insert(Participant(participantId=123, biobankId=123)) self.summary_dao.insert(self.participant_summary(participant)) bo = self._make_biobank_order(participantId=participant.participantId, biobankOrderId='123', identifiers=[BiobankOrderIdentifier( system=u'https://www.pmi-ops.org', value=u'12345678')]) BiobankOrderDao().insert(bo) participant2 = self.participant_dao.insert(Participant(participantId=124, biobankId=124)) self.summary_dao.insert(self.participant_summary(participant2)) bo2 = self._make_biobank_order(participantId=participant2.participantId, biobankOrderId='124', identifiers=[BiobankOrderIdentifier( system=u'https://www.pmi-ops.org', value=u'12345679')]) BiobankOrderDao().insert(bo2) participant3 = self.participant_dao.insert(Participant(participantId=125, biobankId=125)) self.summary_dao.insert(self.participant_summary(participant3)) bo3 = self._make_biobank_order(participantId=participant3.participantId, biobankOrderId='125', identifiers=[BiobankOrderIdentifier( system=u'https://www.pmi-ops.org', value=u'12345680')]) BiobankOrderDao().insert(bo3) genomic_set = self._create_fake_genomic_set('fake_genomic_set_name', 'fake_genomic_set_criteria', 'Genomic-Test-Set-v12019-04-05-00-30-10.CSV') self._create_fake_genomic_member(genomic_set.id, participant.participantId, bo.biobankOrderId, participant.biobankId, bo.identifiers[0].value, validation_status=GenomicValidationStatus.VALID, sex_at_birth='F', genome_type='aou_array', ny_flag='Y') self._create_fake_genomic_member(genomic_set.id, participant2.participantId, bo2.biobankOrderId, participant2.biobankId, bo2.identifiers[0].value, validation_status=GenomicValidationStatus.INVALID_AGE, sex_at_birth='M', genome_type='aou_array', ny_flag='N') self._create_fake_genomic_member(genomic_set.id, participant3.participantId, bo3.biobankOrderId, participant3.biobankId, bo3.identifiers[0].value, validation_status=GenomicValidationStatus.INVALID_CONSENT, sex_at_birth='F', genome_type='aou_wgs', ny_flag='Y') genomic_set_file_handler.create_genomic_set_status_result_file(genomic_set.id) expected_result_filename = 'Genomic-Test-Set-v12019-04-05-00-30-10-Validation-Result.CSV' bucket_name = config.getSetting(config.GENOMIC_SET_BUCKET_NAME) path = '/' + bucket_name + '/' + expected_result_filename csv_file = cloudstorage_api.open(path) csv_reader = csv.DictReader(csv_file, delimiter=',') class ResultCsvColumns(object): """Names of CSV columns that we read from the genomic set upload.""" GENOMIC_SET_NAME = 'genomic_set_name' GENOMIC_SET_CRITERIA = 'genomic_set_criteria' PID = 'pid' BIOBANK_ORDER_ID = 'biobank_order_id' NY_FLAG = 'ny_flag' SEX_AT_BIRTH = 'sex_at_birth' GENOME_TYPE = 'genome_type' STATUS = 'status' INVALID_REASON = 'invalid_reason' ALL = (GENOMIC_SET_NAME, GENOMIC_SET_CRITERIA, PID, BIOBANK_ORDER_ID, NY_FLAG, SEX_AT_BIRTH, GENOME_TYPE, STATUS, INVALID_REASON) missing_cols = set(ResultCsvColumns.ALL) - set(csv_reader.fieldnames) self.assertEqual(len(missing_cols), 0) rows = list(csv_reader) self.assertEqual(len(rows), 3) self.assertEqual(rows[0][ResultCsvColumns.GENOMIC_SET_NAME], 'fake_genomic_set_name') self.assertEqual(rows[0][ResultCsvColumns.GENOMIC_SET_CRITERIA], 'fake_genomic_set_criteria') self.assertEqual(rows[0][ResultCsvColumns.STATUS], 'valid') self.assertEqual(rows[0][ResultCsvColumns.INVALID_REASON], '') self.assertEqual(rows[0][ResultCsvColumns.PID], '123') self.assertEqual(rows[0][ResultCsvColumns.BIOBANK_ORDER_ID], '123') self.assertEqual(rows[0][ResultCsvColumns.NY_FLAG], 'Y') self.assertEqual(rows[0][ResultCsvColumns.GENOME_TYPE], 'aou_array') self.assertEqual(rows[0][ResultCsvColumns.SEX_AT_BIRTH], 'F') self.assertEqual(rows[1][ResultCsvColumns.GENOMIC_SET_NAME], 'fake_genomic_set_name') self.assertEqual(rows[1][ResultCsvColumns.GENOMIC_SET_CRITERIA], 'fake_genomic_set_criteria') self.assertEqual(rows[1][ResultCsvColumns.STATUS], 'invalid') self.assertEqual(rows[1][ResultCsvColumns.INVALID_REASON], 'INVALID_AGE') self.assertEqual(rows[1][ResultCsvColumns.PID], '124') self.assertEqual(rows[1][ResultCsvColumns.BIOBANK_ORDER_ID], '124') self.assertEqual(rows[1][ResultCsvColumns.NY_FLAG], 'N') self.assertEqual(rows[1][ResultCsvColumns.GENOME_TYPE], 'aou_array') self.assertEqual(rows[1][ResultCsvColumns.SEX_AT_BIRTH], 'M') self.assertEqual(rows[2][ResultCsvColumns.GENOMIC_SET_NAME], 'fake_genomic_set_name') self.assertEqual(rows[2][ResultCsvColumns.GENOMIC_SET_CRITERIA], 'fake_genomic_set_criteria') self.assertEqual(rows[2][ResultCsvColumns.STATUS], 'invalid') self.assertEqual(rows[2][ResultCsvColumns.INVALID_REASON], 'INVALID_CONSENT') self.assertEqual(rows[2][ResultCsvColumns.PID], '125') self.assertEqual(rows[2][ResultCsvColumns.BIOBANK_ORDER_ID], '125') self.assertEqual(rows[2][ResultCsvColumns.NY_FLAG], 'Y') self.assertEqual(rows[2][ResultCsvColumns.GENOME_TYPE], 'aou_wgs') self.assertEqual(rows[2][ResultCsvColumns.SEX_AT_BIRTH], 'F')
def test_create_and_upload_biobank_manifest_file(self): participant = self.participant_dao.insert(Participant(participantId=123, biobankId=123)) self.summary_dao.insert(self.participant_summary(participant)) bo = self._make_biobank_order(participantId=participant.participantId, biobankOrderId='123', identifiers=[BiobankOrderIdentifier( system=u'https://www.pmi-ops.org', value=u'12345678')]) BiobankOrderDao().insert(bo) participant2 = self.participant_dao.insert(Participant(participantId=124, biobankId=124)) self.summary_dao.insert(self.participant_summary(participant2)) bo2 = self._make_biobank_order(participantId=participant2.participantId, biobankOrderId='124', identifiers=[BiobankOrderIdentifier( system=u'https://www.pmi-ops.org', value=u'12345679')]) BiobankOrderDao().insert(bo2) participant3 = self.participant_dao.insert(Participant(participantId=125, biobankId=125)) self.summary_dao.insert(self.participant_summary(participant3)) bo3 = self._make_biobank_order(participantId=participant3.participantId, biobankOrderId='125', identifiers=[BiobankOrderIdentifier( system=u'https://www.pmi-ops.org', value=u'12345680')]) BiobankOrderDao().insert(bo3) genomic_set = self._create_fake_genomic_set('fake_genomic_set_name', 'fake_genomic_set_criteria', 'Genomic-Test-Set-v12019-04-05-00-30-10.CSV') self._create_fake_genomic_member(genomic_set.id, participant.participantId, bo.biobankOrderId, participant.biobankId, bo.identifiers[0].value, validation_status=GenomicValidationStatus.VALID, sex_at_birth='F', genome_type='aou_array', ny_flag='Y') self._create_fake_genomic_member(genomic_set.id, participant2.participantId, bo2.biobankOrderId, participant2.biobankId, bo2.identifiers[0].value, validation_status=GenomicValidationStatus.INVALID_AGE, sex_at_birth='M', genome_type='aou_array', ny_flag='N') self._create_fake_genomic_member(genomic_set.id, participant3.participantId, bo3.biobankOrderId, participant3.biobankId, bo3.identifiers[0].value, validation_status=GenomicValidationStatus.INVALID_CONSENT, sex_at_birth='F', genome_type='aou_wgs', ny_flag='Y') now = clock.CLOCK.now() genomic_biobank_menifest_handler\ .create_and_upload_genomic_biobank_manifest_file(genomic_set.id, now) bucket_name = config.getSetting(config.BIOBANK_SAMPLES_BUCKET_NAME) # convert UTC to CDT now_cdt_str = _UTC.localize(now).astimezone(_US_CENTRAL).replace(tzinfo=None) \ .strftime(_OUTPUT_CSV_TIME_FORMAT) class ExpectedCsvColumns(object): VALUE = 'value' BIOBANK_ID = 'biobank_id' SEX_AT_BIRTH = 'sex_at_birth' GENOME_TYPE = 'genome_type' NY_FLAG = 'ny_flag' REQUEST_ID = 'request_id' PACKAGE_ID = 'package_id' ALL = (VALUE, SEX_AT_BIRTH, GENOME_TYPE, NY_FLAG, REQUEST_ID, PACKAGE_ID) expected_result_filename = 'rdr_fake_sub_folder/Genomic-Manifest-AoU-1-v1' + \ now_cdt_str + '.CSV' path = '/' + bucket_name + '/' + expected_result_filename csv_file = cloudstorage_api.open(path) csv_reader = csv.DictReader(csv_file, delimiter=',') missing_cols = set(ExpectedCsvColumns.ALL) - set(csv_reader.fieldnames) self.assertEqual(len(missing_cols), 0) rows = list(csv_reader) self.assertEqual(rows[0][ExpectedCsvColumns.VALUE], '12345678') self.assertEqual(rows[0][ExpectedCsvColumns.BIOBANK_ID], '123') self.assertEqual(rows[0][ExpectedCsvColumns.SEX_AT_BIRTH], 'F') self.assertEqual(rows[0][ExpectedCsvColumns.GENOME_TYPE], 'aou_array') self.assertEqual(rows[0][ExpectedCsvColumns.NY_FLAG], 'Y') self.assertEqual(rows[1][ExpectedCsvColumns.VALUE], '12345679') self.assertEqual(rows[1][ExpectedCsvColumns.BIOBANK_ID], '124') self.assertEqual(rows[1][ExpectedCsvColumns.SEX_AT_BIRTH], 'M') self.assertEqual(rows[1][ExpectedCsvColumns.GENOME_TYPE], 'aou_array') self.assertEqual(rows[1][ExpectedCsvColumns.NY_FLAG], 'N') self.assertEqual(rows[2][ExpectedCsvColumns.VALUE], '12345680') self.assertEqual(rows[2][ExpectedCsvColumns.BIOBANK_ID], '125') self.assertEqual(rows[2][ExpectedCsvColumns.SEX_AT_BIRTH], 'F') self.assertEqual(rows[2][ExpectedCsvColumns.GENOME_TYPE], 'aou_wgs') self.assertEqual(rows[2][ExpectedCsvColumns.NY_FLAG], 'Y')
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)
def setUp(self): super(BiobankOrderDaoTest, self).setUp(use_mysql=True) self.participant = Participant(participantId=123, biobankId=555) ParticipantDao().insert(self.participant) self.dao = BiobankOrderDao()
class BiobankOrderDaoTest(SqlTestBase): _A_TEST = BIOBANK_TESTS[0] _B_TEST = BIOBANK_TESTS[1] TIME_1 = datetime.datetime(2018, 9, 20, 5, 49, 11) TIME_2 = datetime.datetime(2018, 9, 21, 8, 49, 37) def setUp(self): super(BiobankOrderDaoTest, self).setUp(use_mysql=True) self.participant = Participant(participantId=123, biobankId=555) ParticipantDao().insert(self.participant) self.dao = BiobankOrderDao() def _make_biobank_order(self, **kwargs): """Makes a new BiobankOrder (same values every time) with valid/complete defaults. Kwargs pass through to BiobankOrder constructor, overriding defaults. """ for k, default_value in ( ('biobankOrderId', '1'), ('created', clock.CLOCK.now()), ('participantId', self.participant.participantId), ('sourceSiteId', 1), ('sourceUsername', '*****@*****.**'), ('collectedSiteId', 1), ('collectedUsername', '*****@*****.**'), ('processedSiteId', 1), ('processedUsername', '*****@*****.**'), ('finalizedSiteId', 2), ('finalizedUsername', '*****@*****.**'), ('identifiers', [BiobankOrderIdentifier(system='a', value='c')]), ('samples', [BiobankOrderedSample( biobankOrderId='1', test=self._A_TEST, finalized=self.TIME_2, description='description', processingRequired=True)])): if k not in kwargs: kwargs[k] = default_value return BiobankOrder(**kwargs) @staticmethod def _get_cancel_patch(): return { "amendedReason": 'I messed something up :( ', "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" } @staticmethod def _get_restore_patch(): return { "amendedReason": 'I didn"t mess something up :( ', "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" } @staticmethod def _get_amended_info(order): amendment = dict(amendedReason='I had to change something', amendedInfo={ "author": { "system": "https://www.pmi-ops.org/healthpro-username", "value": "*****@*****.**" }, "site": { "system": "https://www.pmi-ops.org/site-id", "value": "hpo-site-monroeville" } }) order.amendedReason = amendment['amendedReason'] order.amendedInfo = amendment['amendedInfo'] return order def test_bad_participant(self): with self.assertRaises(BadRequest): self.dao.insert(self._make_biobank_order(participantId=999)) def test_from_json(self): ParticipantSummaryDao().insert(self.participant_summary(self.participant)) order_json = load_biobank_order_json(self.participant.participantId) order = BiobankOrderDao().from_client_json(order_json, participant_id=self.participant.participantId) self.assertEquals(1, order.sourceSiteId) self.assertEquals('*****@*****.**', order.sourceUsername) self.assertEquals(1, order.collectedSiteId) self.assertEquals('*****@*****.**', order.collectedUsername) self.assertEquals(1, order.processedSiteId) self.assertEquals('*****@*****.**', order.processedUsername) self.assertEquals(2, order.finalizedSiteId) self.assertEquals('*****@*****.**', order.finalizedUsername) # testing finalized_time samples_finalized_time = None for sample in order_json['samples']: samples_finalized_time = parse_date(sample['finalized']) break self.assertEquals(samples_finalized_time, order.finalizedTime) def test_to_json(self): order = self._make_biobank_order() order_json = self.dao.to_client_json(order) expected_order_json = load_biobank_order_json(self.participant.participantId) for key in ('createdInfo', 'collectedInfo', 'processedInfo', 'finalizedInfo'): self.assertEquals(expected_order_json[key], order_json.get(key)) def test_duplicate_insert_ok(self): ParticipantSummaryDao().insert(self.participant_summary(self.participant)) order_1 = self.dao.insert(self._make_biobank_order(created=self.TIME_1)) order_2 = self.dao.insert(self._make_biobank_order(created=self.TIME_1)) self.assertEquals(order_1.asdict(), order_2.asdict()) def test_same_id_different_identifier_not_ok(self): ParticipantSummaryDao().insert(self.participant_summary(self.participant)) self.dao.insert(self._make_biobank_order( identifiers=[BiobankOrderIdentifier(system='a', value='b')])) with self.assertRaises(Conflict): self.dao.insert(self._make_biobank_order( identifiers=[BiobankOrderIdentifier(system='a', value='c')])) def test_reject_used_identifier(self): ParticipantSummaryDao().insert(self.participant_summary(self.participant)) self.dao.insert(self._make_biobank_order( biobankOrderId='1', identifiers=[BiobankOrderIdentifier(system='a', value='b')])) with self.assertRaises(BadRequest): self.dao.insert(self._make_biobank_order( biobankOrderId='2', identifiers=[BiobankOrderIdentifier(system='a', value='b')])) def test_order_for_withdrawn_participant_fails(self): self.participant.withdrawalStatus = WithdrawalStatus.NO_USE ParticipantDao().update(self.participant) ParticipantSummaryDao().insert(self.participant_summary(self.participant)) with self.assertRaises(Forbidden): self.dao.insert(self._make_biobank_order(participantId=self.participant.participantId)) def test_get_for_withdrawn_participant_fails(self): ParticipantSummaryDao().insert(self.participant_summary(self.participant)) self.dao.insert(self._make_biobank_order( biobankOrderId='1', participantId=self.participant.participantId)) self.participant.version += 1 self.participant.withdrawalStatus = WithdrawalStatus.NO_USE ParticipantDao().update(self.participant) with self.assertRaises(Forbidden): self.dao.get(1) def test_store_invalid_test(self): with self.assertRaises(BadRequest): self.dao.insert(self._make_biobank_order( samples=[BiobankOrderedSample( test='InvalidTestName', processingRequired=True, description=u'tested it')])) def test_cancelling_an_order(self): ParticipantSummaryDao().insert(self.participant_summary(self.participant)) order_1 = self.dao.insert(self._make_biobank_order()) cancelled_request = self._get_cancel_patch() self.assertEqual(order_1.version, 1) self.assertEqual(order_1.orderStatus, None) updated_order = self.dao.update_with_patch(order_1.biobankOrderId, cancelled_request, order_1.version) self.assertEqual(updated_order.version, 2) self.assertEqual(updated_order.cancelledUsername, '*****@*****.**') self.assertEqual(updated_order.orderStatus, BiobankOrderStatus.CANCELLED) self.assertEqual(updated_order.amendedReason, cancelled_request['amendedReason']) ps_dao = ParticipantSummaryDao().get(self.participant.participantId) self.assertEqual(ps_dao.biospecimenFinalizedSiteId, None) def test_cancelled_order_removes_from_participant_summary(self): ParticipantSummaryDao().insert(self.participant_summary(self.participant)) samples = [BiobankOrderedSample( test=self._B_TEST, processingRequired=True, description=u'new sample')] biobank_order_id = 2 with clock.FakeClock(self.TIME_1): order_1 = self.dao.insert(self._make_biobank_order()) with clock.FakeClock(self.TIME_2): self.dao.insert(self._make_biobank_order(samples=samples, biobankOrderId=biobank_order_id, identifiers=[ BiobankOrderIdentifier(system='z', value='x')])) cancelled_request = self._get_cancel_patch() ps_dao = ParticipantSummaryDao().get(self.participant.participantId) self.assertEqual(ps_dao.sampleOrderStatus1ED10, OrderStatus.FINALIZED) self.assertEqual(ps_dao.sampleOrderStatus1ED10Time, self.TIME_2) self.assertEqual(ps_dao.sampleOrderStatus2ED10, OrderStatus.CREATED) self.assertEqual(ps_dao.sampleOrderStatus2ED10Time, self.TIME_2) self.dao.update_with_patch(order_1.biobankOrderId, cancelled_request, order_1.version) ps_dao = ParticipantSummaryDao().get(self.participant.participantId) self.assertEqual(ps_dao.sampleOrderStatus1ED10, None) self.assertEqual(ps_dao.sampleOrderStatus1ED10Time, None) # should not remove the other order self.assertEqual(ps_dao.sampleOrderStatus2ED10, OrderStatus.CREATED) self.assertEqual(ps_dao.sampleOrderStatus2ED10Time, self.TIME_2) self.assertEqual(ps_dao.biospecimenCollectedSiteId, 1) self.assertEqual(ps_dao.biospecimenFinalizedSiteId, 2) self.assertEqual(ps_dao.biospecimenProcessedSiteId, 1) self.assertEqual(ps_dao.biospecimenStatus, OrderStatus.FINALIZED) def test_restoring_an_order_gets_to_participant_summary(self): ParticipantSummaryDao().insert(self.participant_summary(self.participant)) order_1 = self.dao.insert(self._make_biobank_order()) cancelled_request = self._get_cancel_patch() cancelled_order = self.dao.update_with_patch(order_1.biobankOrderId, cancelled_request, order_1.version) restore_request = self._get_restore_patch() self.dao.update_with_patch(order_1.biobankOrderId, restore_request, cancelled_order.version) ps_dao = ParticipantSummaryDao().get(self.participant.participantId) self.assertEqual(ps_dao.sampleOrderStatus1ED10, OrderStatus.FINALIZED) self.assertEqual(ps_dao.biospecimenStatus, OrderStatus.FINALIZED) self.assertEqual(ps_dao.biospecimenSourceSiteId, 1) self.assertEqual(ps_dao.biospecimenCollectedSiteId, 1) self.assertEqual(ps_dao.biospecimenFinalizedSiteId, 2) self.assertEqual(ps_dao.biospecimenProcessedSiteId, 1) def test_amending_order_participant_summary(self): ParticipantSummaryDao().insert(self.participant_summary(self.participant)) order_1 = self.dao.insert(self._make_biobank_order()) amended_info = self._get_amended_info(order_1) amended_info.sourceSiteId = 2 samples = [BiobankOrderedSample( test=self._B_TEST, processingRequired=True, description=u'new sample')] amended_info.samples = samples with self.dao.session() as session: self.dao._do_update(session, amended_info, order_1) amended_order = self.dao.get(1) self.assertEqual(amended_order.version, 2) ps_dao = ParticipantSummaryDao().get(self.participant.participantId) self.assertEqual(ps_dao.sampleOrderStatus2ED10, OrderStatus.CREATED) self.assertEqual(ps_dao.sampleOrderStatus1ED10, OrderStatus.FINALIZED) self.assertEqual(ps_dao.numberDistinctVisits, 1) def test_cancelling_an_order_missing_reason(self): ParticipantSummaryDao().insert(self.participant_summary(self.participant)) order_1 = self.dao.insert(self._make_biobank_order()) cancelled_request = self._get_cancel_patch() del cancelled_request['amendedReason'] with self.assertRaises(BadRequest): self.dao.update_with_patch(order_1.biobankOrderId, cancelled_request, order_1.version) def test_cancelling_an_order_missing_info(self): ParticipantSummaryDao().insert(self.participant_summary(self.participant)) order_1 = self.dao.insert(self._make_biobank_order()) # missing cancelled info cancelled_request = self._get_cancel_patch() del cancelled_request['cancelledInfo'] with self.assertRaises(BadRequest): self.dao.update_with_patch(order_1.biobankOrderId, cancelled_request, order_1.version) # missing site cancelled_request = self._get_cancel_patch() del cancelled_request['cancelledInfo']['site'] with self.assertRaises(BadRequest): self.dao.update_with_patch(order_1.biobankOrderId, cancelled_request, order_1.version) # missing author cancelled_request = self._get_cancel_patch() del cancelled_request['cancelledInfo']['author'] with self.assertRaises(BadRequest): self.dao.update_with_patch(order_1.biobankOrderId, cancelled_request, order_1.version) # missing status cancelled_request = self._get_cancel_patch() del cancelled_request['status'] with self.assertRaises(BadRequest): self.dao.update_with_patch(order_1.biobankOrderId, cancelled_request, order_1.version) def test_restoring_an_order(self): ParticipantSummaryDao().insert(self.participant_summary(self.participant)) order_1 = self.dao.insert(self._make_biobank_order()) cancelled_request = self._get_cancel_patch() cancelled_order = self.dao.update_with_patch(order_1.biobankOrderId, cancelled_request, order_1.version) ps_dao = ParticipantSummaryDao().get(self.participant.participantId) self.assertEqual(ps_dao.numberDistinctVisits, 0) restore_request = self._get_restore_patch() restored_order = self.dao.update_with_patch(order_1.biobankOrderId, restore_request, cancelled_order.version) self.assertEqual(restored_order.version, 3) self.assertEqual(restored_order.restoredUsername, '*****@*****.**') self.assertEqual(restored_order.orderStatus, BiobankOrderStatus.UNSET) self.assertEqual(restored_order.amendedReason, restore_request['amendedReason']) ps_dao = ParticipantSummaryDao().get(self.participant.participantId) self.assertEqual(ps_dao.numberDistinctVisits, 1) def test_amending_an_order(self): ParticipantSummaryDao().insert(self.participant_summary(self.participant)) order_1 = self.dao.insert(self._make_biobank_order()) amended_info = self._get_amended_info(order_1) amended_info.sourceSiteId = 2 with self.dao.session() as session: self.dao._do_update(session, order_1, amended_info) amended_order = self.dao.get(1) self.assertEqual(amended_order.version, 2) self.assertEqual(amended_order.orderStatus, BiobankOrderStatus.AMENDED) self.assertEqual(amended_order.amendedReason, 'I had to change something') self.assertEqual(amended_order.amendedSiteId, 1) self.assertEqual(amended_order.amendedUsername, '*****@*****.**')
class BigQuerySyncDaoTest(SqlTestBase): TIME_1 = datetime.datetime(2018, 9, 20, 5, 49, 11) TIME_2 = datetime.datetime(2018, 9, 24, 14, 21, 01) site = None hpo = None participant = None summary = None pm_json = None pm = None bio_order = None def setUp(self): super(BigQuerySyncDaoTest, self).setUp(use_mysql=True, with_consent_codes=True) self.dao = ParticipantDao() with self.dao.session() as session: self.site = session.query(Site).filter( Site.googleGroup == 'hpo-site-monroeville').first() self.hpo = session.query(HPO).filter(HPO.name == 'PITT').first() with clock.FakeClock(self.TIME_1): self.participant = Participant(participantId=123, biobankId=555) self.participant.hpoId = self.hpo.hpoId self.participant.siteId = self.site.siteId self.dao.insert(self.participant) ps = ParticipantSummary( participantId=123, biobankId=555, firstName='john', lastName='doe', withdrawalStatus=WithdrawalStatus.NOT_WITHDRAWN, suspensionStatus=SuspensionStatus.NOT_SUSPENDED) ps.hpoId = self.hpo.hpoId ps.siteId = self.site.siteId self.summary = ParticipantSummaryDao().insert(ps) self.pm_json = json.dumps( load_measurement_json(self.participant.participantId, self.TIME_1.isoformat())) self.pm = PhysicalMeasurementsDao().insert( self._make_physical_measurements()) with clock.FakeClock(self.TIME_2): self.dao = BiobankOrderDao() self.bio_order = BiobankOrderDao().insert( self._make_biobank_order( participantId=self.participant.participantId)) def _make_physical_measurements(self, **kwargs): """Makes a new PhysicalMeasurements (same values every time) with valid/complete defaults. Kwargs pass through to PM constructor, overriding defaults. """ for k, default_value in (('physicalMeasurementsId', 1), ('participantId', self.participant.participantId), ('resource', self.pm_json), ('createdSiteId', self.site.siteId), ('finalizedSiteId', self.site.siteId)): if k not in kwargs: kwargs[k] = default_value return PhysicalMeasurements(**kwargs) def _make_biobank_order(self, **kwargs): """Makes a new BiobankOrder (same values every time) with valid/complete defaults. Kwargs pass through to BiobankOrder constructor, overriding defaults. """ for k, default_value in (('biobankOrderId', '1'), ('created', clock.CLOCK.now()), ('participantId', self.participant.participantId), ('sourceSiteId', 1), ('sourceUsername', '*****@*****.**'), ('collectedSiteId', 1), ('collectedUsername', '*****@*****.**'), ('processedSiteId', 1), ('processedUsername', '*****@*****.**'), ('finalizedSiteId', 2), ('finalizedUsername', '*****@*****.**'), ('identifiers', [ BiobankOrderIdentifier(system='a', value='c') ]), ('samples', [ BiobankOrderedSample( biobankOrderId='1', test=BIOBANK_TESTS[0], description=u'description', finalized=self.TIME_1, processingRequired=True) ])): if k not in kwargs: kwargs[k] = default_value return BiobankOrder(**kwargs) def test_participant_summary_gen(self): gen = BQParticipantSummaryGenerator() ps_json = gen.make_bqrecord(self.participant.participantId) self.assertIsNotNone(ps_json) self.assertEqual(ps_json.sign_up_time, self.TIME_1) self.assertEqual(ps_json['pm'][0]['pm_finalized_site'], 'hpo-site-monroeville') self.assertEqual(ps_json.suspension_status, 'NOT_SUSPENDED') self.assertEqual(ps_json.withdrawal_status, 'NOT_WITHDRAWN') self.assertEqual(ps_json['pm'][0]['pm_status'], 'COMPLETED')
class ParticipantSummaryDaoTest(NdbTestBase): def setUp(self): super(ParticipantSummaryDaoTest, self).setUp(use_mysql=True) self.dao = ParticipantSummaryDao() self.order_dao = BiobankOrderDao() self.measurement_dao = PhysicalMeasurementsDao() self.participant_dao = ParticipantDao() self.no_filter_query = Query([], None, 2, None) self.one_filter_query = Query([FieldFilter("participantId", Operator.EQUALS, 1)], None, 2, None) self.two_filter_query = Query([FieldFilter("participantId", Operator.EQUALS, 1), FieldFilter("hpoId", Operator.EQUALS, PITT_HPO_ID)], None, 2, None) self.ascending_biobank_id_query = Query([], OrderBy("biobankId", True), 2, None) self.descending_biobank_id_query = Query([], OrderBy("biobankId", False), 2, None) self.enrollment_status_order_query = Query([], OrderBy("enrollmentStatus", True), 2, None) self.hpo_id_order_query = Query([], OrderBy("hpoId", True), 2, None) self.first_name_order_query = Query([], OrderBy("firstName", True), 2, None) def assert_no_results(self, query): results = self.dao.query(query) self.assertEquals([], results.items) self.assertIsNone(results.pagination_token) def assert_results(self, query, items, pagination_token=None): results = self.dao.query(query) self.assertListAsDictEquals(items, results.items) self.assertEquals(pagination_token, results.pagination_token, "Pagination tokens don't match; decoded = %s, %s" % (_decode_token(pagination_token), _decode_token(results.pagination_token))) def test_query_with_total(self): num_participants = 5 query = Query([], None, 10, None, include_total=True) results = self.dao.query(query) self.assertEqual(results.total, 0) for i in range(num_participants): participant = Participant(participantId=i, biobankId=i) self._insert(participant) results = self.dao.query(query) self.assertEqual(results.total, num_participants) def testQuery_noSummaries(self): self.assert_no_results(self.no_filter_query) self.assert_no_results(self.one_filter_query) self.assert_no_results(self.two_filter_query) self.assert_no_results(self.ascending_biobank_id_query) self.assert_no_results(self.descending_biobank_id_query) def _insert(self, participant, first_name=None, last_name=None): self.participant_dao.insert(participant) summary = self.participant_summary(participant) if first_name: summary.firstName = first_name if last_name: summary.lastName = last_name self.dao.insert(summary) return participant def testQuery_oneSummary(self): participant = Participant(participantId=1, biobankId=2) self._insert(participant) summary = self.dao.get(1) self.assert_results(self.no_filter_query, [summary]) self.assert_results(self.one_filter_query, [summary]) self.assert_no_results(self.two_filter_query) self.assert_results(self.ascending_biobank_id_query, [summary]) self.assert_results(self.descending_biobank_id_query, [summary]) def testUnicodeNameRoundTrip(self): name = self.fake.first_name() with self.assertRaises(UnicodeEncodeError): str(name) # sanity check that the name contains non-ASCII participant = self._insert(Participant(participantId=1, biobankId=2)) summary = self.dao.get(participant.participantId) summary.firstName = name self.dao.update(summary) fetched_summary = self.dao.get(participant.participantId) self.assertEquals(name, fetched_summary.firstName) def testQuery_twoSummaries(self): participant_1 = Participant(participantId=1, biobankId=2) self._insert(participant_1, 'Alice', 'Smith') participant_2 = Participant(participantId=2, biobankId=1) self._insert(participant_2, 'Zed', 'Zebra') ps_1 = self.dao.get(1) ps_2 = self.dao.get(2) self.assert_results(self.no_filter_query, [ps_1, ps_2]) self.assert_results(self.one_filter_query, [ps_1]) self.assert_no_results(self.two_filter_query) self.assert_results(self.ascending_biobank_id_query, [ps_2, ps_1]) self.assert_results(self.descending_biobank_id_query, [ps_1, ps_2]) def testQuery_threeSummaries_paginate(self): participant_1 = Participant(participantId=1, biobankId=4) self._insert(participant_1, 'Alice', 'Aardvark') participant_2 = Participant(participantId=2, biobankId=1) self._insert(participant_2, 'Bob', 'Builder') participant_3 = Participant(participantId=3, biobankId=3) self._insert(participant_3, 'Chad', 'Caterpillar') ps_1 = self.dao.get(1) ps_2 = self.dao.get(2) ps_3 = self.dao.get(3) self.assert_results(self.no_filter_query, [ps_1, ps_2], _make_pagination_token(['Builder', 'Bob', None, 2])) self.assert_results(self.one_filter_query, [ps_1]) self.assert_no_results(self.two_filter_query) self.assert_results(self.ascending_biobank_id_query, [ps_2, ps_3], _make_pagination_token([3, 'Caterpillar', 'Chad', None, 3])) self.assert_results(self.descending_biobank_id_query, [ps_1, ps_3], _make_pagination_token([3, 'Caterpillar', 'Chad', None, 3])) self.assert_results(_with_token(self.no_filter_query, _make_pagination_token(['Builder', 'Bob', None, 2])), [ps_3]) self.assert_results(_with_token(self.ascending_biobank_id_query, _make_pagination_token([3, 'Caterpillar', 'Chad', None, 3])), [ps_1]) self.assert_results(_with_token(self.descending_biobank_id_query, _make_pagination_token([3, 'Caterpillar', 'Chad', None, 3])), [ps_2]) def testQuery_fourFullSummaries_paginate(self): participant_1 = Participant(participantId=1, biobankId=4) self._insert(participant_1, 'Bob', 'Jones') participant_2 = Participant(participantId=2, biobankId=1) self._insert(participant_2, 'Bob', 'Jones') participant_3 = Participant(participantId=3, biobankId=3) self._insert(participant_3, 'Bob', 'Jones') participant_4 = Participant(participantId=4, biobankId=2) self._insert(participant_4, 'Bob', 'Jones') ps_1 = self.dao.get(1) ps_2 = self.dao.get(2) ps_3 = self.dao.get(3) ps_4 = self.dao.get(4) ps_1.lastName = 'Jones' ps_1.firstName = 'Bob' ps_1.dateOfBirth = datetime.date(1978, 10, 9) ps_1.hpoId = PITT_HPO_ID self.dao.update(ps_1) ps_2.lastName = 'Aardvark' ps_2.firstName = 'Bob' ps_2.dateOfBirth = datetime.date(1978, 10, 10) ps_2.enrollmentStatus = EnrollmentStatus.MEMBER self.dao.update(ps_2) ps_3.lastName = 'Jones' ps_3.firstName = 'Bob' ps_3.dateOfBirth = datetime.date(1978, 10, 10) ps_3.hpoId = PITT_HPO_ID ps_3.enrollmentStatus = EnrollmentStatus.MEMBER self.dao.update(ps_3) ps_4.lastName = 'Jones' ps_4.enrollmentStatus = EnrollmentStatus.FULL_PARTICIPANT self.dao.update(ps_4) self.assert_results(self.no_filter_query, [ps_2, ps_4], _make_pagination_token(['Jones', 'Bob', None, 4])) self.assert_results(self.one_filter_query, [ps_1]) self.assert_results(self.two_filter_query, [ps_1]) self.assert_results(self.ascending_biobank_id_query, [ps_2, ps_4], _make_pagination_token([2, 'Jones', 'Bob', None, 4])) self.assert_results(self.descending_biobank_id_query, [ps_1, ps_3], _make_pagination_token([3, 'Jones', 'Bob', datetime.date(1978, 10, 10), 3])) self.assert_results(self.hpo_id_order_query, [ps_2, ps_4], _make_pagination_token([0, 'Jones', 'Bob', None, 4])) self.assert_results(self.enrollment_status_order_query, [ps_1, ps_2], _make_pagination_token(['MEMBER', 'Aardvark', 'Bob', datetime.date(1978, 10, 10), 2])) self.assert_results(_with_token(self.no_filter_query, _make_pagination_token(['Jones', 'Bob', None, 4])), [ps_1, ps_3]) self.assert_results(_with_token(self.ascending_biobank_id_query, _make_pagination_token([2, 'Jones', 'Bob', None, 4])), [ps_3, ps_1]) self.assert_results(_with_token(self.descending_biobank_id_query, _make_pagination_token([3, 'Jones', 'Bob', datetime.date(1978, 10, 10), 3])), [ps_4, ps_2]) self.assert_results(_with_token(self.hpo_id_order_query, _make_pagination_token([0, 'Jones', 'Bob', None, 4])), [ps_1, ps_3]) self.assert_results(_with_token(self.enrollment_status_order_query, _make_pagination_token(['MEMBER', 'Aardvark', 'Bob', datetime.date(1978, 10, 10), 2])), [ps_3, ps_4]) def test_update_from_samples(self): # baseline_tests = ['BASELINE1', 'BASELINE2'] baseline_tests = ["1PST8", "2PST8"] config.override_setting(config.BASELINE_SAMPLE_TEST_CODES, baseline_tests) self.dao.update_from_biobank_stored_samples() # safe noop p_baseline_samples = self._insert(Participant(participantId=1, biobankId=11)) p_mixed_samples = self._insert(Participant(participantId=2, biobankId=22)) p_no_samples = self._insert(Participant(participantId=3, biobankId=33)) p_unconfirmed = self._insert(Participant(participantId=4, biobankId=44)) self.assertEquals(self.dao.get(p_baseline_samples.participantId).numBaselineSamplesArrived, 0) def get_p_baseline_last_modified(): return self.dao.get(p_baseline_samples.participantId).lastModified p_baseline_last_modified1 = get_p_baseline_last_modified() sample_dao = BiobankStoredSampleDao() def add_sample(participant, test_code, sample_id): TIME = datetime.datetime(2018, 3, 2) sample_dao.insert(BiobankStoredSample( biobankStoredSampleId=sample_id, biobankId=participant.biobankId, biobankOrderIdentifier='KIT', test=test_code, confirmed=TIME)) add_sample(p_baseline_samples, baseline_tests[0], '11111') add_sample(p_baseline_samples, baseline_tests[1], '22223') add_sample(p_mixed_samples, baseline_tests[0], '11112') add_sample(p_mixed_samples, 'NOT1', '44441') # add unconfirmed sample sample_dao.insert(BiobankStoredSample(biobankStoredSampleId=55555, biobankId=p_unconfirmed.biobankId, biobankOrderIdentifier='KIT', test=baseline_tests[1], confirmed=None)) # sleep 1 sec to make lastModified different time.sleep(1) self.dao.update_from_biobank_stored_samples() p_baseline_last_modified2 = get_p_baseline_last_modified() self.assertNotEquals(p_baseline_last_modified2, p_baseline_last_modified1) self.assertEquals(self.dao.get(p_baseline_samples.participantId).numBaselineSamplesArrived, 2) self.assertEquals(self.dao.get(p_mixed_samples.participantId).numBaselineSamplesArrived, 1) self.assertEquals(self.dao.get(p_no_samples.participantId).numBaselineSamplesArrived, 0) self.assertEquals(self.dao.get(p_unconfirmed.participantId).numBaselineSamplesArrived, 0) M_baseline_samples = self._insert(Participant(participantId=9, biobankId=99)) add_sample(M_baseline_samples, baseline_tests[0], '999') M_first_update = self.dao.get(M_baseline_samples.participantId) # sleep 1 sec to make lastModified different time.sleep(1) self.dao.update_from_biobank_stored_samples() add_sample(M_baseline_samples, baseline_tests[1], '9999') M_second_update = self.dao.get(M_baseline_samples.participantId) # sleep 1 sec to make lastModified different time.sleep(1) self.dao.update_from_biobank_stored_samples() self.assertNotEqual(M_first_update.lastModified, M_second_update.lastModified) self.assertEquals(get_p_baseline_last_modified(), p_baseline_last_modified2) def test_update_from_samples_changed_tests(self): baseline_tests = ["1PST8", "2PST8"] config.override_setting(config.BASELINE_SAMPLE_TEST_CODES, baseline_tests) self.dao.update_from_biobank_stored_samples() # safe noop participant = self._insert(Participant(participantId=1, biobankId=11)) self.assertEquals(self.dao.get(participant.participantId).numBaselineSamplesArrived, 0) sample_dao = BiobankStoredSampleDao() def add_sample(test_code, sample_id): TIME = datetime.datetime(2018, 3, 2) sample_dao.insert(BiobankStoredSample( biobankStoredSampleId=sample_id, biobankId=participant.biobankId, biobankOrderIdentifier='KIT', test=test_code, confirmed=TIME)) add_sample(baseline_tests[0], '11111') add_sample(baseline_tests[1], '22223') self.dao.update_from_biobank_stored_samples() summary = self.dao.get(participant.participantId) init_last_modified = summary.lastModified self.assertEquals(summary.numBaselineSamplesArrived, 2) # sleep 1 sec to make lastModified different time.sleep(1) # Simulate removal of one of the baseline tests from config.json. baseline_tests.pop() config.override_setting(config.BASELINE_SAMPLE_TEST_CODES, baseline_tests) self.dao.update_from_biobank_stored_samples() summary = self.dao.get(participant.participantId) self.assertEquals(summary.numBaselineSamplesArrived, 1) self.assertNotEqual(init_last_modified, summary.lastModified) def test_only_update_dna_sample(self): dna_tests = ["1ED10", "1SAL2"] config.override_setting(config.DNA_SAMPLE_TEST_CODES, dna_tests) self.dao.update_from_biobank_stored_samples() # safe noop p_dna_samples = self._insert(Participant(participantId=1, biobankId=11)) self.assertEquals(self.dao.get(p_dna_samples.participantId).samplesToIsolateDNA, None) self.assertEquals( self.dao.get(p_dna_samples.participantId).enrollmentStatusCoreStoredSampleTime, None) self.assertEquals( self.dao.get(p_dna_samples.participantId).enrollmentStatusCoreOrderedSampleTime, None) sample_dao = BiobankStoredSampleDao() def add_sample(participant, test_code, sample_id, confirmed_time): sample_dao.insert(BiobankStoredSample( biobankStoredSampleId=sample_id, biobankId=participant.biobankId, biobankOrderIdentifier='KIT', test=test_code, confirmed=confirmed_time)) confirmed_time_0 = datetime.datetime(2018, 3, 1) add_sample(p_dna_samples, dna_tests[0], '11111', confirmed_time_0) self.dao.update_from_biobank_stored_samples() self.assertEquals(self.dao.get(p_dna_samples.participantId).samplesToIsolateDNA, SampleStatus.RECEIVED) # only update dna sample will not update enrollmentStatusCoreStoredSampleTime self.assertEquals( self.dao.get(p_dna_samples.participantId).enrollmentStatusCoreStoredSampleTime, None) self.assertEquals( self.dao.get(p_dna_samples.participantId).enrollmentStatusCoreOrderedSampleTime, None) def test_calculate_enrollment_status(self): self.assertEquals(EnrollmentStatus.FULL_PARTICIPANT, self.dao.calculate_enrollment_status(True, NUM_BASELINE_PPI_MODULES, PhysicalMeasurementsStatus.COMPLETED, SampleStatus.RECEIVED)) self.assertEquals(EnrollmentStatus.MEMBER, self.dao.calculate_enrollment_status(True, NUM_BASELINE_PPI_MODULES - 1, PhysicalMeasurementsStatus.COMPLETED, SampleStatus.RECEIVED)) self.assertEquals(EnrollmentStatus.MEMBER, self.dao.calculate_enrollment_status(True, NUM_BASELINE_PPI_MODULES, PhysicalMeasurementsStatus.UNSET, SampleStatus.RECEIVED)) self.assertEquals(EnrollmentStatus.MEMBER, self.dao.calculate_enrollment_status(True, NUM_BASELINE_PPI_MODULES, PhysicalMeasurementsStatus.COMPLETED, SampleStatus.UNSET)) self.assertEquals(EnrollmentStatus.INTERESTED, self.dao.calculate_enrollment_status(False, NUM_BASELINE_PPI_MODULES, PhysicalMeasurementsStatus.COMPLETED, SampleStatus.RECEIVED)) def testUpdateEnrollmentStatus(self): ehr_consent_time = datetime.datetime(2018, 3, 1) summary = ParticipantSummary( participantId=1, biobankId=2, consentForStudyEnrollment=QuestionnaireStatus.SUBMITTED, consentForElectronicHealthRecords=QuestionnaireStatus.SUBMITTED, consentForElectronicHealthRecordsTime=ehr_consent_time, enrollmentStatus=EnrollmentStatus.INTERESTED) self.dao.update_enrollment_status(summary) self.assertEquals(EnrollmentStatus.MEMBER, summary.enrollmentStatus) self.assertEquals(ehr_consent_time, summary.enrollmentStatusMemberTime) def testUpdateEnrollmentStatusLastModified(self): """DA-631: enrollment_status update should update last_modified.""" participant = self._insert(Participant(participantId=6, biobankId=66)) # collect current modified and enrollment status summary = self.dao.get(participant.participantId) test_dt = datetime.datetime(2018, 11, 1) def reset_summary(): # change summary so enrollment status will be changed from INTERESTED to MEMBER. summary.enrollmentStatus = EnrollmentStatus.INTERESTED summary.lastModified = test_dt summary.consentForStudyEnrollment = QuestionnaireStatus.SUBMITTED summary.consentForElectronicHealthRecords = QuestionnaireStatus.SUBMITTED summary.physicalMeasurementsStatus = PhysicalMeasurementsStatus.COMPLETED summary.samplesToIsolateDNA = SampleStatus.RECEIVED self.dao.update(summary) ## Test Step 1: Validate update_from_biobank_stored_samples() changes lastModified. reset_summary() # Update and reload summary record self.dao.update_from_biobank_stored_samples(participant_id=participant.participantId) summary = self.dao.get(participant.participantId) # Test that status has changed and lastModified is also different self.assertEquals(EnrollmentStatus.MEMBER, summary.enrollmentStatus) self.assertNotEqual(test_dt, summary.lastModified) ## Test Step 2: Validate that update_enrollment_status() changes the lastModified property. reset_summary() summary = self.dao.get(participant.participantId) self.assertEqual(test_dt, summary.lastModified) # update_enrollment_status() does not touch the db, it only modifies object properties. self.dao.update_enrollment_status(summary) self.assertEquals(EnrollmentStatus.MEMBER, summary.enrollmentStatus) self.assertNotEqual(test_dt, summary.lastModified) def testNumberDistinctVisitsCounts(self): self.participant = self._insert(Participant(participantId=7, biobankId=77)) # insert biobank order order = self.order_dao.insert(self._make_biobank_order()) summary = self.dao.get(self.participant.participantId) self.assertEquals(summary.numberDistinctVisits, 1) cancel_request = cancel_biobank_order() # cancel biobank order self.order_dao.update_with_patch(order.biobankOrderId, cancel_request, order.version) summary = self.dao.get(self.participant.participantId) # distinct count should be 0 self.assertEquals(summary.numberDistinctVisits, 0) self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId, TIME_1.isoformat())) # insert physical measurement measurement = self.measurement_dao.insert(self._make_physical_measurements()) summary = self.dao.get(self.participant.participantId) # count should be 1 self.assertEquals(summary.numberDistinctVisits, 1) # cancel the measurement cancel_measurement = get_restore_or_cancel_info() with self.measurement_dao.session() as session: self.measurement_dao.update_with_patch(measurement.physicalMeasurementsId, session, cancel_measurement) summary = self.dao.get(self.participant.participantId) # count should be 0 self.assertEquals(summary.numberDistinctVisits, 0) with clock.FakeClock(TIME_1): self.order_dao.insert(self._make_biobank_order(biobankOrderId='2', identifiers=[ BiobankOrderIdentifier(system='b', value='d')], samples=[BiobankOrderedSample( biobankOrderId='2', test=BIOBANK_TESTS[0], description='description', processingRequired=True)])) with clock.FakeClock(TIME_2): self.measurement_dao.insert(self._make_physical_measurements( physicalMeasurementsId=2)) summary = self.dao.get(self.participant.participantId) # A PM on another day should add a new distinct count. self.assertEquals(summary.numberDistinctVisits, 2) with clock.FakeClock(TIME_3): self.order_dao.insert(self._make_biobank_order(biobankOrderId='3', identifiers=[ BiobankOrderIdentifier(system='s', value='s')], samples=[BiobankOrderedSample( biobankOrderId ='3', finalized=TIME_3, test=BIOBANK_TESTS[1], description='another description', processingRequired=False)])) # a physical measurement on same day as biobank order does not add distinct visit. self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=6)) # another biobank order on the same day should also not add a distinct visit self.order_dao.insert(self._make_biobank_order(biobankOrderId='7', identifiers=[ BiobankOrderIdentifier(system='x', value='x')], samples=[BiobankOrderedSample( biobankOrderId ='7', finalized=TIME_3, test=BIOBANK_TESTS[1], description='another description', processingRequired=False)])) summary = self.dao.get(self.participant.participantId) # 1 from each of TIME_1 TIME_2 TIME_3 self.assertEquals(summary.numberDistinctVisits, 3) def test_qa_scenarios_for_pmb_visits(self): """ PDR at https://docs.google.com/document/d/1sL54f-I91RvhjIprrdbwD8TlR9Jq91MX2ELf1EtJdxc/edit#heading=h.bqo8kt3igsrw<Paste> """ self.participant = self._insert(Participant(participantId=6, biobankId=66)) # test scenario 1 with clock.FakeClock(TIME_4): self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId, TIME_4.isoformat())) self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=666, participantId=self.participant.participantId, finalized=TIME_4)) summary = self.dao.get(self.participant.participantId) self.assertEquals(summary.numberDistinctVisits, 1) with clock.FakeClock(TIME_5): self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId, TIME_5.isoformat())) self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=669, finalized=TIME_5)) summary = self.dao.get(self.participant.participantId) self.assertEquals(summary.numberDistinctVisits, 2) # test scenario 2 with clock.FakeClock(TIME_6): self.participant = self._insert(Participant(participantId=9, biobankId=13)) self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId, TIME_6.isoformat())) self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=8, finalized=TIME_6)) self.order_dao.insert(self._make_biobank_order(biobankOrderId='2', identifiers=[ BiobankOrderIdentifier(system='b', value='d')], samples=[BiobankOrderedSample( biobankOrderId='2', finalized=TIME_7, test=BIOBANK_TESTS[0], description='description', processingRequired=True)])) summary = self.dao.get(self.participant.participantId) # distinct count should be 2 self.assertEquals(summary.numberDistinctVisits, 2) # test scenario 3 with clock.FakeClock(TIME_6): self.participant = self._insert(Participant(participantId=66, biobankId=42)) self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId, TIME_6.isoformat())) self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=12, createdSiteId=2, finalized=TIME_6)) self.order_dao.insert(self._make_biobank_order(biobankOrderId='18', finalizedSiteId=1, identifiers=[ BiobankOrderIdentifier(system='x', value='y')], samples=[BiobankOrderedSample( biobankOrderId='18', finalized=TIME_6, test=BIOBANK_TESTS[0], description='description', processingRequired=True)])) summary = self.dao.get(self.participant.participantId) # distinct count should be 1 self.assertEquals(summary.numberDistinctVisits, 1) # test scenario 4 with clock.FakeClock(TIME_8): self.participant = self._insert(Participant(participantId=6613, biobankId=142)) self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId, TIME_8.isoformat())) self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=129, finalized=TIME_8)) order = self.order_dao.insert(self._make_biobank_order(biobankOrderId='999', identifiers=[ BiobankOrderIdentifier(system='s', value='s')], samples=[BiobankOrderedSample( biobankOrderId='999', finalized=TIME_8, test=BIOBANK_TESTS[1], description='description', processingRequired=True)])) summary = self.dao.get(self.participant.participantId) # distinct count should be 1 self.assertEquals(summary.numberDistinctVisits, 1) # change finalized time, recalculating count with self.order_dao.session() as session: existing_order = copy.deepcopy(order) order.samples[0].finalized = TIME_9 self.order_dao._do_update(session, order, existing_order) summary = self.dao.get(self.participant.participantId) self.assertEquals(summary.numberDistinctVisits, 1) # change test, should not change count. with self.order_dao.session() as session: existing_order = copy.deepcopy(order) order.samples[0].test = BIOBANK_TESTS[0] self.order_dao._do_update(session, order, existing_order) summary = self.dao.get(self.participant.participantId) self.assertEquals(summary.numberDistinctVisits, 1) # test scenario 5 with clock.FakeClock(TIME_12): self.participant = self._insert(Participant(participantId=3000, biobankId=2019)) self.order_dao.insert(self._make_biobank_order(biobankOrderId='700', identifiers=[ BiobankOrderIdentifier(system='n', value='s')], samples=[BiobankOrderedSample( biobankOrderId='700', finalized=TIME_10, test=BIOBANK_TESTS[1], description='description', processingRequired=True)])) summary = self.dao.get(self.participant.participantId) # distinct count should be 1 self.assertEquals(summary.numberDistinctVisits, 1) other_order = self.order_dao.insert(self._make_biobank_order(biobankOrderId='701', identifiers=[ BiobankOrderIdentifier(system='n', value='t')], samples=[BiobankOrderedSample( biobankOrderId='701', finalized=TIME_11, test=BIOBANK_TESTS[1], description='description', processingRequired=True)])) summary = self.dao.get(self.participant.participantId) # distinct count should be 2 self.assertEquals(summary.numberDistinctVisits, 2) order = self.order_dao.insert(self._make_biobank_order(biobankOrderId='702', identifiers=[ BiobankOrderIdentifier(system='n', value='u')], samples=[BiobankOrderedSample( biobankOrderId='702', finalized=TIME_12, test=BIOBANK_TESTS[1], description='description', processingRequired=True)])) summary = self.dao.get(self.participant.participantId) # distinct count should be 3 self.assertEquals(summary.numberDistinctVisits, 3) self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId, TIME_12.isoformat())) self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=120, finalized=TIME_12)) summary = self.dao.get(self.participant.participantId) # distinct count should be 3 self.assertEquals(summary.numberDistinctVisits, 3) cancel_request = cancel_biobank_order() # cancel biobank order with PM on same day self.order_dao.update_with_patch(order.biobankOrderId, cancel_request, order.version) summary = self.dao.get(self.participant.participantId) # distinct count should be 3 (the PM on same day still counts) self.assertEquals(summary.numberDistinctVisits, 3) self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId, TIME_1.isoformat())) self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=150, finalized=TIME_1)) summary = self.dao.get(self.participant.participantId) # distinct count should be 4 self.assertEquals(summary.numberDistinctVisits, 4) # cancel order with pm on different day self.order_dao.update_with_patch(other_order.biobankOrderId, cancel_request, order.version) summary = self.dao.get(self.participant.participantId) # distinct count should be 3 self.assertEquals(summary.numberDistinctVisits, 3) def test_pm_restore_cancel_biobank_restore_cancel(self): self.participant = self._insert(Participant(participantId=9, biobankId=13)) self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId, TIME_4.isoformat())) measurement = self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=669, finalized=TIME_4)) summary = self.dao.get(self.participant.participantId) self.assertEquals(summary.numberDistinctVisits, 1) with clock.FakeClock(TIME_5): order = self.order_dao.insert(self._make_biobank_order(biobankOrderId='2', identifiers=[ BiobankOrderIdentifier(system='b', value='d')], samples=[BiobankOrderedSample( biobankOrderId='2', finalized=TIME_5, test=BIOBANK_TESTS[0], description='description', processingRequired=True)])) with clock.FakeClock(TIME_7): summary = self.dao.get(self.participant.participantId) # distinct count should be 2 self.assertEquals(summary.numberDistinctVisits, 2) # cancel the measurement cancel_measurement = get_restore_or_cancel_info() with self.measurement_dao.session() as session: self.measurement_dao.update_with_patch(measurement.physicalMeasurementsId, session, cancel_measurement) summary = self.dao.get(self.participant.participantId) self.assertEquals(summary.numberDistinctVisits, 1) with clock.FakeClock(TIME_7): restore_measurement = get_restore_or_cancel_info(status='restored') with self.measurement_dao.session() as session: self.measurement_dao.update_with_patch(measurement.physicalMeasurementsId, session, restore_measurement) summary = self.dao.get(self.participant.participantId) self.assertEquals(summary.numberDistinctVisits, 2) cancel_request = cancel_biobank_order() order = self.order_dao.update_with_patch(order.biobankOrderId, cancel_request, order.version) summary = self.dao.get(self.participant.participantId) self.assertEquals(summary.numberDistinctVisits, 1) restore_order = get_restore_or_cancel_info(status='restored') restore_order['amendedReason'] = 'some reason' self.order_dao.update_with_patch(order.biobankOrderId, restore_order, order.version) summary = self.dao.get(self.participant.participantId) self.assertEquals(summary.numberDistinctVisits, 2) def test_amending_biobank_order_distinct_visit_count(self): self.participant = self._insert(Participant(participantId=9, biobankId=13)) with clock.FakeClock(TIME_5): order = self.order_dao.insert(self._make_biobank_order(biobankOrderId='2', identifiers=[ BiobankOrderIdentifier(system='b', value='d')], samples=[BiobankOrderedSample( biobankOrderId='2', finalized=TIME_5, test=BIOBANK_TESTS[0], description='description', processingRequired=True)])) summary = self.dao.get(self.participant.participantId) self.assertEquals(summary.numberDistinctVisits, 1) with clock.FakeClock(TIME_7): amend_order = self._get_amended_info(order) with self.order_dao.session() as session: self.order_dao._do_update(session, amend_order, order) # Shouldn't change on a simple amendment (unless finalized time on samples change) summary = self.dao.get(self.participant.participantId) self.assertEquals(summary.numberDistinctVisits, 1) with clock.FakeClock(TIME_7_5): cancel_request = cancel_biobank_order() order = self.order_dao.update_with_patch(order.biobankOrderId, cancel_request, order.version) # A cancelled order (even after amending) should reduce count (unless some other valid order on same day) summary = self.dao.get(self.participant.participantId) self.assertEquals(summary.numberDistinctVisits, 0) @staticmethod def _get_amended_info(order): amendment = dict(amendedReason='I had to change something', amendedInfo={ "author": { "system": "https://www.pmi-ops.org/healthpro-username", "value": "*****@*****.**" }, "site": { "system": "https://www.pmi-ops.org/site-id", "value": "hpo-site-monroeville" } }) order.amendedReason = amendment['amendedReason'] order.amendedInfo = amendment['amendedInfo'] return order def _make_biobank_order(self, **kwargs): """Makes a new BiobankOrder (same values every time) with valid/complete defaults. Kwargs pass through to BiobankOrder constructor, overriding defaults. """ for k, default_value in ( ('biobankOrderId', '1'), ('created', clock.CLOCK.now()), ('participantId', self.participant.participantId), ('sourceSiteId', 1), ('sourceUsername', '*****@*****.**'), ('collectedSiteId', 1), ('collectedUsername', '*****@*****.**'), ('processedSiteId', 1), ('processedUsername', '*****@*****.**'), ('finalizedSiteId', 2), ('finalizedUsername', '*****@*****.**'), ('identifiers', [BiobankOrderIdentifier(system='a', value='c')]), ('samples', [BiobankOrderedSample( biobankOrderId='1', test=BIOBANK_TESTS[0], description='description', finalized=TIME_1, processingRequired=True)])): if k not in kwargs: kwargs[k] = default_value return BiobankOrder(**kwargs) def _make_physical_measurements(self, **kwargs): """Makes a new PhysicalMeasurements (same values every time) with valid/complete defaults. Kwargs pass through to PM constructor, overriding defaults. """ for k, default_value in ( ('physicalMeasurementsId', 1), ('participantId', self.participant.participantId), ('resource', self.measurement_json), ('createdSiteId', 1), ('finalized', TIME_3), ('finalizedSiteId', 2)): if k not in kwargs: kwargs[k] = default_value return PhysicalMeasurements(**kwargs)
class BiobankOrderDaoTest(SqlTestBase): _A_TEST = BIOBANK_TESTS[0] def setUp(self): super(BiobankOrderDaoTest, self).setUp() self.participant = Participant(participantId=123, biobankId=555) ParticipantDao().insert(self.participant) self.dao = BiobankOrderDao() def _make_biobank_order(self, **kwargs): """Makes a new BiobankOrder (same values every time) with valid/complete defaults. Kwargs pass through to BiobankOrder constructor, overriding defaults. """ for k, default_value in (('biobankOrderId', '1'), ('created', clock.CLOCK.now()), ('participantId', self.participant.participantId), ('sourceSiteId', 1), ('sourceUsername', '*****@*****.**'), ('collectedSiteId', 1), ('collectedUsername', '*****@*****.**'), ('processedSiteId', 1), ('processedUsername', '*****@*****.**'), ('finalizedSiteId', 1), ('finalizedUsername', '*****@*****.**'), ('identifiers', [ BiobankOrderIdentifier(system='a', value='c') ]), ('samples', [ BiobankOrderedSample( biobankOrderId='1', test=self._A_TEST, description='description', processingRequired=True) ])): if k not in kwargs: kwargs[k] = default_value return BiobankOrder(**kwargs) def test_bad_participant(self): with self.assertRaises(BadRequest): self.dao.insert(self._make_biobank_order(participantId=999)) def test_from_json(self): ParticipantSummaryDao().insert( self.participant_summary(self.participant)) order_json = load_biobank_order_json(self.participant.participantId) order = BiobankOrderDao().from_client_json( order_json, self.participant.participantId) self.assertEquals(1, order.sourceSiteId) self.assertEquals('*****@*****.**', order.sourceUsername) self.assertEquals(1, order.collectedSiteId) self.assertEquals('*****@*****.**', order.collectedUsername) self.assertEquals(1, order.processedSiteId) self.assertEquals('*****@*****.**', order.processedUsername) self.assertEquals(1, order.finalizedSiteId) self.assertEquals('*****@*****.**', order.finalizedUsername) def test_to_json(self): order = self._make_biobank_order() order_json = BiobankOrderDao().to_client_json(order) expected_order_json = load_biobank_order_json( self.participant.participantId) for key in ('createdInfo', 'collectedInfo', 'processedInfo', 'finalizedInfo'): self.assertEquals(expected_order_json[key], order_json.get(key)) def test_duplicate_insert_ok(self): ParticipantSummaryDao().insert( self.participant_summary(self.participant)) order_1 = self.dao.insert(self._make_biobank_order()) order_2 = self.dao.insert(self._make_biobank_order()) self.assertEquals(order_1.asdict(), order_2.asdict()) def test_same_id_different_identifier_not_ok(self): ParticipantSummaryDao().insert( self.participant_summary(self.participant)) self.dao.insert( self._make_biobank_order( identifiers=[BiobankOrderIdentifier(system='a', value='b')])) with self.assertRaises(Conflict): self.dao.insert( self._make_biobank_order(identifiers=[ BiobankOrderIdentifier(system='a', value='c') ])) def test_reject_used_identifier(self): ParticipantSummaryDao().insert( self.participant_summary(self.participant)) self.dao.insert( self._make_biobank_order( biobankOrderId='1', identifiers=[BiobankOrderIdentifier(system='a', value='b')])) with self.assertRaises(BadRequest): self.dao.insert( self._make_biobank_order(biobankOrderId='2', identifiers=[ BiobankOrderIdentifier(system='a', value='b') ])) def test_order_for_withdrawn_participant_fails(self): self.participant.withdrawalStatus = WithdrawalStatus.NO_USE ParticipantDao().update(self.participant) ParticipantSummaryDao().insert( self.participant_summary(self.participant)) with self.assertRaises(Forbidden): self.dao.insert( self._make_biobank_order( participantId=self.participant.participantId)) def test_get_for_withdrawn_participant_fails(self): ParticipantSummaryDao().insert( self.participant_summary(self.participant)) self.dao.insert( self._make_biobank_order( biobankOrderId='1', participantId=self.participant.participantId)) self.participant.version += 1 self.participant.withdrawalStatus = WithdrawalStatus.NO_USE ParticipantDao().update(self.participant) with self.assertRaises(Forbidden): self.dao.get(1) def test_store_invalid_test(self): with self.assertRaises(BadRequest): self.dao.insert( self._make_biobank_order(samples=[ BiobankOrderedSample(test='InvalidTestName', processingRequired=True, description=u'tested it') ]))