示例#1
0
  def test_metrics_redaction(self):
    self._create_data()

    with FakeClock(TIME):
      PublicMetricsExport.export('123')

      # Withdraw particpant.
      pdao = ParticipantDao()
      p1 = pdao.get(1)
      p1.withdrawalStatus = WithdrawalStatus.NO_USE
      pdao.update(p1)

      PublicMetricsExport.export('123')
      self.assert_total_count_per_key(2) # now, 2 qualified participants
示例#2
0
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'
            })
示例#3
0
class ParticipantDaoTest(SqlTestBase):
    def setUp(self):
        super(ParticipantDaoTest, self).setUp()
        self.dao = ParticipantDao()
        self.participant_summary_dao = ParticipantSummaryDao()
        self.participant_history_dao = ParticipantHistoryDao()

    def test_get_before_insert(self):
        self.assertIsNone(self.dao.get(1))
        self.assertIsNone(self.participant_summary_dao.get(1))
        self.assertIsNone(self.participant_history_dao.get([1, 1]))

    def test_insert(self):
        p = Participant()
        time = datetime.datetime(2016, 1, 1)
        with random_ids([1, 2]):
            with FakeClock(time):
                self.dao.insert(p)
        expected_participant = self._participant_with_defaults(
            participantId=1,
            version=1,
            biobankId=2,
            lastModified=time,
            signUpTime=time)
        self.assertEquals(expected_participant.asdict(), p.asdict())

        p2 = self.dao.get(1)
        self.assertEquals(p.asdict(), p2.asdict())

        # Creating a participant also creates a ParticipantHistory row, but not a ParticipantSummary row
        ps = self.participant_summary_dao.get(1)
        self.assertIsNone(ps)
        ph = self.participant_history_dao.get([1, 1])
        expected_ph = self._participant_history_with_defaults(
            participantId=1, biobankId=2, lastModified=time, signUpTime=time)
        self.assertEquals(expected_ph.asdict(), ph.asdict())

    def test_insert_with_external_id(self):
        p = Participant(externalId=3)
        time = datetime.datetime(2016, 1, 1)
        with random_ids([1, 2]):
            with FakeClock(time):
                self.dao.insert(p)
        expected_participant = self._participant_with_defaults(
            participantId=1,
            externalId=3,
            version=1,
            biobankId=2,
            lastModified=time,
            signUpTime=time)
        self.assertEquals(expected_participant.asdict(), p.asdict())

        p2 = self.dao.get(1)
        self.assertEquals(p.asdict(), p2.asdict())

        # Creating a participant also creates a ParticipantHistory row, but not a ParticipantSummary row
        ps = self.participant_summary_dao.get(1)
        self.assertIsNone(ps)
        ph = self.participant_history_dao.get([1, 1])
        expected_ph = self._participant_history_with_defaults(
            participantId=1,
            externalId=3,
            biobankId=2,
            lastModified=time,
            signUpTime=time)
        self.assertEquals(expected_ph.asdict(), ph.asdict())

    def test_insert_duplicate_participant_id_retry(self):
        p = Participant()
        with random_ids([1, 2]):
            self.dao.insert(p)
        p2 = Participant()
        time = datetime.datetime(2016, 1, 1)
        with random_ids([1, 3, 2, 3]):
            with FakeClock(time):
                p2 = self.dao.insert(p2)
        expected_participant = self._participant_with_defaults(
            participantId=2,
            version=1,
            biobankId=3,
            lastModified=time,
            signUpTime=time)
        self.assertEquals(expected_participant.asdict(), p2.asdict())

    def test_insert_duplicate_participant_id_give_up(self):
        p = Participant()
        with random_ids([1, 2]):
            self.dao.insert(p)
        rand_ints = []
        for i in range(0, MAX_INSERT_ATTEMPTS):
            rand_ints.append(1)
            rand_ints.append(i)
        p2 = Participant()
        with random_ids(rand_ints):
            with self.assertRaises(ServiceUnavailable):
                self.dao.insert(p2)

    def test_insert_duplicate_biobank_id_give_up(self):
        p = Participant()
        with random_ids([1, 2]):
            self.dao.insert(p)
        rand_ints = []
        for i in range(0, MAX_INSERT_ATTEMPTS):
            rand_ints.append(i + 2)
            rand_ints.append(2)
        p2 = Participant()
        with random_ids(rand_ints):
            with self.assertRaises(ServiceUnavailable):
                self.dao.insert(p2)

    def test_update_no_expected_version_no_ps(self):
        p = Participant()
        time = datetime.datetime(2016, 1, 1)
        with random_ids([1, 2]):
            with FakeClock(time):
                self.dao.insert(p)

        p.providerLink = make_primary_provider_link_for_name('PITT')
        time2 = datetime.datetime(2016, 1, 2)
        with FakeClock(time2):
            self.dao.update(p)
        # lastModified, hpoId, version is updated on p after being passed in
        p2 = self.dao.get(1)
        expected_participant = self._participant_with_defaults(
            participantId=1,
            version=2,
            biobankId=2,
            lastModified=time2,
            signUpTime=time,
            hpoId=PITT_HPO_ID,
            providerLink=p2.providerLink)
        self.assertEquals(expected_participant.asdict(), p2.asdict())
        self.assertEquals(p.asdict(), p2.asdict())

        ps = self.participant_summary_dao.get(1)
        self.assertIsNone(ps)

        expected_ph = self._participant_history_with_defaults(
            participantId=1, biobankId=2, lastModified=time, signUpTime=time)
        # Updating the participant adds a new ParticipantHistory row.
        ph = self.participant_history_dao.get([1, 1])
        self.assertEquals(expected_ph.asdict(), ph.asdict())
        ph2 = self.participant_history_dao.get([1, 2])
        expected_ph2 = self._participant_history_with_defaults(
            participantId=1,
            version=2,
            biobankId=2,
            lastModified=time2,
            signUpTime=time,
            hpoId=PITT_HPO_ID,
            providerLink=p2.providerLink)
        self.assertEquals(expected_ph2.asdict(), ph2.asdict())

    def test_update_no_expected_version_with_ps(self):
        p = Participant()
        time = datetime.datetime(2016, 1, 1)
        with random_ids([1, 2]):
            with FakeClock(time):
                self.dao.insert(p)
        p.providerLink = make_primary_provider_link_for_name('PITT')
        time2 = datetime.datetime(2016, 1, 2)
        with FakeClock(time2):
            self.dao.update(p)

        summary = self.participant_summary(p)
        self.participant_summary_dao.insert(summary)

        # lastModified, hpoId, version is updated on p after being passed in
        p2 = self.dao.get(1)
        expected_participant = self._participant_with_defaults(
            participantId=1,
            version=2,
            biobankId=2,
            lastModified=time2,
            signUpTime=time,
            hpoId=PITT_HPO_ID,
            providerLink=p2.providerLink)
        self.assertEquals(expected_participant.asdict(), p2.asdict())
        self.assertEquals(p.asdict(), p2.asdict())

        # Updating the participant provider link also updates the HPO ID on the participant summary.
        ps = self.participant_summary_dao.get(1)
        expected_ps = self._participant_summary_with_defaults(
            participantId=1,
            biobankId=2,
            signUpTime=time,
            hpoId=PITT_HPO_ID,
            lastModified=time2,
            firstName=summary.firstName,
            lastName=summary.lastName,
            email=summary.email)
        self.assertEquals(expected_ps.asdict(), ps.asdict())

        p2_last_modified = p2.lastModified
        p2.hpoId = 2
        self.dao.update(p2)
        p2_update = self.dao.get(1)
        self.assertNotEquals(p2_last_modified, p2_update.lastModified)
        self.assertEquals(p2_update.lastModified, p2.lastModified)

        expected_ph = self._participant_history_with_defaults(
            participantId=1, biobankId=2, lastModified=time, signUpTime=time)
        # And updating the participant adds a new ParticipantHistory row.
        ph = self.participant_history_dao.get([1, 1])
        self.assertEquals(expected_ph.asdict(), ph.asdict())
        ph2 = self.participant_history_dao.get([1, 2])
        expected_ph2 = self._participant_history_with_defaults(
            participantId=1,
            version=2,
            biobankId=2,
            lastModified=time2,
            signUpTime=time,
            hpoId=PITT_HPO_ID,
            providerLink=p2.providerLink)
        self.assertEquals(expected_ph2.asdict(), ph2.asdict())

    def test_update_right_expected_version(self):
        p = Participant()
        time = datetime.datetime(2016, 1, 1)
        with random_ids([1, 2]):
            with FakeClock(time):
                self.dao.insert(p)
        p.version = 1
        p.providerLink = make_primary_provider_link_for_name('PITT')
        time2 = datetime.datetime(2016, 1, 2)
        with FakeClock(time2):
            self.dao.update(p)

        p2 = self.dao.get(1)
        expected_participant = self._participant_with_defaults(
            participantId=1,
            version=2,
            biobankId=2,
            lastModified=time2,
            signUpTime=time,
            hpoId=PITT_HPO_ID,
            providerLink=p2.providerLink)
        self.assertEquals(expected_participant.asdict(), p2.asdict())

    def test_update_withdraw(self):
        p = Participant()
        time = datetime.datetime(2016, 1, 1)
        with random_ids([1, 2]):
            with FakeClock(time):
                self.dao.insert(p)
        p.version = 1
        p.withdrawalStatus = WithdrawalStatus.NO_USE
        time2 = datetime.datetime(2016, 1, 2)
        with FakeClock(time2):
            self.dao.update(p)

        p2 = self.dao.get(1)
        expected_participant = self._participant_with_defaults(
            participantId=1,
            version=2,
            biobankId=2,
            lastModified=time2,
            signUpTime=time,
            withdrawalStatus=WithdrawalStatus.NO_USE,
            withdrawalTime=time2)
        self.assertEquals(expected_participant.asdict(), p2.asdict())

        p.version = 2
        p.providerLink = make_primary_provider_link_for_name('PITT')
        p.withdrawalTime = None
        time3 = datetime.datetime(2016, 1, 3)
        with FakeClock(time3):
            self.dao.update(p)

        # Withdrawal time should get copied over.
        p2 = self.dao.get(1)
        expected_participant = self._participant_with_defaults(
            participantId=1,
            version=3,
            biobankId=2,
            lastModified=time3,
            signUpTime=time,
            withdrawalStatus=WithdrawalStatus.NO_USE,
            withdrawalTime=time2,
            hpoId=PITT_HPO_ID,
            providerLink=p2.providerLink)
        self.assertEquals(expected_participant.asdict(), p2.asdict())

    def test_update_suspend(self):
        p = Participant()
        time = datetime.datetime(2016, 1, 1)
        with random_ids([1, 2]):
            with FakeClock(time):
                self.dao.insert(p)
        p.version = 1
        p.suspensionStatus = SuspensionStatus.NO_CONTACT
        time2 = datetime.datetime(2016, 1, 2)
        with FakeClock(time2):
            self.dao.update(p)

        p2 = self.dao.get(1)
        expected_participant = self._participant_with_defaults(
            participantId=1,
            version=2,
            biobankId=2,
            lastModified=time2,
            signUpTime=time,
            suspensionStatus=SuspensionStatus.NO_CONTACT,
            suspensionTime=time2)
        self.assertEquals(expected_participant.asdict(), p2.asdict())

        p.version = 2
        p.providerLink = make_primary_provider_link_for_name('PITT')
        p.suspensionTime = None
        time3 = datetime.datetime(2016, 1, 3)
        with FakeClock(time3):
            self.dao.update(p)

        # Withdrawal time should get copied over.
        p2 = self.dao.get(1)
        expected_participant = self._participant_with_defaults(
            participantId=1,
            version=3,
            biobankId=2,
            lastModified=time3,
            signUpTime=time,
            suspensionStatus=SuspensionStatus.NO_CONTACT,
            suspensionTime=time2,
            hpoId=PITT_HPO_ID,
            providerLink=p2.providerLink)
        self.assertEquals(expected_participant.asdict(), p2.asdict())

    def test_update_wrong_expected_version(self):
        p = Participant()
        time = datetime.datetime(2016, 1, 1)
        with random_ids([1, 2]):
            with FakeClock(time):
                self.dao.insert(p)

        p.version = 2
        p.providerLink = make_primary_provider_link_for_name('PITT')
        time2 = datetime.datetime(2016, 1, 2)
        with FakeClock(time2):
            with self.assertRaises(PreconditionFailed):
                self.dao.update(p)

    def test_update_withdrawn_hpo_succeeds(self):
        p = Participant(withdrawalStatus=WithdrawalStatus.NO_USE)
        time = datetime.datetime(2016, 1, 1)
        with random_ids([1, 2]):
            with FakeClock(time):
                self.dao.insert(p)

        expected_participant = self._participant_with_defaults(
            participantId=1,
            version=1,
            biobankId=2,
            lastModified=time,
            signUpTime=time,
            withdrawalStatus=WithdrawalStatus.NO_USE)
        self.assertEquals(expected_participant.asdict(), p.asdict())

        p2 = self.dao.get(1)
        self.assertEquals(p.asdict(), p2.asdict())

        p.version = 1
        p.providerLink = make_primary_provider_link_for_name('PITT')
        self.dao.update(p)

    def test_update_withdrawn_status_fails(self):
        p = Participant(withdrawalStatus=WithdrawalStatus.NO_USE)
        time = datetime.datetime(2016, 1, 1)
        with random_ids([1, 2]):
            with FakeClock(time):
                self.dao.insert(p)

        expected_participant = self._participant_with_defaults(
            participantId=1,
            version=1,
            biobankId=2,
            lastModified=time,
            signUpTime=time,
            withdrawalStatus=WithdrawalStatus.NO_USE)
        self.assertEquals(expected_participant.asdict(), p.asdict())

        p2 = self.dao.get(1)
        self.assertEquals(p.asdict(), p2.asdict())

        p.version = 1
        p.withdrawalStatus = WithdrawalStatus.NOT_WITHDRAWN
        with self.assertRaises(Forbidden):
            self.dao.update(p)

    def test_update_not_exists(self):
        p = self._participant_with_defaults(participantId=1, biobankId=2)
        with self.assertRaises(NotFound):
            self.dao.update(p)

    def test_bad_hpo_insert(self):
        p = Participant(
            participantId=1,
            version=1,
            biobankId=2,
            providerLink=make_primary_provider_link_for_name('FOO'))
        with self.assertRaises(BadRequest):
            self.dao.insert(p)

    def test_bad_hpo_update(self):
        p = Participant(participantId=1, biobankId=2)
        time = datetime.datetime(2016, 1, 1)
        with FakeClock(time):
            self.dao.insert(p)

        p.providerLink = make_primary_provider_link_for_name('FOO')
        with self.assertRaises(BadRequest):
            self.dao.update(p)

    def test_pairs_unset(self):
        participant_id = 22
        self.dao.insert(Participant(participantId=participant_id, biobankId=2))
        refetched = self.dao.get(participant_id)
        self.assertEquals(refetched.hpoId, UNSET_HPO_ID)  # sanity check
        self.participant_summary_dao.insert(
            self.participant_summary(refetched))

        with self.dao.session() as session:
            self.dao.add_missing_hpo_from_site(session, participant_id,
                                               self._test_db.site_id)

        paired = self.dao.get(participant_id)
        self.assertEquals(paired.hpoId, self._test_db.hpo_id)
        self.assertEquals(
            paired.providerLink,
            make_primary_provider_link_for_id(self._test_db.hpo_id))
        self.assertEquals(
            self.participant_summary_dao.get(participant_id).hpoId,
            self._test_db.hpo_id)
        self.assertEquals(paired.organizationId, self._test_db.organization_id)
        self.assertEquals(paired.siteId, self._test_db.site_id)

    def test_overwrite_existing_pairing(self):
        participant_id = 99
        created = self.dao.insert(
            Participant(participantId=participant_id,
                        biobankId=2,
                        hpoId=self._test_db.hpo_id,
                        providerLink=make_primary_provider_link_for_id(
                            self._test_db.hpo_id)))
        self.participant_summary_dao.insert(self.participant_summary(created))
        self.assertEquals(created.hpoId, self._test_db.hpo_id)  # sanity check

        other_hpo = HPODao().insert(
            HPO(hpoId=PITT_HPO_ID + 1, name='DIFFERENT_HPO'))
        other_site = SiteDao().insert(
            Site(hpoId=other_hpo.hpoId,
                 siteName='Arbitrary Site',
                 googleGroup='*****@*****.**'))

        with self.dao.session() as session:
            self.dao.add_missing_hpo_from_site(session, participant_id,
                                               other_site.siteId)

        # Original Participant + summary is affected.
        refetched = self.dao.get(participant_id)

        self.assertEquals(refetched.hpoId, other_hpo.hpoId)
        self.assertEquals(refetched.providerLink,
                          make_primary_provider_link_for_id(other_hpo.hpoId))
        self.assertEquals(
            self.participant_summary_dao.get(participant_id).hpoId,
            other_hpo.hpoId)

    def test_pairing_at_different_levels(self):
        p = Participant()
        time = datetime.datetime(2016, 1, 1)
        with random_ids([1, 2]):
            with FakeClock(time):
                self.dao.insert(p)

        p.version = 1
        p.siteId = 1
        time2 = datetime.datetime(2016, 1, 2)
        with FakeClock(time2):
            self.dao.update(p)

        p2 = self.dao.get(1)
        ep = self._participant_with_defaults(participantId=1,
                                             version=2,
                                             biobankId=2,
                                             lastModified=time2,
                                             signUpTime=time,
                                             hpoId=PITT_HPO_ID,
                                             siteId=1,
                                             organizationId=PITT_ORG_ID,
                                             providerLink=p2.providerLink)
        self.assertEquals(ep.siteId, p2.siteId)
        # ensure that p2 get paired with expected awardee and organization from update().
        self.assertEquals(ep.hpoId, p2.hpoId)
        self.assertEquals(ep.organizationId, p2.organizationId)
