def test_participant_race_answers(self): with FakeClock(TIME_1): participant_id = self.create_participant() self.send_consent(participant_id) questionnaire_id = self.create_questionnaire('questionnaire_the_basics.json') with open(data_path('questionnaire_the_basics_resp_multiple_race.json')) as f: resource = json.load(f) resource['subject']['reference'] = \ resource['subject']['reference'].format(participant_id=participant_id) resource['questionnaire']['reference'] = \ resource['questionnaire']['reference'].format(questionnaire_id=questionnaire_id) with FakeClock(TIME_2): resource['authored'] = TIME_2.isoformat() self.send_post(_questionnaire_response_url(participant_id), resource) code_dao = CodeDao() code1 = code_dao.get_code('http://terminology.pmi-ops.org/CodeSystem/ppi', 'WhatRaceEthnicity_White') code2 = code_dao.get_code('http://terminology.pmi-ops.org/CodeSystem/ppi', 'WhatRaceEthnicity_Hispanic') participant_race_answers_dao = ParticipantRaceAnswersDao() answers = participant_race_answers_dao.get_all() self.assertEqual(len(answers), 2) for answer in answers: self.assertIn(answer.codeId, [code1.codeId, code2.codeId]) # resubmit the answers, old value should be removed with open(data_path('questionnaire_the_basics_resp_multiple_race_2.json')) as f: resource = json.load(f) resource['subject']['reference'] = \ resource['subject']['reference'].format(participant_id=participant_id) resource['questionnaire']['reference'] = \ resource['questionnaire']['reference'].format(questionnaire_id=questionnaire_id) with FakeClock(TIME_2): resource['authored'] = TIME_2.isoformat() self.send_post(_questionnaire_response_url(participant_id), resource) code_dao = CodeDao() code1 = code_dao.get_code('http://terminology.pmi-ops.org/CodeSystem/ppi', 'WhatRaceEthnicity_NHPI') code2 = code_dao.get_code('http://terminology.pmi-ops.org/CodeSystem/ppi', 'PMI_PreferNotToAnswer') answers = participant_race_answers_dao.get_all() self.assertEqual(len(answers), 2) for answer in answers: self.assertIn(answer.codeId, [code1.codeId, code2.codeId])
def test_invalid_questionnaire(self): participant_id = self.create_participant() questionnaire_id = self.create_questionnaire('questionnaire1.json') q = QuestionnaireDao() quesstionnaire = q.get(questionnaire_id) make_transient(quesstionnaire) quesstionnaire.status = QuestionnaireDefinitionStatus.INVALID q.update(quesstionnaire) q.get(questionnaire_id) with open(data_path('questionnaire_response3.json')) as fd: resource = json.load(fd) self.send_consent(participant_id) resource['subject']['reference'] = \ resource['subject']['reference'].format(participant_id=participant_id) # The resource gets rewritten to include the version resource['questionnaire']['reference'] = 'Questionnaire/%s' % questionnaire_id self.send_post(_questionnaire_response_url(participant_id), resource, expected_status=httplib.BAD_REQUEST) resource['questionnaire']['reference'] = 'Questionnaire/%s/_history/2' % questionnaire_id self.send_post(_questionnaire_response_url(participant_id), resource, expected_status=httplib.BAD_REQUEST)
def test_invalid_questionnaire_linkid(self): """ DA-623 - Make sure that an invalid link id in response triggers a BadRequest status. Per a PTSC group request, only log a message for invalid link ids. In the future if questionnaires with bad link ids trigger a BadRequest, the code below can be uncommented. """ participant_id = self.create_participant() self.send_consent(participant_id) questionnaire_id = self.create_questionnaire( 'questionnaire_family_history.json') with open(data_path('questionnaire_family_history_resp.json')) as fd: resource = json.load(fd) # update resource json to set participant and questionnaire ids. resource['subject']['reference'] = \ resource['subject']['reference'].format(participant_id=participant_id) resource['questionnaire']['reference'] = \ resource['questionnaire']['reference'].format(questionnaire_id=questionnaire_id) self.send_post(_questionnaire_response_url(participant_id), resource, expected_status=httplib.OK)
def test_update_no_ifmatch_specified(self): response = self.insert_questionnaire() with open(data_path('questionnaire2.json')) as f2: questionnaire2 = json.load(f2) self.send_put('Questionnaire/%s' % response['id'], questionnaire2, expected_status=httplib.BAD_REQUEST)
def test_update_wrong_ifmatch_specified(self): response = self.insert_questionnaire() with open(data_path('questionnaire2.json')) as f2: questionnaire2 = json.load(f2) self.send_put('Questionnaire/%s' % response['id'], questionnaire2, expected_status=httplib.PRECONDITION_FAILED, headers={ 'If-Match': 'W/"123"' })
def test_participant_gender_answers(self): with FakeClock(TIME_1): participant_id = self.create_participant() self.send_consent(participant_id) questionnaire_id = self.create_questionnaire('questionnaire_the_basics.json') with open(data_path('questionnaire_the_basics_resp_multiple_gender.json')) as f: resource = json.load(f) resource['subject']['reference'] = \ resource['subject']['reference'].format(participant_id=participant_id) resource['questionnaire']['reference'] = \ resource['questionnaire']['reference'].format(questionnaire_id=questionnaire_id) with FakeClock(TIME_2): resource['authored'] = TIME_2.isoformat() self.send_post(_questionnaire_response_url(participant_id), resource) participant_gender_answers_dao = ParticipantGenderAnswersDao() answers = participant_gender_answers_dao.get_all() self.assertEqual(len(answers), 2) for answer in answers: self.assertIn(answer.codeId, [90, 95]) # resubmit the answers, old value should be removed with open(data_path('questionnaire_the_basics_resp_multiple_gender_2.json')) as f: resource = json.load(f) resource['subject']['reference'] = \ resource['subject']['reference'].format(participant_id=participant_id) resource['questionnaire']['reference'] = \ resource['questionnaire']['reference'].format(questionnaire_id=questionnaire_id) with FakeClock(TIME_2): resource['authored'] = TIME_2.isoformat() self.send_post(_questionnaire_response_url(participant_id), resource) answers = participant_gender_answers_dao.get_all() self.assertEqual(len(answers), 2) for answer in answers: self.assertIn(answer.codeId, [100, 95])
def test_update_right_ifmatch_specified(self): response = self.insert_questionnaire() self.assertEquals('W/"1"', response['meta']['versionId']) with open(data_path('questionnaire2.json')) as f2: questionnaire2 = json.load(f2) update_response = self.send_put('Questionnaire/%s' % response['id'], questionnaire2, headers={ 'If-Match': response['meta']['versionId'] }, expected_response_headers = { 'ETag': 'W/"2"'}) questionnaire2['id'] = response['id'] questionnaire2['version'] = '2' self.assertJsonResponseMatches(questionnaire2, update_response) self.assertEquals('W/"2"', update_response['meta']['versionId'])
def test_insert(self): questionnaire_files = ( 'questionnaire1.json', 'questionnaire2.json', 'questionnaire_demographics.json', ) for json_file in questionnaire_files: with open(data_path(json_file)) as f: questionnaire = json.load(f) response = self.send_post('Questionnaire', questionnaire) questionnaire_id = response['id'] del response['id'] questionnaire['version'] = '1' self.assertJsonResponseMatches(questionnaire, response) response = self.send_get('Questionnaire/%s' % questionnaire_id) del response['id'] self.assertJsonResponseMatches(questionnaire, response) # Ensure we didn't create codes in the extra system self.assertIsNone(CodeDao().get_code(PPI_EXTRA_SYSTEM, 'IgnoreThis'))
def test_column_missing(self): with open(test_data.data_path( 'biobank_samples_missing_field.csv')) as samples_file: reader = csv.DictReader(samples_file, delimiter='\t') with self.assertRaises(biobank_samples_pipeline.DataError): biobank_samples_pipeline._upsert_samples_from_csv(reader)
def create_questionnaire(self, filename): with open(data_path(filename)) as f: questionnaire = json.load(f) response = self.send_post('Questionnaire', questionnaire) return response['id']
def test_insert(self): participant_id = self.create_participant() questionnaire_id = self.create_questionnaire('questionnaire1.json') with open(data_path('questionnaire_response3.json')) as fd: resource = json.load(fd) # Sending response with the dummy participant id in the file is an error self.send_post(_questionnaire_response_url('{participant_id}'), resource, expected_status=httplib.NOT_FOUND) # Fixing participant id but not the questionnaire id is also an error resource['subject']['reference'] = \ resource['subject']['reference'].format(participant_id=participant_id) self.send_post(_questionnaire_response_url(participant_id), resource, expected_status=httplib.BAD_REQUEST) # Fix the reference resource['questionnaire']['reference'] = \ resource['questionnaire']['reference'].format(questionnaire_id=questionnaire_id) # Sending the response before the consent is an error. self.send_post(_questionnaire_response_url(participant_id), resource, expected_status=httplib.BAD_REQUEST) # After consent, the post succeeds self.send_consent(participant_id) response = self.send_post(_questionnaire_response_url(participant_id), resource) resource['id'] = response['id'] # The resource gets rewritten to include the version resource['questionnaire'][ 'reference'] = 'Questionnaire/%s/_history/1' % questionnaire_id self.assertJsonResponseMatches(resource, response) # Do a get to fetch the questionnaire get_response = self.send_get( _questionnaire_response_url(participant_id) + "/" + response['id']) self.assertJsonResponseMatches(resource, get_response) code_dao = CodeDao() # Ensure we didn't create codes in the extra system self.assertIsNone(code_dao.get_code(PPI_EXTRA_SYSTEM, 'IgnoreThis')) name_of_child = code_dao.get_code("sys", "nameOfChild") birth_weight = code_dao.get_code("sys", "birthWeight") birth_length = code_dao.get_code("sys", "birthLength") vitamin_k_dose_1 = code_dao.get_code("sys", "vitaminKDose1") vitamin_k_dose_2 = code_dao.get_code("sys", "vitaminKDose2") hep_b_given = code_dao.get_code("sys", "hepBgiven") abnormalities_at_birth = code_dao.get_code("sys", "abnormalitiesAtBirth") answer_dao = QuestionnaireResponseAnswerDao() with answer_dao.session() as session: code_ids = [ code.codeId for code in [ name_of_child, birth_weight, birth_length, vitamin_k_dose_1, vitamin_k_dose_2, hep_b_given, abnormalities_at_birth ] ] current_answers = answer_dao.get_current_answers_for_concepts(session,\ from_client_participant_id(participant_id), code_ids) self.assertEquals(7, len(current_answers)) questionnaire = QuestionnaireDao().get_with_children(questionnaire_id) question_id_to_answer = { answer.questionId: answer for answer in current_answers } code_id_to_answer = { question.codeId: question_id_to_answer.get(question.questionnaireQuestionId) for question in questionnaire.questions } self.assertEquals("Cathy Jones", code_id_to_answer[name_of_child.codeId].valueString) self.assertEquals(3.25, code_id_to_answer[birth_weight.codeId].valueDecimal) self.assertEquals(44.3, code_id_to_answer[birth_length.codeId].valueDecimal) self.assertEquals(44, code_id_to_answer[birth_length.codeId].valueInteger) self.assertEquals(True, code_id_to_answer[hep_b_given.codeId].valueBoolean) self.assertEquals( 0, code_id_to_answer[abnormalities_at_birth.codeId].valueInteger) self.assertEquals(datetime.date(1972, 11, 30), code_id_to_answer[vitamin_k_dose_1.codeId].valueDate) self.assertEquals( datetime.datetime(1972, 11, 30, 12, 34, 42), code_id_to_answer[vitamin_k_dose_2.codeId].valueDateTime)
def test_demographic_questionnaire_responses(self): with FakeClock(TIME_1): participant_id = self.create_participant() self.send_consent(participant_id) questionnaire_id = self.create_questionnaire( 'questionnaire_demographics.json') with open(data_path('questionnaire_response_demographics.json')) as f: resource = json.load(f) resource['subject']['reference'] = \ resource['subject']['reference'].format(participant_id=participant_id) resource['questionnaire']['reference'] = \ resource['questionnaire']['reference'].format(questionnaire_id=questionnaire_id) with FakeClock(TIME_2): self.send_post(_questionnaire_response_url(participant_id), resource) participant = self.send_get('Participant/%s' % participant_id) summary = self.send_get('Participant/%s/Summary' % participant_id) expected = { 'ageRange': 'UNSET', 'genderIdentity': 'UNMAPPED', 'firstName': self.first_name, 'lastName': self.last_name, 'email': self.email, 'race': 'UNSET', 'hpoId': 'UNSET', 'awardee': 'UNSET', 'site': 'UNSET', 'organization': 'UNSET', 'education': 'UNSET', 'income': 'UNSET', 'language': 'UNSET', 'sex': 'UNSET', 'sexualOrientation': 'UNSET', 'state': 'UNSET', 'recontactMethod': 'UNSET', 'enrollmentStatus': 'INTERESTED', 'samplesToIsolateDNA': 'UNSET', 'numBaselineSamplesArrived': 0, 'numCompletedPPIModules': 1, 'numCompletedBaselinePPIModules': 1, 'biobankId': participant['biobankId'], 'participantId': participant_id, 'physicalMeasurementsStatus': 'UNSET', 'consentForElectronicHealthRecords': 'UNSET', 'consentForStudyEnrollment': 'SUBMITTED', 'consentForStudyEnrollmentTime': TIME_1.isoformat(), 'consentForCABoR': 'UNSET', 'questionnaireOnFamilyHealth': 'UNSET', 'questionnaireOnHealthcareAccess': 'UNSET', 'questionnaireOnMedicalHistory': 'UNSET', 'questionnaireOnMedications': 'UNSET', 'questionnaireOnOverallHealth': 'UNSET', 'questionnaireOnLifestyle': 'UNSET', 'questionnaireOnTheBasics': 'SUBMITTED', 'questionnaireOnTheBasicsTime': TIME_2.isoformat(), 'biospecimenCollectedSite': 'UNSET', 'biospecimenFinalizedSite': 'UNSET', 'biospecimenProcessedSite': 'UNSET', 'biospecimenSourceSite': 'UNSET', 'physicalMeasurementsCreatedSite': 'UNSET', 'physicalMeasurementsFinalizedSite': 'UNSET', 'biospecimenStatus': 'UNSET', 'sampleOrderStatus1ED04': 'UNSET', 'sampleOrderStatus1ED10': 'UNSET', 'sampleOrderStatus1HEP4': 'UNSET', 'sampleOrderStatus1PST8': 'UNSET', 'sampleOrderStatus1PS08': 'UNSET', 'sampleOrderStatus2PST8': 'UNSET', 'sampleOrderStatus1SAL': 'UNSET', 'sampleOrderStatus1SST8': 'UNSET', 'sampleOrderStatus2SST8': 'UNSET', 'sampleOrderStatus1SS08': 'UNSET', 'sampleOrderStatus1UR10': 'UNSET', 'sampleOrderStatus2ED10': 'UNSET', 'sampleStatus1ED04': 'UNSET', 'sampleStatus1ED10': 'UNSET', 'sampleStatus1HEP4': 'UNSET', 'sampleStatus1PST8': 'UNSET', 'sampleStatus2PST8': 'UNSET', 'sampleStatus1PS08': 'UNSET', 'sampleStatus1SAL': 'UNSET', 'sampleStatus1SST8': 'UNSET', 'sampleStatus2SST8': 'UNSET', 'sampleStatus1SS08': 'UNSET', 'sampleStatus1UR10': 'UNSET', 'sampleStatus2ED10': 'UNSET', 'samplesToIsolateDNA': 'UNSET', 'signUpTime': TIME_1.isoformat(), 'withdrawalStatus': 'NOT_WITHDRAWN', 'suspensionStatus': 'NOT_SUSPENDED', } self.assertJsonResponseMatches(expected, summary)
def test_consent_with_extension_language(self): with FakeClock(TIME_1): participant_id = self.create_participant() self.send_consent(participant_id, language='es') participant = self.send_get('Participant/%s' % participant_id) summary = self.send_get('Participant/%s/Summary' % participant_id) expected = { 'ageRange': 'UNSET', 'genderIdentity': 'UNSET', 'firstName': self.first_name, 'lastName': self.last_name, 'email': self.email, 'streetAddress': self.streetAddress, 'streetAddress2': self.streetAddress2, 'race': 'UNSET', 'hpoId': 'UNSET', 'awardee': 'UNSET', 'site': 'UNSET', 'organization': 'UNSET', 'education': 'UNSET', 'income': 'UNSET', "language": "UNSET", 'sex': 'UNSET', 'sexualOrientation': 'UNSET', 'state': 'UNSET', 'recontactMethod': 'UNSET', 'enrollmentStatus': 'INTERESTED', 'samplesToIsolateDNA': 'UNSET', 'numBaselineSamplesArrived': 0, 'numCompletedPPIModules': 0, 'numCompletedBaselinePPIModules': 0, 'biobankId': participant['biobankId'], 'participantId': participant_id, 'physicalMeasurementsStatus': 'UNSET', 'consentForDvElectronicHealthRecordsSharing': 'UNSET', 'consentForElectronicHealthRecords': 'UNSET', 'consentForStudyEnrollment': 'SUBMITTED', 'consentForStudyEnrollmentTime': TIME_1.isoformat(), 'consentForStudyEnrollmentAuthored': TIME_1.isoformat(), 'consentForCABoR': 'UNSET', 'primaryLanguage': 'es', 'questionnaireOnFamilyHealth': 'UNSET', 'questionnaireOnHealthcareAccess': 'UNSET', 'questionnaireOnMedicalHistory': 'UNSET', 'questionnaireOnMedications': 'UNSET', 'questionnaireOnOverallHealth': 'UNSET', 'questionnaireOnLifestyle': 'UNSET', 'questionnaireOnTheBasics': 'UNSET', 'biospecimenCollectedSite': 'UNSET', 'biospecimenFinalizedSite': 'UNSET', 'biospecimenProcessedSite': 'UNSET', 'biospecimenSourceSite': 'UNSET', 'physicalMeasurementsCreatedSite': 'UNSET', 'physicalMeasurementsFinalizedSite': 'UNSET', 'biospecimenStatus': 'UNSET', 'sampleOrderStatus1ED04': 'UNSET', 'sampleOrderStatus1ED10': 'UNSET', 'sampleOrderStatus1HEP4': 'UNSET', 'sampleOrderStatus1PST8': 'UNSET', 'sampleOrderStatus1PS08': 'UNSET', 'sampleOrderStatus2PST8': 'UNSET', 'sampleOrderStatus1SAL': 'UNSET', 'sampleOrderStatus1SAL2': 'UNSET', 'sampleOrderStatus1SST8': 'UNSET', 'sampleOrderStatus2SST8': 'UNSET', 'sampleOrderStatus1SS08': 'UNSET', 'sampleOrderStatus1UR10': 'UNSET', 'sampleOrderStatus1UR90': 'UNSET', 'sampleOrderStatus2ED10': 'UNSET', 'sampleOrderStatus1CFD9': 'UNSET', 'sampleOrderStatus1PXR2': 'UNSET', 'sampleOrderStatus1ED02': 'UNSET', 'sampleOrderStatusDV1SAL2': 'UNSET', 'sampleStatus1ED04': 'UNSET', 'sampleStatus1ED10': 'UNSET', 'sampleStatus1HEP4': 'UNSET', 'sampleStatus1PST8': 'UNSET', 'sampleStatus2PST8': 'UNSET', 'sampleStatus1PS08': 'UNSET', 'sampleStatus1SAL': 'UNSET', 'sampleStatus1SAL2': 'UNSET', 'sampleStatus1SST8': 'UNSET', 'sampleStatus2SST8': 'UNSET', 'sampleStatus1SS08': 'UNSET', 'sampleStatus1UR10': 'UNSET', 'sampleStatus1UR90': 'UNSET', 'sampleStatus2ED10': 'UNSET', 'sampleStatus1CFD9': 'UNSET', 'sampleStatus1ED02': 'UNSET', 'sampleStatus1PXR2': 'UNSET', 'sampleStatusDV1SAL2': 'UNSET', 'signUpTime': TIME_1.isoformat(), 'withdrawalStatus': 'NOT_WITHDRAWN', 'withdrawalReason': 'UNSET', 'suspensionStatus': 'NOT_SUSPENDED', 'numberDistinctVisits': 0, 'ehrStatus': 'UNSET', } self.assertJsonResponseMatches(expected, summary) # verify if the response is not consent, the primary language will not change questionnaire_id = self.create_questionnaire( 'questionnaire_family_history.json') with open(data_path('questionnaire_family_history_resp.json')) as f: resource = json.load(f) resource['subject']['reference'] = \ resource['subject']['reference'].format(participant_id=participant_id) resource['questionnaire']['reference'] = \ resource['questionnaire']['reference'].format(questionnaire_id=questionnaire_id) with FakeClock(TIME_2): self.send_post(_questionnaire_response_url(participant_id), resource) summary = self.send_get('Participant/%s/Summary' % participant_id) self.assertEqual(expected['primaryLanguage'], summary['primaryLanguage'])
def test_update_before_insert(self): with open(data_path('questionnaire1.json')) as f: questionnaire = json.load(f) self.send_put('Questionnaire/1', questionnaire, expected_status=httplib.BAD_REQUEST)
def insert_questionnaire(self): with open(data_path('questionnaire1.json')) as f: questionnaire = json.load(f) return self.send_post('Questionnaire', questionnaire, expected_response_headers = { 'ETag': 'W/"1"'})