示例#4
0
  def _create_data(self):
    HPODao().insert(HPO(hpoId=PITT_HPO_ID + 1, name='AZ_TUCSON_2'))
    HPODao().insert(HPO(hpoId=PITT_HPO_ID + 4, name='TEST'))
    SqlTestBase.setup_codes(
        ANSWER_FIELD_TO_QUESTION_CODE.values() + [EHR_CONSENT_QUESTION_CODE],
        code_type=CodeType.QUESTION)
    SqlTestBase.setup_codes(
        FIELD_TO_QUESTIONNAIRE_MODULE_CODE.values(), code_type=CodeType.MODULE)

    # Import codes for white and female, but not male or black.
    SqlTestBase.setup_codes([
      RACE_WHITE_CODE, CONSENT_PERMISSION_YES_CODE, RACE_NONE_OF_THESE_CODE,
      PMI_PREFER_NOT_TO_ANSWER_CODE, CONSENT_PERMISSION_NO_CODE, 'female', 'PIIState_VA',
      PMI_SKIP_CODE
    ], code_type=CodeType.ANSWER)
    participant_dao = ParticipantDao()

    questionnaire_id = self.create_questionnaire('questionnaire3.json')
    questionnaire_id_2 = self.create_questionnaire('questionnaire4.json')
    questionnaire_id_3 = self.create_questionnaire('all_consents_questionnaire.json')

    pl_tucson = make_primary_provider_link_for_name('AZ_TUCSON')
    pl_test = make_primary_provider_link_for_name('TEST')
    pl_pitt = make_primary_provider_link_for_name('PITT')

    with FakeClock(TIME):
      participant = Participant(participantId=1, biobankId=2, providerLink=pl_tucson)
      participant_dao.insert(participant)
      self.send_consent('P1', email='*****@*****.**')

      # Participant 2 starts out unpaired; later gets paired automatically when their physical
      # measurements come in.
      participant2 = Participant(participantId=2, biobankId=3)
      participant_dao.insert(participant2)
      self.send_consent('P2', email='*****@*****.**')

      # Test HPO affiliation; this test participant is ignored.
      participant3 = Participant(participantId=3, biobankId=4, providerLink=pl_test)
      participant_dao.insert(participant3)
      self.send_consent('P3', email='*****@*****.**')

      # example.com e-mail; this test participant is ignored, too.
      participant4 = Participant(participantId=4, biobankId=5, providerLink=pl_pitt)
      participant_dao.insert(participant4)
      self.send_consent('P4', email='*****@*****.**')

      participant5 = Participant(participantId=5, biobankId=6, providerLink=pl_tucson)
      participant_dao.insert(participant5)
      self.send_consent('P5', email='*****@*****.**')

    with FakeClock(TIME_2):
      # FIXME: The test passes, but the following "update" doesn't actually make much sense.  The
      # providerlink is not changed but the HPO ID actually is (at this point in time
      # `participant.hpoId` evaluates to 4, which is the value given in `unit_test_util.AZ_HPO_ID`).
      # The original intent of the test is not clear.
      # This update to participant has no effect, as the HPO ID didn't change.
      participant = self._participant_with_defaults(
        participantId=1, version=1, biobankId=2,
        hpoId=3, # <<<< Had to add hpoId here, default is UNSET_HPO_ID
        providerLink=pl_tucson
      )
      participant_dao.update(participant)

      self.submit_questionnaire_response('P1', questionnaire_id,
                                         race_code=RACE_WHITE_CODE,
                                         gender_code='male',
                                         state=PMI_SKIP_CODE,
                                         date_of_birth=datetime.date(1980, 1, 2))

      self.submit_questionnaire_response('P2', questionnaire_id,
                                         race_code=RACE_NONE_OF_THESE_CODE,
                                         gender_code=None,
                                         state=None,
                                         date_of_birth=None)

      self.submit_questionnaire_response('P5', questionnaire_id,
                                         race_code=PMI_SKIP_CODE,
                                         gender_code=PMI_SKIP_CODE,
                                         state=None,
                                         date_of_birth=None)

    with FakeClock(TIME_3):
      # Re-pair the original participant
      participant.version = 2
      participant.providerLink = pl_pitt
      participant_dao.update(participant)
      self.send_post('Participant/P2/PhysicalMeasurements', load_measurement_json(2))
      self.send_post('Participant/P2/BiobankOrder', load_biobank_order_json(2))

      self.submit_questionnaire_response('P1', questionnaire_id,
                                         race_code='black',
                                         gender_code='female',
                                         state=None,
                                         date_of_birth=datetime.date(1980, 1, 3))

      self.submit_questionnaire_response('P2', questionnaire_id,
                                         race_code=None,
                                         gender_code=PMI_PREFER_NOT_TO_ANSWER_CODE,
                                         state=None,
                                         date_of_birth=None)

      self.submit_questionnaire_response('P2', questionnaire_id_2,
                                         race_code=None,
                                         gender_code=None,
                                         state='PIIState_VA',
                                         date_of_birth=None)

      self.submit_consent_questionnaire_response('P1', questionnaire_id_3,
                                                  CONSENT_PERMISSION_NO_CODE)

      self.submit_consent_questionnaire_response('P2', questionnaire_id_3,
                                                  CONSENT_PERMISSION_YES_CODE)

      sample_dao = BiobankStoredSampleDao()
      sample_dao.insert(
          BiobankStoredSample(
              biobankStoredSampleId='abc',
              biobankId=2,
              biobankOrderIdentifier='KIT',
              test='test',
              confirmed=TIME_2))
      sample_dao.insert(
          BiobankStoredSample(
              biobankStoredSampleId='def',
              biobankId=3,
              biobankOrderIdentifier='KIT',
              test='1SAL',
              confirmed=TIME_2))
      sample_dao.insert(
          BiobankStoredSample(
              biobankStoredSampleId='xyz',
              biobankId=4,
              biobankOrderIdentifier='KIT',
              test='1SAL',
              confirmed=TIME_2))
示例#5
0
  def _create_data(self):
    HPODao().insert(HPO(hpoId=PITT_HPO_ID + 1, name='AZ_TUCSON'))
    HPODao().insert(HPO(hpoId=PITT_HPO_ID + 2, name='TEST'))
    SqlTestBase.setup_codes(
        ANSWER_FIELD_TO_QUESTION_CODE.values() + [EHR_CONSENT_QUESTION_CODE],
        code_type=CodeType.QUESTION)
    SqlTestBase.setup_codes(
        FIELD_TO_QUESTIONNAIRE_MODULE_CODE.values(), code_type=CodeType.MODULE)
    # Import codes for white and female, but not male or black.
    SqlTestBase.setup_codes(
        [
            RACE_WHITE_CODE, CONSENT_PERMISSION_YES_CODE,
            CONSENT_PERMISSION_NO_CODE, 'female', 'PIIState_VA'
        ],
        code_type=CodeType.ANSWER)
    participant_dao = ParticipantDao()

    questionnaire_id = self.create_questionnaire('questionnaire3.json')
    questionnaire_id_2 = self.create_questionnaire('questionnaire4.json')
    questionnaire_id_3 = self.create_questionnaire(
        'all_consents_questionnaire.json')
    with FakeClock(TIME):
      participant = Participant(
          participantId=1,
          biobankId=2,
          providerLink=make_primary_provider_link_for_name('AZ_TUCSON'))
      participant_dao.insert(participant)
      self.send_consent('P1', email='*****@*****.**')

    with FakeClock(TIME):
      # Participant 2 starts out unpaired; later gets paired automatically when their physical
      # measurements come in.
      participant2 = Participant(
          participantId=2,
          biobankId=3)
      participant_dao.insert(participant2)
      self.send_consent('P2', email='*****@*****.**')

    with FakeClock(TIME):
      # Test HPO affiliation; this test participant is ignored.
      participant3 = Participant(participantId=3, biobankId=4,
                                 providerLink=make_primary_provider_link_for_name('TEST'))
      participant_dao.insert(participant3)
      self.send_consent('P3', email='*****@*****.**')

      # example.com e-mail; this test participant is ignored, too.
      participant4 = Participant(participantId=4, biobankId=5,
                                 providerLink=make_primary_provider_link_for_name('PITT'))
      participant_dao.insert(participant4)
      self.send_consent('P4', email='*****@*****.**')

    with FakeClock(TIME_2):
      # This update to participant has no effect, as the HPO ID didn't change.
      participant = self._participant_with_defaults(
          participantId=1, version=1, biobankId=2,
          providerLink=make_primary_provider_link_for_name('AZ_TUCSON'))
      participant_dao.update(participant)
      self.submit_questionnaire_response('P1', questionnaire_id,
                                         RACE_WHITE_CODE, 'male', None,
                                         datetime.date(1980, 1, 2))
      self.submit_questionnaire_response('P2', questionnaire_id, None, None,
                                         None, None)

    with FakeClock(TIME_3):
      participant = self._participant_with_defaults(
          participantId=1,
          version=2,
          biobankId=2,
          providerLink=make_primary_provider_link_for_name('PITT'))
      participant_dao.update(participant)
      self.send_post('Participant/P2/PhysicalMeasurements',
                     load_measurement_json(2))
      self.send_post('Participant/P2/BiobankOrder', load_biobank_order_json(2))
      self.submit_questionnaire_response('P1', questionnaire_id, 'black',
                                         'female', None,
                                         datetime.date(1980, 1, 3))
      self.submit_questionnaire_response('P2', questionnaire_id_2, None, None,
                                         'PIIState_VA', None)
      self._submit_consent_questionnaire_response('P1', questionnaire_id_3,
                                                  CONSENT_PERMISSION_NO_CODE)
      self._submit_consent_questionnaire_response('P2', questionnaire_id_3,
                                                  CONSENT_PERMISSION_YES_CODE)
      sample_dao = BiobankStoredSampleDao()
      sample_dao.insert(
          BiobankStoredSample(
              biobankStoredSampleId='abc',
              biobankId=2,
              test='test',
              confirmed=TIME_2))
      sample_dao.insert(
          BiobankStoredSample(
              biobankStoredSampleId='def',
              biobankId=3,
              test='1SAL',
              confirmed=TIME_2))
class ParticipantCountsOverTimeApiTest(FlaskTestBase):

  def setUp(self):
    super(ParticipantCountsOverTimeApiTest, self).setUp(use_mysql=True)
    self.dao = ParticipantDao()
    self.ps_dao = ParticipantSummaryDao()
    self.ps = ParticipantSummary()
    self.calendar_dao = CalendarDao()
    self.hpo_dao = HPODao()

    # Needed by ParticipantCountsOverTimeApi
    self.hpo_dao.insert(HPO(hpoId=TEST_HPO_ID, name=TEST_HPO_NAME, displayName='Test',
                       organizationType=OrganizationType.UNSET))

    self.time1 = datetime.datetime(2017, 12, 31)
    self.time2 = datetime.datetime(2018, 1, 1)
    self.time3 = datetime.datetime(2018, 1, 2)
    self.time4 = datetime.datetime(2018, 1, 3)

    # Insert 2 weeks of dates
    curr_date = datetime.date(2017, 12, 22)
    for _ in xrange(0, 14):
      calendar_day = Calendar(day=curr_date )
      CalendarDao().insert(calendar_day)
      curr_date = curr_date + datetime.timedelta(days=1)

  def _insert(self, participant, first_name=None, last_name=None, hpo_name=None,
              unconsented=False, time_int=None, time_mem=None, time_fp=None):
    """
    Create a participant in a transient test database.

    :param participant: Participant object
    :param first_name: First name
    :param last_name: Last name
    :param hpo_name: HPO name (one of PITT or AZ_TUCSON)
    :param time_int: Time that participant fulfilled INTERESTED criteria
    :param time_mem: Time that participant fulfilled MEMBER criteria
    :param time_fp: Time that participant fulfilled FULL_PARTICIPANT criteria
    :return: Participant object
    """

    if unconsented is True:
      enrollment_status = None
    elif time_mem is None:
      enrollment_status = EnrollmentStatus.INTERESTED
    elif time_fp is None:
      enrollment_status = EnrollmentStatus.MEMBER
    else:
      enrollment_status = EnrollmentStatus.FULL_PARTICIPANT

    with FakeClock(time_int):
      self.dao.insert(participant)

    participant.providerLink = make_primary_provider_link_for_name(hpo_name)
    with FakeClock(time_mem):
      self.dao.update(participant)

    if enrollment_status is None:
      return None

    summary = self.participant_summary(participant)

    if first_name:
      summary.firstName = first_name
    if last_name:
      summary.lastName = last_name

    summary.dateOfBirth = datetime.date(1978, 10, 10)

    summary.enrollmentStatus = enrollment_status

    summary.hpoId = self.hpo_dao.get_by_name(hpo_name).hpoId

    if time_mem is not None:
      with FakeClock(time_mem):
        summary.consentForElectronicHealthRecordsTime = time_mem

    if time_fp is not None:
      with FakeClock(time_fp):
        summary.consentForElectronicHealthRecordsTime = time_fp
        summary.questionnaireOnTheBasicsTime = time_fp
        summary.questionnaireOnLifestyleTime = time_fp
        summary.questionnaireOnOverallHealthTime = time_fp
        summary.physicalMeasurementsFinalizedTime = time_fp
        summary.sampleOrderStatus1ED04Time = time_fp
        summary.sampleOrderStatus1SALTime = time_fp

    self.ps_dao.insert(summary)

    return summary

  def test_get_counts_with_default_parameters(self):
    # The most basic test in this class

    p1 = Participant(participantId=1, biobankId=4)
    self._insert(p1, 'Alice', 'Aardvark', 'PITT', time_int=self.time1)

    # TODO: remove bucketSize from these parameters in all tests
    qs = """
      bucketSize=1
      &stratification=ENROLLMENT_STATUS
      &startDate=2017-12-30
      &endDate=2018-01-04
      """

    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs)

    # You can debug API responses easily by uncommenting the lines below
    # print('response')
    # print(response)

    interested_count_day_1 = response[0]['metrics']['INTERESTED']
    interested_count_day_2 = response[1]['metrics']['INTERESTED']

    self.assertEquals(interested_count_day_1, 0)
    self.assertEquals(interested_count_day_2, 1)

  def test_get_counts_with_single_awardee_filter(self):
    # Does the awardee filter work?

    p1 = Participant(participantId=1, biobankId=4)
    self._insert(p1, 'Alice', 'Aardvark', 'PITT', time_int=self.time1)

    p1 = Participant(participantId=2, biobankId=5)
    self._insert(p1, 'Bob', 'Builder', 'AZ_TUCSON', time_int=self.time1)

    p1 = Participant(participantId=3, biobankId=6)
    self._insert(p1, 'Chad', 'Caterpillar', 'AZ_TUCSON', time_int=self.time1)

    # enrollmentStatus param left blank to test we can handle it
    qs = """
      bucketSize=1
      &stratification=ENROLLMENT_STATUS
      &startDate=2017-12-30
      &endDate=2018-01-04
      &awardee=PITT
      &enrollmentStatus=
      """

    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs)

    interested_count_day_1 = response[0]['metrics']['INTERESTED']
    interested_count_day_2 = response[1]['metrics']['INTERESTED']

    self.assertEquals(interested_count_day_1, 0)
    self.assertEquals(interested_count_day_2, 1)

    qs = """
      bucketSize=1
      &stratification=ENROLLMENT_STATUS
      &startDate=2017-12-30
      &endDate=2018-01-04
      &awardee=AZ_TUCSON
      """

    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs)

    interested_count_day_1 = response[0]['metrics']['INTERESTED']
    interested_count_day_2 = response[1]['metrics']['INTERESTED']

    self.assertEquals(interested_count_day_1, 0)
    self.assertEquals(interested_count_day_2, 2)

  def test_get_counts_with_single_awardee_filter(self):
    # Does the awardee filter work when passed a single awardee?

    p1 = Participant(participantId=1, biobankId=4)
    self._insert(p1, 'Alice', 'Aardvark', 'PITT', time_int=self.time1)

    p1 = Participant(participantId=2, biobankId=5)
    self._insert(p1, 'Bob', 'Builder', 'AZ_TUCSON', time_int=self.time1)

    p1 = Participant(participantId=3, biobankId=6)
    self._insert(p1, 'Chad', 'Caterpillar', 'AZ_TUCSON', time_int=self.time1)

    qs = """
        bucketSize=1
        &stratification=ENROLLMENT_STATUS
        &startDate=2017-12-30
        &endDate=2018-01-04
        &awardee=PITT
        """

    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs)

    interested_count_day_1 = response[0]['metrics']['INTERESTED']
    interested_count_day_2 = response[1]['metrics']['INTERESTED']

    self.assertEquals(interested_count_day_1, 0)
    self.assertEquals(interested_count_day_2, 1)

    qs = """
        bucketSize=1
        &stratification=ENROLLMENT_STATUS
        &startDate=2017-12-30
        &endDate=2018-01-04
        &awardee=AZ_TUCSON
        """

    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs)

    interested_count_day_1 = response[0]['metrics']['INTERESTED']
    interested_count_day_2 = response[1]['metrics']['INTERESTED']

    self.assertEquals(interested_count_day_1, 0)
    self.assertEquals(interested_count_day_2, 2)

  def test_get_counts_with_multiple_awardee_filters(self):
    # Does the awardee filter work when passed more than one awardee?

    p1 = Participant(participantId=1, biobankId=4)
    self._insert(p1, 'Alice', 'Aardvark', 'PITT', time_int=self.time1)

    p2 = Participant(participantId=2, biobankId=5)
    self._insert(p2, 'Bob', 'Builder', 'AZ_TUCSON', time_int=self.time1)

    p3 = Participant(participantId=3, biobankId=6)
    self._insert(p3, 'Chad', 'Caterpillar', 'AZ_TUCSON', time_int=self.time1)

    qs = """
        bucketSize=1
        &stratification=ENROLLMENT_STATUS
        &startDate=2017-12-30
        &endDate=2018-01-04
        &awardee=PITT,AZ_TUCSON
        &enrollmentStatus=
        """

    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs)

    interested_count_day_1 = response[0]['metrics']['INTERESTED']
    interested_count_day_2 = response[1]['metrics']['INTERESTED']

    self.assertEquals(interested_count_day_1, 0)
    self.assertEquals(interested_count_day_2, 3)

  def test_get_counts_with_enrollment_status_member_filter(self):

    p1 = Participant(participantId=1, biobankId=4)
    self._insert(p1, 'Alice', 'Aardvark', 'PITT', time_int=self.time1)

    p2 = Participant(participantId=2, biobankId=5)
    self._insert(p2, 'Bob', 'Builder', 'AZ_TUCSON', time_int=self.time1, time_mem=self.time2)

    p3 = Participant(participantId=3, biobankId=6)
    self._insert(p3, 'Chad', 'Caterpillar', 'AZ_TUCSON', time_int=self.time1, time_mem=self.time2)

    p4 = Participant(participantId=4, biobankId=7)
    self._insert(p4, 'Debra', 'Dinosaur', 'PITT', time_int=self.time1, time_mem=self.time3)

    # awardee param intentionally left blank to test we can handle it
    qs = """
      bucketSize=1
      &stratification=ENROLLMENT_STATUS
      &startDate=2017-12-30
      &endDate=2018-01-04
      &awardee=
      &enrollmentStatus=MEMBER
      """

    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs)

    member_count_day_1 = response[0]['metrics']['MEMBER']
    member_count_day_2 = response[1]['metrics']['MEMBER']
    member_count_day_3 = response[2]['metrics']['MEMBER']
    member_count_day_4 = response[3]['metrics']['MEMBER']
    interested_count_day_4 = response[1]['metrics']['INTERESTED']

    self.assertEquals(member_count_day_1, 0)
    self.assertEquals(member_count_day_2, 0)
    self.assertEquals(member_count_day_3, 2)
    self.assertEquals(member_count_day_4, 3)
    self.assertEquals(interested_count_day_4, 0)

    qs = """
      bucketSize=1
      &stratification=TOTAL
      &startDate=2017-12-30
      &endDate=2018-01-04
      &enrollmentStatus=MEMBER
      """

    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs)

    total_count_day_1 = response[0]['metrics']['TOTAL']
    total_count_day_2 = response[1]['metrics']['TOTAL']

    self.assertEquals(total_count_day_1, 0)
    self.assertEquals(total_count_day_2, 3)

  def test_get_counts_with_enrollment_status_full_participant_filter(self):

    # MEMBER @ time 1
    p1 = Participant(participantId=1, biobankId=4)
    self._insert(p1, 'Alice', 'Aardvark', 'PITT', time_int=self.time1,
                 time_mem=self.time1)

    # FULL PARTICIPANT @ time 2
    p2 = Participant(participantId=2, biobankId=5)
    self._insert(p2, 'Bob', 'Builder', 'AZ_TUCSON', time_int=self.time1,
                 time_mem=self.time1, time_fp=self.time2)

    # FULL PARTICIPANT @ time 2
    p3 = Participant(participantId=3, biobankId=6)
    self._insert(p3, 'Chad', 'Caterpillar', 'AZ_TUCSON', time_int=self.time1,
                 time_mem=self.time1, time_fp=self.time2)

    # FULL PARTICIPANT @ time 3
    p4 = Participant(participantId=4, biobankId=7)
    self._insert(p4, 'Debra', 'Dinosaur', 'PITT', time_int=self.time1,
                 time_mem=self.time1, time_fp=self.time3)

    qs = """
      bucketSize=1
      &stratification=ENROLLMENT_STATUS
      &startDate=2017-12-30
      &endDate=2018-01-04
      &enrollmentStatus=FULL_PARTICIPANT
      """

    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs)

    full_participant_count_day_1 = response[0]['metrics']['FULL_PARTICIPANT']
    full_participant_count_day_2 = response[1]['metrics']['FULL_PARTICIPANT']
    full_participant_count_day_3 = response[2]['metrics']['FULL_PARTICIPANT']
    full_participant_count_day_4 = response[3]['metrics']['FULL_PARTICIPANT']
    member_count_day_4 = response[4]['metrics']['MEMBER']

    self.assertEquals(full_participant_count_day_1, 0)
    self.assertEquals(full_participant_count_day_2, 0)
    self.assertEquals(full_participant_count_day_3, 2)
    self.assertEquals(full_participant_count_day_4, 3)
    self.assertEquals(member_count_day_4, 0)  # Excluded per enrollmentStatus parameter

  def test_get_counts_with_total_enrollment_status_full_participant_filter(self):
    # When filtering with TOTAL stratification, filtered participants are
    # returned by their sign up date, not the date they reached their highest
    # enrollment status.

    # MEMBER @ time 1
    p1 = Participant(participantId=1, biobankId=4)
    self._insert(p1, 'Alice', 'Aardvark', 'PITT', time_int=self.time1,
                 time_mem=self.time1)

    # FULL PARTICIPANT @ time 2
    p2 = Participant(participantId=2, biobankId=5)
    self._insert(p2, 'Bob', 'Builder', 'AZ_TUCSON', time_int=self.time1,
                 time_mem=self.time1, time_fp=self.time2)

    # FULL PARTICIPANT @ time 2
    p3 = Participant(participantId=3, biobankId=6)
    self._insert(p3, 'Chad', 'Caterpillar', 'AZ_TUCSON', time_int=self.time1,
                 time_mem=self.time1, time_fp=self.time2)

    # FULL PARTICIPANT @ time 3
    p4 = Participant(participantId=4, biobankId=7)
    self._insert(p4, 'Debra', 'Dinosaur', 'PITT', time_int=self.time1,
                 time_mem=self.time1, time_fp=self.time3)

    qs = """
      bucketSize=1
      &stratification=TOTAL
      &startDate=2017-12-30
      &endDate=2018-01-04
      &enrollmentStatus=FULL_PARTICIPANT
      """

    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs)

    total_count_day_1 = response[0]['metrics']['TOTAL']
    total_count_day_2 = response[1]['metrics']['TOTAL']
    total_count_day_3 = response[2]['metrics']['TOTAL']
    total_count_day_4 = response[3]['metrics']['TOTAL']

    self.assertEquals(total_count_day_1, 0)
    self.assertEquals(total_count_day_2, 3)
    self.assertEquals(total_count_day_3, 3)
    self.assertEquals(total_count_day_4, 3)

  def test_get_counts_with_single_various_filters(self):
    # Do the awardee and enrollment status filters work when passed single values?

    p1 = Participant(participantId=1, biobankId=4)
    self._insert(p1, 'Alice', 'Aardvark', 'PITT', time_int=self.time1)

    p2 = Participant(participantId=2, biobankId=5)
    self._insert(p2, 'Bob', 'Builder', 'AZ_TUCSON', time_int=self.time1)

    p3 = Participant(participantId=3, biobankId=6)
    self._insert(p3, 'Chad', 'Caterpillar', 'AZ_TUCSON', time_int=self.time1,
                 time_mem=self.time1)

    p4 = Participant(participantId=4, biobankId=7)
    self._insert(p4, 'Debra', 'Dinosaur', 'PITT', time_int=self.time1,
                 time_mem=self.time1)

    qs = """
      bucketSize=1
      &stratification=ENROLLMENT_STATUS
      &startDate=2017-12-30
      &endDate=2018-01-04
      &awardee=PITT
      &enrollmentStatus=MEMBER
      """

    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs)

    interested_count_day_1 = response[0]['metrics']['INTERESTED']
    interested_count_day_2 = response[1]['metrics']['INTERESTED']
    member_count_day_2 = response[1]['metrics']['MEMBER']

    self.assertEquals(interested_count_day_1, 0)

    # We requested data for only MEMBERs, so no INTERESTEDs should be returned
    self.assertEquals(interested_count_day_2, 0)

    # We requested data for only MEMBERs in PITT, so no MEMBERs in AZ_TUCSON should be returned
    self.assertEquals(member_count_day_2, 1)

  def test_get_counts_with_multiple_various_filters(self):
    # Do the awardee and enrollment status filters work when passed multiple values?

    p1 = Participant(participantId=1, biobankId=4)
    self._insert(p1, 'Alice', 'Aardvark', 'PITT', time_int=self.time1)

    p2 = Participant(participantId=2, biobankId=5)
    self._insert(p2, 'Bob', 'Builder', 'AZ_TUCSON', time_int=self.time1)

    p3 = Participant(participantId=3, biobankId=6)
    self._insert(p3, 'Chad', 'Caterpillar', 'AZ_TUCSON', time_int=self.time1)

    qs = """
        bucketSize=1
        &stratification=ENROLLMENT_STATUS
        &startDate=2017-12-30
        &endDate=2018-01-04
        &awardee=AZ_TUCSON,PITT
        &enrollmentStatus=INTERESTED,MEMBER,FULL_PARTICIPANT
        """

    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs)

    interested_count_day_1 = response[0]['metrics']['INTERESTED']
    interested_count_day_2 = response[1]['metrics']['INTERESTED']

    self.assertEquals(interested_count_day_1, 0)
    self.assertEquals(interested_count_day_2, 3)

  def test_get_counts_with_total_stratification_unfiltered(self):

    p1 = Participant(participantId=1, biobankId=4)
    self._insert(p1, 'Alice', 'Aardvark', 'PITT', time_int=self.time1)

    p2 = Participant(participantId=2, biobankId=5)
    self._insert(p2, 'Bob', 'Builder', 'AZ_TUCSON', time_int=self.time1)

    p3 = Participant(participantId=3, biobankId=6)
    self._insert(p3, 'Chad', 'Caterpillar', 'AZ_TUCSON', time_int=self.time1)

    qs = """
      bucketSize=1
      &stratification=TOTAL
      &startDate=2017-12-30
      &endDate=2018-01-04
      """

    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs)

    total_count_day_1 = response[0]['metrics']['TOTAL']
    total_count_day_2 = response[1]['metrics']['TOTAL']

    self.assertEquals(total_count_day_1, 0)
    self.assertEquals(total_count_day_2, 3)

  def test_get_counts_excluding_interested_participants(self):
    # When filtering only for MEMBER, no INTERESTED (neither consented nor unconsented) should be counted

    p1 = Participant(participantId=1, biobankId=4)
    self._insert(p1, 'Alice', 'Aardvark', 'UNSET', unconsented=True, time_int=self.time1)

    p2 = Participant(participantId=2, biobankId=5)
    self._insert(p2, 'Bob', 'Builder', 'AZ_TUCSON', time_int=self.time1)

    p3 = Participant(participantId=3, biobankId=6)
    self._insert(p3, 'Chad', 'Caterpillar', 'AZ_TUCSON', time_int=self.time1, time_mem=self.time1)

    qs = """
        bucketSize=1
        &stratification=ENROLLMENT_STATUS
        &startDate=2017-12-30
        &endDate=2018-01-04
        &enrollmentStatus=MEMBER
        """

    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs)

    interested_count_day_2 = response[1]['metrics']['INTERESTED']
    member_count_day_2 = response[1]['metrics']['MEMBER']

    self.assertEquals(interested_count_day_2, 0)
    self.assertEquals(member_count_day_2, 1)

  def test_get_counts_excluding_withdrawn_participants(self):
    # Withdrawn participants should not appear in counts

    p1 = Participant(participantId=1, biobankId=4)
    self._insert(p1, 'Alice', 'Aardvark', 'PITT', time_int=self.time1)

    p2 = Participant(participantId=2, biobankId=5)
    self._insert(p2, 'Bob', 'Builder', 'AZ_TUCSON', time_int=self.time1)

    p3 = Participant(participantId=3, biobankId=6)
    ps3 = self._insert(p3, 'Chad', 'Caterpillar', 'AZ_TUCSON', time_int=self.time1)
    ps3.withdrawalStatus = WithdrawalStatus.NO_USE  # Chad withdrew from the study
    self.ps_dao.update(ps3)

    qs = """
        bucketSize=1
        &stratification=TOTAL
        &startDate=2017-12-30
        &endDate=2018-01-04
        """

    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs)

    total_count_day_1 = response[0]['metrics']['TOTAL']
    total_count_day_2 = response[1]['metrics']['TOTAL']

    self.assertEquals(total_count_day_1, 0)
    self.assertEquals(total_count_day_2, 2)

  def test_get_counts_for_unconsented_individuals(self):
    # Those who have signed up but not consented should be INTERESTED

    p1 = Participant(participantId=1, biobankId=4)
    self._insert(p1, 'Alice', 'Aardvark', 'UNSET', unconsented=True, time_int=self.time1)

    p2 = Participant(participantId=2, biobankId=5)
    self._insert(p2, 'Bob', 'Builder', 'AZ_TUCSON', time_int=self.time1)

    p3 = Participant(participantId=3, biobankId=6)
    self._insert(p3, 'Chad', 'Caterpillar', 'AZ_TUCSON', time_int=self.time1)

    qs = """
          bucketSize=1
          &stratification=ENROLLMENT_STATUS
          &startDate=2017-12-30
          &endDate=2018-01-04
          """

    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs)

    total_count_day_1 = response[0]['metrics']['INTERESTED']
    total_count_day_2 = response[1]['metrics']['INTERESTED']

    self.assertEquals(total_count_day_1, 0)
    self.assertEquals(total_count_day_2, 3)

  def test_url_parameter_validation_for_date_range(self):
    # Ensure requests for very long date ranges are marked BAD REQUEST

    qs = """
        bucketSize=1
        &stratification=TOTAL
        &startDate=2017-12-30
        &endDate=2217-12-30
        """
    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs,
                             expected_status=httplib.BAD_REQUEST)
    self.assertEquals(response, None)

  def test_url_parameter_validation_for_stratifications(self):
    # Ensure requests invalid stratifications are marked BAD REQUEST

    qs = """
          bucketSize=1
          &stratification=FOOBAR
          &startDate=2017-12-30
          &endDate=2018-01-04
          """
    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs,
                             expected_status=httplib.BAD_REQUEST)
    self.assertEquals(response, None)

  def test_url_parameter_validation_for_awardee(self):
    # Ensure requests invalid awardee are marked BAD REQUEST

    qs = """
            bucketSize=1
            &stratification=ENROLLMENT_STATUS
            &startDate=2017-12-30
            &endDate=2018-01-04
            &awardee=FOOBAR
            """
    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs,
                             expected_status=httplib.BAD_REQUEST)
    self.assertEquals(response, None)

  def test_url_parameter_validation_for_enrollment_status(self):
    # Ensure requests invalid enrollment status are marked BAD REQUEST

    qs = """
            bucketSize=1
            &stratification=ENROLLMENT_STATUS
            &startDate=2017-12-30
            &endDate=2018-01-04
            &enrollmentStatus=FOOBAR
            """
    qs = ''.join(qs.split())  # Remove all whitespace

    response = self.send_get('ParticipantCountsOverTime', query_string=qs,
                             expected_status=httplib.BAD_REQUEST)
    self.assertEquals(response, None)
示例#7
0
  def _create_data(self):
    HPODao().insert(HPO(hpoId=AZ_HPO_ID + 1, name='AZ_TUCSON_2'))
    HPODao().insert(HPO(hpoId=PITT_HPO_ID + 4, name='TEST'))
    SqlTestBase.setup_codes(
        ANSWER_FIELD_TO_QUESTION_CODE.values() + [EHR_CONSENT_QUESTION_CODE],
        code_type=CodeType.QUESTION)
    SqlTestBase.setup_codes(
        FIELD_TO_QUESTIONNAIRE_MODULE_CODE.values(), code_type=CodeType.MODULE)
    # Import codes for white and female, but not male or black.
    SqlTestBase.setup_codes(
        [
            RACE_WHITE_CODE, CONSENT_PERMISSION_YES_CODE,
            RACE_NONE_OF_THESE_CODE, PMI_PREFER_NOT_TO_ANSWER_CODE,
            CONSENT_PERMISSION_NO_CODE, 'female', 'PIIState_VA'
        ],
        code_type=CodeType.ANSWER)
    participant_dao = ParticipantDao()

    questionnaire_id = self.create_questionnaire('questionnaire3.json')
    questionnaire_id_2 = self.create_questionnaire('questionnaire4.json')
    questionnaire_id_3 = self.create_questionnaire(
        'all_consents_questionnaire.json')

    with FakeClock(TIME):
      participant = self._participant_with_defaults(
          participantId=1,
          version=2,
          biobankId=2,
          providerLink=make_primary_provider_link_for_name('PITT'))
      participant_dao.insert(participant)
      self.send_consent('P1', email='*****@*****.**')

      # Participant 2 starts out unpaired; later gets paired automatically when their physical
      # measurements come in.
      participant2 = Participant(participantId=2, biobankId=3)
      participant_dao.insert(participant2)
      self.send_consent('P2', email='*****@*****.**')

      # Test HPO affiliation; this test participant is ignored.
      participant3 = Participant(
          participantId=3,
          biobankId=4,
          providerLink=make_primary_provider_link_for_name('TEST'))
      participant_dao.insert(participant3)
      self.send_consent('P3', email='*****@*****.**')

      # example.com e-mail; this test participant is ignored, too.
      participant4 = Participant(
          participantId=4,
          biobankId=5,
          providerLink=make_primary_provider_link_for_name('PITT'))
      participant_dao.insert(participant4)
      self.send_consent('P4', email='*****@*****.**')

      participant5 = Participant(
          participantId=5,
          biobankId=6,
          providerLink=make_primary_provider_link_for_name('PITT'))
      participant_dao.insert(participant5)
      self.send_consent('P5', email='*****@*****.**')

      # A withdrawn participant should be excluded from metrics.
      participant6 = Participant(
          participantId=6,
          biobankId=7,
          providerLink=make_primary_provider_link_for_name('PITT')
      )
      participant_dao.insert(participant6)
      self.send_consent('P6', email='*****@*****.**')
      participant6.withdrawalStatus=WithdrawalStatus.NO_USE
      participant_dao.update(participant6)

      self.send_post('Participant/P2/PhysicalMeasurements',
                     load_measurement_json(2))
      self.send_post('Participant/P2/BiobankOrder', load_biobank_order_json(2))
      self.submit_questionnaire_response('P1', questionnaire_id,
                                         RACE_WHITE_CODE, 'female', None,
                                         datetime.date(1980, 1, 2))
      self.submit_questionnaire_response(
          'P2', questionnaire_id, PMI_PREFER_NOT_TO_ANSWER_CODE, 'male', None,
          datetime.date(1920, 1, 3))
      self.submit_questionnaire_response('P2', questionnaire_id_2, None, None,
                                         'PIIState_VA', None)
      self.submit_questionnaire_response('P5', questionnaire_id, None, None,
                                         None, datetime.date(1970, 1, 2))
      self.submit_consent_questionnaire_response('P1', questionnaire_id_3,
                                                 CONSENT_PERMISSION_NO_CODE)
      self.submit_consent_questionnaire_response('P2', questionnaire_id_3,
                                                 CONSENT_PERMISSION_YES_CODE)
      sample_dao = BiobankStoredSampleDao()
      sample_dao.insert(
          BiobankStoredSample(
              biobankStoredSampleId='abc',
              biobankId=2,
              biobankOrderIdentifier='KIT',
              test='test',
              confirmed=TIME))
      sample_dao.insert(
          BiobankStoredSample(
              biobankStoredSampleId='def',
              biobankId=3,
              biobankOrderIdentifier='KIT',
              test='1SAL',
              confirmed=TIME))
      # Required to update the HPO linkage (and test filtering for P3).
      sample_dao.insert(
          BiobankStoredSample(
              biobankStoredSampleId='xyz',
              biobankId=4,
              biobankOrderIdentifier='KIT',
              test='1SAL',
              confirmed=TIME))
示例#8
0
class QuestionnaireResponseDaoTest(FlaskTestBase):
    def setUp(self):
        super(QuestionnaireResponseDaoTest, self).setUp()
        self.code_dao = CodeDao()
        self.participant_dao = ParticipantDao()
        self.questionnaire_dao = QuestionnaireDao()
        self.questionnaire_response_dao = QuestionnaireResponseDao()
        self.questionnaire_response_answer_dao = QuestionnaireResponseAnswerDao(
        )
        self.participant_summary_dao = ParticipantSummaryDao()
        self.CODE_1 = Code(codeId=1,
                           system=PPI_SYSTEM,
                           value=GENDER_IDENTITY_QUESTION_CODE,
                           display=u'c',
                           topic=u'd',
                           codeType=CodeType.QUESTION,
                           mapped=True)
        self.CODE_2 = Code(codeId=2,
                           system='a',
                           value='x',
                           display=u'y',
                           codeType=CodeType.QUESTION,
                           mapped=False)
        self.CODE_3 = Code(codeId=3,
                           system='a',
                           value='c',
                           codeType=CodeType.ANSWER,
                           mapped=True,
                           parentId=1)
        self.CODE_4 = Code(codeId=4,
                           system='a',
                           value='d',
                           codeType=CodeType.ANSWER,
                           mapped=True,
                           parentId=2)
        self.CODE_5 = Code(codeId=5,
                           system='a',
                           value='e',
                           codeType=CodeType.ANSWER,
                           mapped=False,
                           parentId=1)
        self.CODE_6 = Code(codeId=6,
                           system='a',
                           value='f',
                           codeType=CodeType.ANSWER,
                           mapped=True,
                           parentId=1)
        self.MODULE_CODE_7 = Code(codeId=7,
                                  system=PPI_SYSTEM,
                                  value=THE_BASICS_PPI_MODULE,
                                  codeType=CodeType.MODULE,
                                  mapped=True)
        self.CONCEPT_1 = QuestionnaireConcept(codeId=7)
        self.CODE_1_QUESTION_1 = QuestionnaireQuestion(linkId='a',
                                                       codeId=1,
                                                       repeats=False)
        self.CODE_2_QUESTION = QuestionnaireQuestion(linkId='d',
                                                     codeId=2,
                                                     repeats=True)
        # Same code as question 1
        self.CODE_1_QUESTION_2 = QuestionnaireQuestion(linkId='x',
                                                       codeId=1,
                                                       repeats=False)

        self.skip_code = Code(codeId=8,
                              system=PPI_SYSTEM,
                              value=PMI_SKIP_CODE,
                              mapped=True,
                              codeType=CodeType.ANSWER)

        config.override_setting(config.CONSENT_PDF_BUCKET, [_FAKE_BUCKET])

    def _setup_questionnaire(self):
        q = Questionnaire(resource=QUESTIONNAIRE_RESOURCE)
        q.concepts.append(self.CONCEPT_1)
        q.concepts.append(QuestionnaireConcept(codeId=self.consent_code_id))
        q.questions.append(self.CODE_1_QUESTION_1)
        q.questions.append(self.CODE_2_QUESTION)
        q.questions.append(self.FN_QUESTION)
        q.questions.append(self.LN_QUESTION)
        q.questions.append(self.EMAIL_QUESTION)
        q.questions.append(self.LOGIN_PHONE_NUMBER_QUESTION)
        return self.questionnaire_dao.insert(q)

    def insert_codes(self):
        self.code_dao.insert(self.CODE_1)
        self.code_dao.insert(self.CODE_2)
        self.code_dao.insert(self.CODE_3)
        self.code_dao.insert(self.CODE_4)
        self.code_dao.insert(self.CODE_5)
        self.code_dao.insert(self.CODE_6)
        self.code_dao.insert(self.MODULE_CODE_7)
        self.code_dao.insert(self.skip_code)
        self.consent_code_id = self.code_dao.insert(consent_code()).codeId
        self.first_name_code_id = self.code_dao.insert(
            first_name_code()).codeId
        self.last_name_code_id = self.code_dao.insert(last_name_code()).codeId
        self.email_code_id = self.code_dao.insert(email_code()).codeId
        self.login_phone_number_code_id = self.code_dao.insert(
            login_phone_number_code()).codeId
        self.FN_QUESTION = QuestionnaireQuestion(
            linkId='fn', codeId=self.first_name_code_id, repeats=False)
        self.LN_QUESTION = QuestionnaireQuestion(linkId='ln',
                                                 codeId=self.last_name_code_id,
                                                 repeats=False)
        self.EMAIL_QUESTION = QuestionnaireQuestion(linkId='email',
                                                    codeId=self.email_code_id,
                                                    repeats=False)
        self.LOGIN_PHONE_NUMBER_QUESTION = QuestionnaireQuestion(
            linkId='lpn',
            codeId=self.login_phone_number_code_id,
            repeats=False)
        self.first_name = self.fake.first_name()
        self.last_name = self.fake.last_name()
        self.email = self.fake.email()
        self.login_phone_number = self.fake.phone_number()
        self.FN_ANSWER = QuestionnaireResponseAnswer(
            questionnaireResponseAnswerId=3,
            questionnaireResponseId=1,
            questionId=3,
            valueString=self.first_name)
        self.LN_ANSWER = QuestionnaireResponseAnswer(
            questionnaireResponseAnswerId=4,
            questionnaireResponseId=1,
            questionId=4,
            valueString=self.last_name)
        self.EMAIL_ANSWER = QuestionnaireResponseAnswer(
            questionnaireResponseAnswerId=5,
            questionnaireResponseId=1,
            questionId=5,
            valueString=self.email)
        self.LOGIN_PHONE_NUMBER_ANSWER = QuestionnaireResponseAnswer(
            questionnaireResponseAnswerId=6,
            questionnaireResponseId=1,
            questionId=6,
            valueString=self.login_phone_number)

    def check_response(self, expected_qr):
        qr = self.questionnaire_response_dao.get_with_children(
            expected_qr.questionnaireResponseId)
        self.assertEquals(expected_qr.asdict(follow=ANSWERS),
                          qr.asdict(follow=ANSWERS))

    def _names_and_email_answers(self):
        return [self.FN_ANSWER, self.LN_ANSWER, self.EMAIL_ANSWER]

    def _names_and_login_phone_number_answers(self):
        return [self.FN_ANSWER, self.LN_ANSWER, self.LOGIN_PHONE_NUMBER_ANSWER]

    def test_get_before_insert(self):
        self.assertIsNone(self.questionnaire_response_dao.get(1))
        self.assertIsNone(self.questionnaire_response_dao.get_with_children(1))
        self.assertIsNone(self.questionnaire_response_answer_dao.get(1))

    def test_insert_questionnaire_not_found(self):
        p = Participant(participantId=1, biobankId=2)
        self.participant_dao.insert(p)
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        with self.assertRaises(BadRequest):
            self.questionnaire_response_dao.insert(qr)

    def test_insert_participant_not_found(self):
        self.insert_codes()
        q = Questionnaire(resource=QUESTIONNAIRE_RESOURCE)
        q.concepts.append(QuestionnaireConcept(codeId=self.consent_code_id))
        self.questionnaire_dao.insert(q)
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        qr.answers.extend(self._names_and_email_answers())
        # Answers are there but the participant is not.
        with self.assertRaises(BadRequest):
            self.questionnaire_response_dao.insert(qr)

    def test_insert_participant_not_found2(self):
        self.insert_codes()
        p = Participant(participantId=1,
                        biobankId=2,
                        withdrawalStatus=WithdrawalStatus.NOT_WITHDRAWN)
        self.participant_dao.insert(p)
        self._setup_questionnaire()
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=2,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        qr.answers.extend(self._names_and_email_answers())
        with self.assertRaises(BadRequest):
            self.questionnaire_response_dao.insert(qr)

    def test_insert_participant_withdrawn(self):
        self.insert_codes()
        p = Participant(participantId=1,
                        biobankId=2,
                        withdrawalStatus=WithdrawalStatus.NO_USE)
        self.participant_dao.insert(p)
        self._setup_questionnaire()
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        qr.answers.extend(self._names_and_email_answers())
        with self.assertRaises(Forbidden):
            self.questionnaire_response_dao.insert(qr)

    def test_insert_not_name_answers(self):
        self.insert_codes()
        p = Participant(participantId=1, biobankId=2)
        self.participant_dao.insert(p)
        self._setup_questionnaire()
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        qr.answers.append(
            QuestionnaireResponseAnswer(questionnaireResponseAnswerId=2,
                                        questionnaireResponseId=1,
                                        questionId=2,
                                        valueSystem='c',
                                        valueCodeId=4))
        # Both first and last name are required.
        with self.assertRaises(BadRequest):
            self.questionnaire_response_dao.insert(qr)

    def test_insert_first_name_only(self):
        self.insert_codes()
        p = Participant(participantId=1, biobankId=2)
        self.participant_dao.insert(p)
        self._setup_questionnaire()
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        qr.answers.append(self.FN_ANSWER)
        with self.assertRaises(BadRequest):
            self.questionnaire_response_dao.insert(qr)

    def test_insert_last_name_only(self):
        self.insert_codes()
        p = Participant(participantId=1, biobankId=2)
        self.participant_dao.insert(p)
        self._setup_questionnaire()
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        qr.answers.append(self.LN_ANSWER)
        # Both first and last name are required.
        with self.assertRaises(BadRequest):
            self.questionnaire_response_dao.insert(qr)

    def test_insert_names_only(self):
        self.insert_codes()
        p = Participant(participantId=1, biobankId=2)
        self.participant_dao.insert(p)
        self._setup_questionnaire()
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        qr.answers.append(self.FN_ANSWER)
        qr.answers.append(self.LN_ANSWER)
        # Email is required.
        with self.assertRaises(BadRequest):
            self.questionnaire_response_dao.insert(qr)

    def test_insert_email_only(self):
        self.insert_codes()
        p = Participant(participantId=1, biobankId=2)
        self.participant_dao.insert(p)
        self._setup_questionnaire()
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        qr.answers.append(self.EMAIL_ANSWER)
        # First and last name are required.
        with self.assertRaises(BadRequest):
            self.questionnaire_response_dao.insert(qr)

    def test_insert_login_phone_number_only(self):
        self.insert_codes()
        p = Participant(participantId=1, biobankId=2)
        self.participant_dao.insert(p)
        self._setup_questionnaire()
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        qr.answers.append(self.LOGIN_PHONE_NUMBER_ANSWER)
        # First and last name are required.
        with self.assertRaises(BadRequest):
            self.questionnaire_response_dao.insert(qr)

    def test_insert_both_email_and_login_phone_number_without_names(self):
        self.insert_codes()
        p = Participant(participantId=1, biobankId=2)
        self.participant_dao.insert(p)
        self._setup_questionnaire()
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        qr.answers.append(self.EMAIL_ANSWER)
        qr.answers.append(self.LOGIN_PHONE_NUMBER_ANSWER)
        # First and last name are required.
        with self.assertRaises(BadRequest):
            self.questionnaire_response_dao.insert(qr)

    def test_insert_both_names_and_login_phone_number(self):
        self.insert_codes()
        p = Participant(participantId=1, biobankId=2)
        self.participant_dao.insert(p)
        self._setup_questionnaire()
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        qr.answers.extend(self._names_and_login_phone_number_answers())
        time = datetime.datetime(2016, 1, 1)
        with FakeClock(time):
            qr.authored = time
            self.questionnaire_response_dao.insert(qr)

        expected_qr = QuestionnaireResponse(
            questionnaireResponseId=1,
            questionnaireId=1,
            questionnaireVersion=1,
            participantId=1,
            resource=with_id(QUESTIONNAIRE_RESPONSE_RESOURCE, 1),
            created=time,
            authored=time)
        expected_qr.answers.extend(
            self._names_and_login_phone_number_answers())
        qr2 = self.questionnaire_response_dao.get(1)
        self.assertEquals(expected_qr.asdict(), qr2.asdict())
        self.check_response(expected_qr)

    def test_insert_both_names_and_email(self):
        self.insert_codes()
        p = Participant(participantId=1, biobankId=2)
        self.participant_dao.insert(p)
        self._setup_questionnaire()
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        qr.answers.extend(self._names_and_email_answers())
        time = datetime.datetime(2016, 1, 1)
        with FakeClock(time):
            qr.authored = time
            self.questionnaire_response_dao.insert(qr)

        expected_qr = QuestionnaireResponse(
            questionnaireResponseId=1,
            questionnaireId=1,
            questionnaireVersion=1,
            participantId=1,
            resource=with_id(QUESTIONNAIRE_RESPONSE_RESOURCE, 1),
            created=time,
            authored=time)
        expected_qr.answers.extend(self._names_and_email_answers())
        qr2 = self.questionnaire_response_dao.get(1)
        self.assertEquals(expected_qr.asdict(), qr2.asdict())
        self.check_response(expected_qr)

    def test_insert_both_names_and_email_and_login_phone_number(self):
        self.insert_codes()
        p = Participant(participantId=1, biobankId=2)
        self.participant_dao.insert(p)
        self._setup_questionnaire()
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        qr.answers.append(self.FN_ANSWER)
        qr.answers.append(self.LN_ANSWER)
        qr.answers.append(self.EMAIL_ANSWER)
        qr.answers.append(self.LOGIN_PHONE_NUMBER_ANSWER)
        time = datetime.datetime(2016, 1, 1)
        with FakeClock(time):
            qr.authored = time
            self.questionnaire_response_dao.insert(qr)

        expected_qr = QuestionnaireResponse(
            questionnaireResponseId=1,
            questionnaireId=1,
            questionnaireVersion=1,
            participantId=1,
            resource=with_id(QUESTIONNAIRE_RESPONSE_RESOURCE, 1),
            created=time,
            authored=time)
        expected_qr.answers.append(self.FN_ANSWER)
        expected_qr.answers.append(self.LN_ANSWER)
        expected_qr.answers.append(self.EMAIL_ANSWER)
        expected_qr.answers.append(self.LOGIN_PHONE_NUMBER_ANSWER)
        qr2 = self.questionnaire_response_dao.get(1)
        self.assertEquals(expected_qr.asdict(), qr2.asdict())
        self.check_response(expected_qr)

    def test_insert_duplicate(self):
        self.insert_codes()
        p = Participant(participantId=1, biobankId=2)
        self.participant_dao.insert(p)
        self._setup_questionnaire()
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        qr.answers.extend(self._names_and_email_answers())
        self.questionnaire_response_dao.insert(qr)
        qr2 = QuestionnaireResponse(questionnaireResponseId=1,
                                    questionnaireId=1,
                                    questionnaireVersion=1,
                                    participantId=1,
                                    resource=QUESTIONNAIRE_RESPONSE_RESOURCE_2)
        qr2.answers.append(
            QuestionnaireResponseAnswer(questionnaireResponseAnswerId=2,
                                        questionnaireResponseId=1,
                                        questionId=2,
                                        valueSystem='c',
                                        valueCodeId=4))
        with self.assertRaises(IntegrityError):
            self.questionnaire_response_dao.insert(qr2)

    def test_insert_skip_codes(self):
        self.insert_codes()
        p = Participant(participantId=1, biobankId=2)
        with FakeClock(TIME):
            self.participant_dao.insert(p)
        self._setup_questionnaire()

        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)

        answer_1 = QuestionnaireResponseAnswer(
            questionnaireResponseAnswerId=1,
            questionnaireResponseId=1,
            questionId=1,
            valueSystem='a',
            valueCodeId=self.skip_code.codeId)

        answer_2 = QuestionnaireResponseAnswer(questionnaireResponseAnswerId=2,
                                               questionnaireResponseId=1,
                                               questionId=2,
                                               valueSystem='c',
                                               valueCodeId=4)

        qr.answers.extend([answer_1, answer_2])
        qr.answers.extend(self._names_and_email_answers())

        with FakeClock(TIME_2):
            self.questionnaire_response_dao.insert(qr)

        expected_qr = QuestionnaireResponse(
            questionnaireResponseId=1,
            questionnaireId=1,
            questionnaireVersion=1,
            participantId=1,
            resource=with_id(QUESTIONNAIRE_RESPONSE_RESOURCE, 1),
            created=TIME_2,
            authored=TIME_2)

        qr2 = self.questionnaire_response_dao.get(1)
        self.assertEquals(expected_qr.asdict(), qr2.asdict())

        expected_qr.answers.extend([answer_1, answer_2])
        expected_qr.answers.extend(self._names_and_email_answers())
        self.check_response(expected_qr)

        expected_ps = self._participant_summary_with_defaults(
            genderIdentityId=self.skip_code.codeId,
            participantId=1,
            biobankId=2,
            signUpTime=TIME,
            numCompletedBaselinePPIModules=1,
            numCompletedPPIModules=1,
            questionnaireOnTheBasics=QuestionnaireStatus.SUBMITTED,
            questionnaireOnTheBasicsTime=TIME_2,
            questionnaireOnTheBasicsAuthored=TIME_2,
            consentForStudyEnrollment=QuestionnaireStatus.SUBMITTED,
            consentForStudyEnrollmentTime=TIME_2,
            consentForStudyEnrollmentAuthored=TIME_2,
            firstName=self.first_name,
            lastName=self.last_name,
            email=self.email,
            lastModified=TIME_2,
        )
        self.assertEquals(expected_ps.asdict(),
                          self.participant_summary_dao.get(1).asdict())

    def test_from_client_json_raises_BadRequest_for_excessively_long_value_string(
            self):
        self.insert_codes()
        q_id = self.create_questionnaire('questionnaire1.json')
        p_id = self.create_participant()
        self.send_consent(p_id)

        # First check that the normal case actually writes out correctly
        string = 'a' * QuestionnaireResponseAnswer.VALUE_STRING_MAXLEN
        string_answers = [["nameOfChild", string]]
        resource = make_questionnaire_response_json(
            p_id, q_id, string_answers=string_answers)
        qr = self.questionnaire_response_dao.from_client_json(
            resource, participant_id=int(p_id[1:]))
        with self.questionnaire_response_answer_dao.session() as session:
            self.questionnaire_response_dao.insert(qr)
            all_strings_query = session.query(
                QuestionnaireResponseAnswer.valueString).all()
            all_strings = [obj.valueString for obj in all_strings_query]
            self.assertTrue(string in all_strings)

        # Now check that the incorrect case throws
        string = 'a' * (QuestionnaireResponseAnswer.VALUE_STRING_MAXLEN + 1)
        string_answers = [["nameOfChild", string]]
        resource = make_questionnaire_response_json(
            p_id, q_id, string_answers=string_answers)
        with self.assertRaises(BadRequest):
            qr = self.questionnaire_response_dao.from_client_json(
                resource, participant_id=int(p_id[1:]))

    def test_get_after_withdrawal_fails(self):
        self.insert_codes()
        p = Participant(participantId=1, biobankId=2)
        self.participant_dao.insert(p)
        self._setup_questionnaire()
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        qr.answers.extend(self._names_and_email_answers())
        self.questionnaire_response_dao.insert(qr)
        p.withdrawalStatus = WithdrawalStatus.NO_USE
        self.participant_dao.update(p)
        with self.assertRaises(Forbidden):
            self.questionnaire_response_dao.get(qr.questionnaireResponseId)

    def test_insert_with_answers(self):
        self.insert_codes()
        p = Participant(participantId=1, biobankId=2)
        with FakeClock(TIME):
            self.participant_dao.insert(p)
        self._setup_questionnaire()
        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        answer_1 = QuestionnaireResponseAnswer(
            questionnaireResponseAnswerId=1,
            questionnaireResponseId=1,
            questionId=1,
            valueSystem='a',
            valueCodeId=3,
            valueDecimal=123,
            valueString=self.fake.first_name(),
            valueDate=datetime.date.today())
        answer_2 = QuestionnaireResponseAnswer(questionnaireResponseAnswerId=2,
                                               questionnaireResponseId=1,
                                               questionId=2,
                                               valueSystem='c',
                                               valueCodeId=4)
        qr.answers.append(answer_1)
        qr.answers.append(answer_2)
        names_and_email_answers = self._names_and_email_answers()
        qr.answers.extend(names_and_email_answers)
        with FakeClock(TIME_2):
            self.questionnaire_response_dao.insert(qr)

        expected_qr = QuestionnaireResponse(
            questionnaireResponseId=1,
            questionnaireId=1,
            questionnaireVersion=1,
            participantId=1,
            resource=with_id(QUESTIONNAIRE_RESPONSE_RESOURCE, 1),
            created=TIME_2,
            authored=TIME_2)
        qr2 = self.questionnaire_response_dao.get(1)
        self.assertEquals(expected_qr.asdict(), qr2.asdict())

        expected_qr.answers.append(answer_1)
        expected_qr.answers.append(answer_2)
        expected_qr.answers.extend(names_and_email_answers)
        self.check_response(expected_qr)

        expected_ps = self._participant_summary_with_defaults(
            participantId=1,
            biobankId=2,
            genderIdentityId=3,
            signUpTime=TIME,
            numCompletedBaselinePPIModules=1,
            numCompletedPPIModules=1,
            questionnaireOnTheBasics=QuestionnaireStatus.SUBMITTED,
            questionnaireOnTheBasicsTime=TIME_2,
            questionnaireOnTheBasicsAuthored=TIME_2,
            consentForStudyEnrollment=QuestionnaireStatus.SUBMITTED,
            consentForStudyEnrollmentTime=TIME_2,
            consentForStudyEnrollmentAuthored=TIME_2,
            lastModified=TIME_2,
            firstName=self.first_name,
            lastName=self.last_name,
            email=self.email)
        self.assertEquals(expected_ps.asdict(),
                          self.participant_summary_dao.get(1).asdict())

    def test_insert_qr_three_times(self):
        """Adds three questionnaire responses for the same participant.

    The latter two responses are for the same questionnaire, answering a question that has the
    same concept code and system as a question found on the first (different) questionnaire.

    Verifies that new answers set endTime on answers for questions with the same concept for the
    same participant, whether on the same questionnaire or a different questionnaire,
    without affecting other answers.
    """
        self.insert_codes()
        p = Participant(participantId=1, biobankId=2)
        with FakeClock(TIME):
            self.participant_dao.insert(p)
        self._setup_questionnaire()
        q2 = Questionnaire(resource=QUESTIONNAIRE_RESOURCE_2)
        # The question on the second questionnaire has the same concept as the first question on the
        # first questionnaire; answers to it will thus set endTime for answers to the first question.
        q2.questions.append(self.CODE_1_QUESTION_2)

        self.questionnaire_dao.insert(q2)

        qr = QuestionnaireResponse(questionnaireResponseId=1,
                                   questionnaireId=1,
                                   questionnaireVersion=1,
                                   participantId=1,
                                   resource=QUESTIONNAIRE_RESPONSE_RESOURCE)
        answer_1 = QuestionnaireResponseAnswer(
            questionnaireResponseAnswerId=1,
            questionnaireResponseId=1,
            questionId=1,
            valueSystem='a',
            valueCodeId=3,
            valueDecimal=123,
            valueString=self.fake.first_name(),
            valueDate=datetime.date.today())
        answer_2 = QuestionnaireResponseAnswer(questionnaireResponseAnswerId=2,
                                               questionnaireResponseId=1,
                                               questionId=2,
                                               valueSystem='c',
                                               valueCodeId=4)
        qr.answers.append(answer_1)
        qr.answers.append(answer_2)
        qr.answers.extend(self._names_and_email_answers())
        with FakeClock(TIME_2):
            self.questionnaire_response_dao.insert(qr)

        expected_ps = self._participant_summary_with_defaults(
            participantId=1,
            biobankId=2,
            genderIdentityId=3,
            signUpTime=TIME,
            numCompletedBaselinePPIModules=1,
            numCompletedPPIModules=1,
            questionnaireOnTheBasics=QuestionnaireStatus.SUBMITTED,
            questionnaireOnTheBasicsTime=TIME_2,
            questionnaireOnTheBasicsAuthored=TIME_2,
            consentForStudyEnrollment=QuestionnaireStatus.SUBMITTED,
            consentForStudyEnrollmentTime=TIME_2,
            consentForStudyEnrollmentAuthored=TIME_2,
            lastModified=TIME_2,
            firstName=self.first_name,
            lastName=self.last_name,
            email=self.email)
        self.assertEquals(expected_ps.asdict(),
                          self.participant_summary_dao.get(1).asdict())

        qr2 = QuestionnaireResponse(questionnaireResponseId=2,
                                    questionnaireId=2,
                                    questionnaireVersion=1,
                                    participantId=1,
                                    resource=QUESTIONNAIRE_RESPONSE_RESOURCE_2)
        answer_3 = QuestionnaireResponseAnswer(
            questionnaireResponseAnswerId=6,
            questionnaireResponseId=2,
            questionId=7,
            valueSystem='x',
            valueCodeId=5,
            valueDecimal=123,
            valueString=self.fake.last_name(),
            valueDate=datetime.date.today())
        qr2.answers.append(answer_3)
        with FakeClock(TIME_3):
            qr2.authored = TIME_3
            self.questionnaire_response_dao.insert(qr2)

        expected_qr = QuestionnaireResponse(
            questionnaireResponseId=1,
            questionnaireId=1,
            questionnaireVersion=1,
            participantId=1,
            resource=with_id(QUESTIONNAIRE_RESPONSE_RESOURCE, 1),
            created=TIME_2,
            authored=TIME_2)
        # Answer one on the original response should be marked as ended, since a question with
        # the same concept was answered. Answer two should be left alone.
        answer_1.endTime = TIME_3
        expected_qr.answers.append(answer_1)
        expected_qr.answers.append(answer_2)
        expected_qr.answers.extend(self._names_and_email_answers())
        self.check_response(expected_qr)

        # The new questionnaire response should be there, too.
        expected_qr2 = QuestionnaireResponse(
            questionnaireResponseId=2,
            questionnaireId=2,
            questionnaireVersion=1,
            participantId=1,
            resource=with_id(QUESTIONNAIRE_RESPONSE_RESOURCE_2, 2),
            created=TIME_3,
            authored=TIME_3)
        expected_qr2.answers.append(answer_3)
        self.check_response(expected_qr2)

        expected_ps2 = self._participant_summary_with_defaults(
            participantId=1,
            biobankId=2,
            genderIdentityId=5,
            signUpTime=TIME,
            numCompletedBaselinePPIModules=1,
            numCompletedPPIModules=1,
            questionnaireOnTheBasics=QuestionnaireStatus.SUBMITTED,
            questionnaireOnTheBasicsTime=TIME_2,
            questionnaireOnTheBasicsAuthored=TIME_2,
            lastModified=TIME_3,
            consentForStudyEnrollment=QuestionnaireStatus.SUBMITTED,
            consentForStudyEnrollmentTime=TIME_2,
            consentForStudyEnrollmentAuthored=TIME_2,
            firstName=self.first_name,
            lastName=self.last_name,
            email=self.email)
        # The participant summary should be updated with the new gender identity, but nothing else
        # changes.
        self.assertEquals(expected_ps2.asdict(),
                          self.participant_summary_dao.get(1).asdict())

        qr3 = QuestionnaireResponse(questionnaireResponseId=3,
                                    questionnaireId=2,
                                    questionnaireVersion=1,
                                    participantId=1,
                                    resource=QUESTIONNAIRE_RESPONSE_RESOURCE_3)
        answer_4 = QuestionnaireResponseAnswer(
            questionnaireResponseAnswerId=7,
            questionnaireResponseId=3,
            questionId=7,
            valueSystem='z',
            valueCodeId=6,
            valueDecimal=456,
            valueString=self.fake.last_name(),
            valueDate=datetime.date.today())
        qr3.answers.append(answer_4)
        with FakeClock(TIME_4):
            qr3.authored = TIME_4
            self.questionnaire_response_dao.insert(qr3)

        # The first questionnaire response hasn't changed.
        self.check_response(expected_qr)

        # The second questionnaire response's answer should have had an endTime set.
        answer_3.endTime = TIME_4
        self.check_response(expected_qr2)

        # The third questionnaire response should be there.
        expected_qr3 = QuestionnaireResponse(
            questionnaireResponseId=3,
            questionnaireId=2,
            questionnaireVersion=1,
            participantId=1,
            resource=with_id(QUESTIONNAIRE_RESPONSE_RESOURCE_3, 3),
            created=TIME_4,
            authored=TIME_4)
        expected_qr3.answers.append(answer_4)
        self.check_response(expected_qr3)

        expected_ps3 = self._participant_summary_with_defaults(
            participantId=1,
            biobankId=2,
            genderIdentityId=6,
            signUpTime=TIME,
            numCompletedBaselinePPIModules=1,
            numCompletedPPIModules=1,
            questionnaireOnTheBasics=QuestionnaireStatus.SUBMITTED,
            questionnaireOnTheBasicsTime=TIME_2,
            questionnaireOnTheBasicsAuthored=TIME_2,
            consentForStudyEnrollment=QuestionnaireStatus.SUBMITTED,
            consentForStudyEnrollmentTime=TIME_2,
            consentForStudyEnrollmentAuthored=TIME_2,
            lastModified=TIME_4,
            firstName=self.first_name,
            lastName=self.last_name,
            email=self.email)
        # The participant summary should be updated with the new gender identity, but nothing else
        # changes.
        self.assertEquals(expected_ps3.asdict(),
                          self.participant_summary_dao.get(1).asdict())

    def _get_questionnaire_response_with_consents(self, *consent_paths):
        self.insert_codes()
        questionnaire = self._setup_questionnaire()
        participant = Participant(participantId=1, biobankId=2)
        self.participant_dao.insert(participant)
        resource = test_data.load_questionnaire_response_with_consents(
            questionnaire.questionnaireId, participant.participantId,
            self.FN_QUESTION.linkId, self.LN_QUESTION.linkId,
            self.EMAIL_QUESTION.linkId, consent_paths)

        # We need to remove the unused answers in the resource so we don't trigger an unused
        # link id exception.
        res_len = len(resource['group']['question']) - 1
        for idx in range(res_len, -1, -1):
            if resource['group']['question'][idx]['linkId'].isdigit() is True:
                del resource['group']['question'][idx]

        questionnaire_response = self.questionnaire_response_dao.from_client_json(
            resource, participant.participantId)

        return questionnaire_response

    @mock.patch('dao.questionnaire_response_dao._raise_if_gcloud_file_missing')
    def test_consent_pdf_valid_leading_slash(self, mock_gcloud_check):
        consent_pdf_path = '/Participant/xyz/consent.pdf'
        questionnaire_response = self._get_questionnaire_response_with_consents(
            consent_pdf_path)
        # This should pass validation (not raise exceptions).
        self.questionnaire_response_dao.insert(questionnaire_response)
        mock_gcloud_check.assert_called_with('/%s%s' %
                                             (_FAKE_BUCKET, consent_pdf_path))

    @mock.patch('dao.questionnaire_response_dao._raise_if_gcloud_file_missing')
    def test_consent_pdf_valid_no_leading_slash(self, mock_gcloud_check):
        consent_pdf_path = 'Participant/xyz/consent.pdf'
        questionnaire_response = self._get_questionnaire_response_with_consents(
            consent_pdf_path)
        # This should pass validation (not raise exceptions).
        self.questionnaire_response_dao.insert(questionnaire_response)
        mock_gcloud_check.assert_called_with('/%s/%s' %
                                             (_FAKE_BUCKET, consent_pdf_path))

    @mock.patch('dao.questionnaire_response_dao._raise_if_gcloud_file_missing')
    def test_consent_pdf_file_invalid(self, mock_gcloud_check):
        mock_gcloud_check.side_effect = BadRequest('Test should raise this.')
        qr = self._get_questionnaire_response_with_consents(
            '/nobucket/no/file.pdf')
        with self.assertRaises(BadRequest):
            self.questionnaire_response_dao.insert(qr)

    @mock.patch('dao.questionnaire_response_dao._raise_if_gcloud_file_missing')
    def test_consent_pdf_checks_multiple_extensions(self, mock_gcloud_check):
        qr = self._get_questionnaire_response_with_consents(
            '/Participant/one.pdf', '/Participant/two.pdf')
        self.questionnaire_response_dao.insert(qr)
        self.assertEquals(mock_gcloud_check.call_count, 2)
示例#9
0
class OrganizationDaoTest(SqlTestBase):

  def setUp(self):
    super(OrganizationDaoTest, self).setUp()
    self.organization_dao = OrganizationDao()
    self.participant_dao = ParticipantDao()
    self.ps_dao = ParticipantSummaryDao()
    self.ps_history = ParticipantHistoryDao()

  def test_insert(self):
    organization = Organization(externalId='myorg', displayName='myorg_display',
                                hpoId=PITT_HPO_ID, isObsolete=1)
    created_organization = self.organization_dao.insert(organization)
    new_organization = self.organization_dao.get(created_organization.organizationId)
    organization.organizationId = created_organization.organizationId
    organization.isObsolete = new_organization.isObsolete
    self.assertEquals(organization.asdict(), new_organization.asdict())

  def test_participant_pairing_updates_onchange(self):
    provider_link = '[{"organization": {"reference": "Organization/AZ_TUCSON"}, "primary": true}]'
    TIME = datetime.datetime(2018, 1, 1)
    TIME2 = datetime.datetime(2018, 1, 2)
    insert_org = self.organization_dao.insert(
      Organization(externalId='tardis', displayName='bluebox', hpoId=PITT_HPO_ID))

    with FakeClock(TIME):
      self.participant_dao.insert(Participant(participantId=1, biobankId=2))
      participant = self.participant_dao.get(1)
      participant.organizationId = insert_org.organizationId
      self.participant_dao.update(participant)

      self.assertEquals(participant.hpoId, insert_org.hpoId)
      participant = self.participant_dao.get(1)
      p_summary = self.ps_dao.insert(self.participant_summary(participant))

    with FakeClock(TIME2):
      insert_org.hpoId = AZ_HPO_ID
      self.organization_dao.update(insert_org)

    new_org = self.organization_dao.get_by_external_id('tardis')
    ps = self.ps_dao.get(p_summary.participantId)
    ph = self.ps_history.get([participant.participantId, 2])
    participant = self.participant_dao.get(1)

    self.assertEquals(ps.lastModified, TIME2)
    self.assertEquals(ps.hpoId, new_org.hpoId)
    self.assertEquals(ph.hpoId, insert_org.hpoId)
    self.assertEquals(ph.organizationId, insert_org.organizationId)
    self.assertEquals(new_org.hpoId, participant.hpoId)
    self.assertEquals(new_org.organizationId, participant.organizationId)
    self.assertIsNone(participant.siteId)
    self.assertEquals(participant.providerLink, provider_link)

  def test_participant_different_hpo_does_not_change(self):
    insert_org = self.organization_dao.insert(
      Organization(externalId='stark_industries', displayName='ironman', hpoId=PITT_HPO_ID))

    self.participant_dao.insert(Participant(participantId=1, biobankId=2))
    participant = self.participant_dao.get(1)
    participant.hpoId = UNSET_HPO_ID
    self.participant_dao.update(participant)
    insert_org.hpoId = AZ_HPO_ID
    self.organization_dao.update(insert_org)
    new_org = self.organization_dao.get_by_external_id('stark_industries')
    participant = self.participant_dao.get(1)
    self.assertNotEqual(new_org.hpoId, participant.hpoId)
    self.assertEqual(new_org.hpoId, AZ_HPO_ID)
    self.assertEqual(participant.hpoId, UNSET_HPO_ID)
示例#10
0
class MetricsEhrApiTestBase(FlaskTestBase):
    def setUp(self, **kwargs):
        super(MetricsEhrApiTestBase, self).setUp(use_mysql=True, **kwargs)
        self.dao = ParticipantDao()
        self.ps_dao = ParticipantSummaryDao()
        self.ehr_receipt_dao = EhrReceiptDao()
        self.ps = ParticipantSummary()
        self.calendar_dao = CalendarDao()
        self.site_dao = SiteDao()
        self.hpo_dao = HPODao()
        self.org_dao = OrganizationDao()

        self.hpo_test = self._make_hpo(hpoId=TEST_HPO_ID,
                                       name=TEST_HPO_NAME,
                                       displayName='Test',
                                       organizationType=OrganizationType.UNSET)

        self.hpo_foo = self._make_hpo(hpoId=10, name='FOO', displayName='Foo')
        self.hpo_bar = self._make_hpo(hpoId=11, name='BAR', displayName='Bar')

        self.org_foo_a = self._make_org(organizationId=10,
                                        externalId='FOO_A',
                                        displayName='Foo A',
                                        hpoId=self.hpo_foo.hpoId)
        self.org_bar_a = self._make_org(organizationId=11,
                                        externalId='BAR_A',
                                        displayName='Bar A',
                                        hpoId=self.hpo_bar.hpoId)

    def _make_hpo(self, **kwargs):
        hpo = HPO(**kwargs)
        self.hpo_dao.insert(hpo)
        return hpo

    def _make_org(self, **kwargs):
        org = Organization(**kwargs)
        self.org_dao.insert(org)
        return org

    def _make_participant(self,
                          participant,
                          first_name=None,
                          last_name=None,
                          hpo=None,
                          organization=None,
                          unconsented=False,
                          time_int=None,
                          time_study=None,
                          time_mem=None,
                          time_fp=None,
                          time_fp_stored=None,
                          gender_id=None,
                          dob=None,
                          state_id=None):
        """
    Create a participant in a transient test database.

    Note: copied from ParticipantCountsOverTimeApiTest

    :param participant: Participant object
    :param first_name: First name
    :param last_name: Last name
    :param time_int: Time that participant fulfilled INTERESTED criteria
    :param time_mem: Time that participant fulfilled MEMBER criteria
    :param time_fp: Time that participant fulfilled FULL_PARTICIPANT criteria
    :return: Participant object
    """

        participant.hpoId = hpo.hpoId
        participant.organizationId = organization.organizationId

        if unconsented is True:
            enrollment_status = None
        elif time_mem is None:
            enrollment_status = EnrollmentStatus.INTERESTED
        elif time_fp is None:
            enrollment_status = EnrollmentStatus.MEMBER
        else:
            enrollment_status = EnrollmentStatus.FULL_PARTICIPANT

        with FakeClock(time_int):
            self.dao.insert(participant)

        participant.providerLink = make_primary_provider_link_for_name(
            hpo.name)
        with FakeClock(time_mem):
            self.dao.update(participant)

        if enrollment_status is None:
            return None

        summary = self.participant_summary(participant)

        if first_name:
            summary.firstName = first_name
        if last_name:
            summary.lastName = last_name

        if gender_id:
            summary.genderIdentityId = gender_id
        if dob:
            summary.dateOfBirth = dob
        else:
            summary.dateOfBirth = datetime.date(1978, 10, 10)
        if state_id:
            summary.stateId = state_id

        summary.enrollmentStatus = enrollment_status

        summary.enrollmentStatusMemberTime = time_mem
        summary.enrollmentStatusCoreOrderedSampleTime = time_fp
        summary.enrollmentStatusCoreStoredSampleTime = time_fp_stored

        summary.hpoId = hpo.hpoId
        summary.organizationId = organization.organizationId

        if time_study is not None:
            with FakeClock(time_mem):
                summary.consentForStudyEnrollment = QuestionnaireStatus.SUBMITTED
                summary.consentForStudyEnrollmentTime = time_study

        if time_mem is not None:
            with FakeClock(time_mem):
                summary.consentForElectronicHealthRecords = QuestionnaireStatus.SUBMITTED
                summary.consentForElectronicHealthRecordsTime = time_mem

        if time_fp is not None:
            with FakeClock(time_fp):
                if not summary.consentForElectronicHealthRecords:
                    summary.consentForElectronicHealthRecords = QuestionnaireStatus.SUBMITTED
                    summary.consentForElectronicHealthRecordsTime = time_fp
                summary.questionnaireOnTheBasicsTime = time_fp
                summary.questionnaireOnLifestyleTime = time_fp
                summary.questionnaireOnOverallHealthTime = time_fp
                summary.physicalMeasurementsFinalizedTime = time_fp
                summary.physicalMeasurementsTime = time_fp
                summary.sampleOrderStatus1ED04Time = time_fp
                summary.sampleOrderStatus1SALTime = time_fp
                summary.sampleStatus1ED04Time = time_fp
                summary.sampleStatus1SALTime = time_fp
                summary.biospecimenOrderTime = time_fp
                summary.numCompletedBaselinePPIModules = REQUIRED_PPI_MODULE_COUNT

        self.ps_dao.insert(summary)

        return summary

    def _update_ehr(self, participant_summary, update_time):
        receipt = EhrReceipt(organizationId=participant_summary.organizationId,
                             receiptTime=update_time)
        self.ehr_receipt_dao.insert(receipt)
        self.ps_dao.update_ehr_status(participant_summary, update_time)
        self.ps_dao.update(participant_summary)