def test_internal_matching(database, gpx4_patients): """Testing the combined matching algorithm""" # load 2 test patients in mock database for patient in gpx4_patients: mme_pat = mme_patient(patient, True) # convert gene symbol to ensembl database['patients'].insert_one(mme_pat).inserted_id # 2 patients should be inserted results = database['patients'].find( {'genomicFeatures.gene.id': 'ENSG00000167468'}) assert len(list(results)) == 2 # test matching of one of the 2 patients against both patients in database proband_patient = mme_patient(gpx4_patients[0], True) match = internal_matcher(database, proband_patient, 0.5, 0.5) match_patients = match['results'][0]['patients'] assert len(match_patients) == 2 higest_scored_patient = match_patients[ 0] # first returned patient has higher score lowest_scored_patient = match_patients[ -1] # last returned patient has lower score assert higest_scored_patient['score']['patient'] > lowest_scored_patient[ 'score']['patient']
def test_internal_matching_with_threshold(database, gpx4_patients): # load 2 test patients in mock database for patient in gpx4_patients: mme_pat = mme_patient(patient, True) # convert gene symbol to ensembl database["patients"].insert_one(mme_pat).inserted_id # 2 patients should be inserted results = database["patients"].find( {"genomicFeatures.gene.id": "ENSG00000167468"}) assert len(list(results)) == 2 # test matching of one of the 2 patients against both patients in database proband_patient = mme_patient(gpx4_patients[0], True) match = internal_matcher( database=database, patient_obj=proband_patient, max_pheno_score=0.5, max_geno_score=0.5, max_results=5, score_threshold=0.5, ) match_patients = match["results"][0]["patients"] assert len( match_patients) == 1 # one patient is filtered out by search threshold
def test_match_ensembl_patient(mock_app, test_client, gpx4_patients, database): """Test matching patient with ensembl gene against patientMatcher database (internal matching)""" # add an authorized client to database ok_token = test_client["auth_token"] add_node(mongo_db=mock_app.db, obj=test_client, is_client=True) query_patient = {"patient": mme_patient(gpx4_patients[0], True)} assert query_patient["patient"]["genomicFeatures"][0]["gene"][ "id"].startswith("ENSG") # load 2 test patient in mock database assert len(gpx4_patients) == 2 inserted_ids = [] for pat in gpx4_patients: # convert patient in mme patient type (convert also gene to ensembl) mme_pat = mme_patient(pat, True) inserted_ids.append(backend_add_patient(database, mme_pat)) assert len(inserted_ids) == 2 # make sure that there are no patient matches in the 'matches collection' assert database["matches"].find_one() is None # send a POST request to match patient with patients in database response = mock_app.test_client().post("/match", data=json.dumps(query_patient), headers=auth_headers(ok_token)) assert response.status_code == 200 # POST request should be successful data = json.loads(response.data) # data should contain results and the max number of results is as defined in the config file assert len(data["results"]) == 2 assert type(data["results"]) == list # which is a list assert "patient" in data["results"][0] # of patients assert "score" in data["results"][0] # with matching scores assert "contact" in data["results"][0][ "patient"] # contact info should be available as well # make sure that a match object is created in db for this internal matching match = database["matches"].find_one() for res in match["results"]: for pat in res["patients"]: assert pat["patient"][ "contact"] # each result should have a contact person assert pat["score"]["patient"] > 0 # and query patient should have hgnc gene symbol saved as non-standard _geneName field assert match["data"]["patient"]["genomicFeatures"][0]["gene"][ "_geneName"] == "GPX4"
def check_request(database, request): """Check if request is valid, if it is return MME formatted patient Otherwise return error code. """ check_result = None # check that request is using a valid auth token if not authorize(database, request): LOG.info("Request is not authorized") return 401 try: # make sure request has valid json data request_json = request.get_json(force=True) except Exception as err: LOG.info("Json data in request is not valid:{}".format(err)) return 400 try: # validate json data against MME API validate_api(json_obj=request_json, is_request=True) except Exception as err: LOG.info("Patient data does not conform to API:{}".format(err)) return 422 formatted_patient = mme_patient(json_patient=request_json['patient'], convert_to_ensembl = True) return formatted_patient
def load_demo(path_to_json_data, mongo_db, convert_to_ensembl=False): """Inserts demo patient data into database Demo data consists of a set of 50 patients from this paper: http://onlinelibrary.wiley.com/doi/10.1002/humu.22850 Args: path_to_demo_data(str): absolute path to json file containing the demo patients. mongo_db(pymongo.database.Database) Returns: inserted_ids(list): the database ID of the inserted patients """ patients = [] # a list of dictionaries inserted_ids = [] #open json file and try to insert one patient at the time try: LOG.info('reading patients file') with open(path_to_json_data) as json_data: patients = json.load(json_data) # create a progress bar pbar = enlighten.Counter(total=len(patients), desc='', unit='patients') for json_patient in patients: #parse patient into format accepted by database patient = mme_patient(json_patient, convert_to_ensembl) inserted_id = backend_add_patient(mongo_db=mongo_db, patient=patient)[1] if inserted_id: inserted_ids.append(inserted_id) pbar.update() except Exception as err: LOG.fatal("An error occurred while importing benchmarking patients: {}".format(err)) return inserted_ids
def test_backend_remove_patient(gpx4_patients, database): """ Test adding 2 test patients and then removing them using label or ID """ # test conversion to format required for the database: test_mme_patients = [ mme_patient(json_patient=patient) for patient in gpx4_patients] # make sure 2 json patient are correctly parsed assert len(test_mme_patients) == 2 # insert the 2 patients into the database inserted_ids = [ backend_add_patient(mongo_db=database, patient=mme_patient, match_external=False) for mme_patient in test_mme_patients ] assert len(inserted_ids) == 2 # make sure that inserted patients contain computed phenotypes from Monarch a_patient = database['patients'].find_one() assert a_patient # test removing a patient by ID: remove_query = {'_id' : 'P0001058'} deleted = delete_by_query(remove_query, database, 'patients') db_patients = database['patients'].find() assert db_patients.count() == 1 # test removing a patient by label: remove_query = {'label' : '350_2-test'} deleted = delete_by_query(remove_query, database, 'patients') db_patients = database['patients'].find() assert db_patients.count() == 0
def test_delete_patient(mock_app, database, gpx4_patients, test_client, match_objs): """Test deleting a patient from database by sending a DELETE request""" # load 2 patients from demo data in mock database assert len(gpx4_patients) == 2 inserted_ids = [] for pat in gpx4_patients: # convert patient in mme patient type (convert also gene to ensembl) mme_pat = mme_patient(pat, True) inserted_ids.append(backend_add_patient(database, mme_pat)) assert len(inserted_ids) == 2 # 50 cases present on patients collection delete_id = "P0001058" # try to delete patient without auth token: response = mock_app.test_client().delete("".join( ["patient/delete/", delete_id])) assert response.status_code == 401 # Add a valid client node ok_token = test_client["auth_token"] add_node(mongo_db=mock_app.db, obj=test_client, is_client=True) # Send delete request providing a valid token but a non valid id response = mock_app.test_client().delete("".join( ["patient/delete/", "not_a_valid_ID"]), headers=auth_headers(ok_token)) assert response.status_code == 200 data = json.loads(response.data) # but server returns error assert ( data["message"] == "ERROR. Could not delete a patient with ID not_a_valid_ID from database" ) assert database["matches"].find_one() is None # no matches in database # insert into database some mock matching objects database["matches"].insert_many(match_objs) # patient "delete_id" should have two associated matches in database results = database["matches"].find({"data.patient.id": delete_id}) assert len(list(results)) == 2 # Send valid patient ID and valid token response = mock_app.test_client().delete("".join( ["patient/delete/", delete_id]), headers=auth_headers(ok_token)) assert response.status_code == 200 # make sure that the patient was removed from database results = database["patients"].find() assert len(list(results)) == 1 # make sure that patient matches are also gone results = database["matches"].find() assert len(list(results)) == 1
def test_genotype_matching(database, gpx4_patients): """Testing the genotyping matching algorithm""" # load 2 test patients in mock database for patient in gpx4_patients: mme_pat = mme_patient(patient, True) # convert gene symbol to ensembl database['patients'].insert_one(mme_pat).inserted_id # 2 patients should be inserted assert database['patients'].find({ 'genomicFeatures.gene.id': 'ENSG00000167468' }).count() == 2 # test matching of a patient (with variants in genes) against the demo patients in database proband_patient = mme_patient(gpx4_patients[0], True) # assert patient has genomic features gt_features = proband_patient['genomicFeatures'] assert len(gt_features) == 2 # should have 2 feature to match assert gt_features[0]['gene']['id'] == 'ENSG00000167468' # match features against database with 2 patients matches = match(database, gt_features, 0.5) assert len(matches.keys()) == 2 # 2 matching patients are returned for key, value in matches.items(): # patient object should also be returned assert 'patient_obj' in value # genotype score for each patient should be higher than 0 assert value['geno_score'] > 0 # make sure that the algorithm works even if a gene or a variant object is missing: # remove gene ID from first gt feature gt_features[0]['gene']['id'] = '' matches = match(database, gt_features, 0.5) # same patient should be returned, because of variant matching instead assert len(matches) == 2 # Remove variant object from second gt feature gt_features[1]['variant'] = None matches = match(database, gt_features, 0.5) # same patients should be returned, because of gene matching instead assert len(matches.keys()) == 2
def test_phenotype_matching(gpx4_patients, database): """test the algorithm that compares the phenotype of a query patient against the database""" # insert 2 test patients into test database for patient in gpx4_patients: database["patients"].insert_one(patient) assert len(list(database["patients"].find())) == 2 query_patient = gpx4_patients[0] assert query_patient # this patient has HPO terms and OMIM diagnosis formatted_patient = mme_patient(query_patient) assert len(formatted_patient["features"]) > 0 assert len(formatted_patient["disorders"]) > 0 matches_HPO_OMIM = match(database, 0.75, formatted_patient["features"], formatted_patient["disorders"]) assert len(matches_HPO_OMIM.keys()) == 2 for key, value in matches_HPO_OMIM.items(): assert "patient_obj" in value assert value["pheno_score"] > 0 features = formatted_patient["features"] disorders = formatted_patient["disorders"] # remove HPO terms from the query patient, test that the algorithm works anyway # because matching will use OMIM disorders formatted_patient["features"] = [] matches_OMIM = match(database, 0.75, formatted_patient["features"], formatted_patient["disorders"]) assert len(matches_OMIM.keys()) > 0 and len(matches_OMIM.keys()) < 50 for key, value in matches_OMIM.items(): assert "patient_obj" in value assert value["pheno_score"] > 0 # remove the OMIM diagnosis from patient object. The algorithm should work # but it shouldn't return any match formatted_patient["disorders"] = [] matches_no_phenotypes = match(database, 0.75, formatted_patient["features"], formatted_patient["disorders"]) assert len(matches_no_phenotypes.keys()) == 0 # Add again features. The algorithm works again because HPO terms will be used formatted_patient["features"] = features matches_HPO = match(database, 0.75, formatted_patient["features"], formatted_patient["disorders"]) assert len(matches_HPO.keys()) == 2 for key, value in matches_HPO.items(): assert "patient_obj" in value assert value["pheno_score"] > 0 # make sure that matches obtained when OMIM and HPO terms are present are more or equal than # when either of these phenotype terms is present by itself assert len(matches_HPO_OMIM.keys()) >= len(matches_OMIM.keys()) assert len(matches_HPO_OMIM.keys()) >= len(matches_HPO.keys())
def test_mme_patient_entrez_gene(entrez_gene_patient, database): #Test format a patient with entrez gene # Before conversion patient's gene id is an entrez gene ID assert entrez_gene_patient['genomicFeatures'][0]['gene']['id'] == "3735" mme_formatted_patient = mme_patient(entrez_gene_patient, True) # convert genes to Ensembl # After conversion formatted patient's gene id should be an Ensembl id assert mme_formatted_patient['genomicFeatures'][0]['gene'][ 'id'].startswith('ENSG')
def test_mme_patient_entrez_gene(entrez_gene_patient, database): # Test format a patient with entrez gene # Before conversion patient's gene id is an entrez gene ID assert entrez_gene_patient["genomicFeatures"][0]["gene"]["id"] == "3735" mme_formatted_patient = mme_patient(entrez_gene_patient, True) # convert genes to Ensembl # After conversion formatted patient's gene id should be an Ensembl id assert mme_formatted_patient["genomicFeatures"][0]["gene"][ "id"].startswith("ENSG") assert mme_formatted_patient["genomicFeatures"][0]["gene"][ "_geneName"] # it's "KARS"
def test_mme_patient_gene_symbol(gpx4_patients, database): # Test format a patient with gene symbol test_patient = gpx4_patients[0] # Before conversion patient's gene id is a gene symbol assert test_patient['genomicFeatures'][0]['gene']['id'].startswith( 'ENSG') is False mme_formatted_patient = mme_patient(test_patient, True) # Convert gene symbol to Ensembl # After conversion formatted patient's gene id should be an Ensembl id assert mme_formatted_patient['genomicFeatures'][0]['gene'][ 'id'].startswith('ENSG')
def test_cli_remove_patient(mock_app, database, gpx4_patients, match_objs): runner = mock_app.test_cli_runner() # add a test patient to database test_patient = mme_patient( gpx4_patients[0], True) # True --> convert gene symbols to ensembl inserted_id = mock_app.db["patients"].insert_one(test_patient).inserted_id assert inserted_id == gpx4_patients[0]["id"] # there is now 1 patient in database assert database["patients"].find_one() # test that without a valid id or label no patient is removed result = runner.invoke(cli, ["remove", "patient", "-id", "", "-label", ""]) assert "Error" in result.output # Add mock patient matches objects to database database["matches"].insert_many(match_objs) # There should be 2 matches in database for this patient: results = database["matches"].find({"data.patient.id": inserted_id}) assert len(list(results)) == 2 # involke cli command to remove the patient by id and label result = runner.invoke(cli, [ "remove", "patient", "-id", inserted_id, "-label", "350_1-test", "-leave_matches" ]) assert result.exit_code == 0 # check that the patient was removed from database assert database["patients"].find_one() is None # But matches are still there results = database["matches"].find({"data.patient.id": inserted_id}) assert len(list(results)) == 2 # Run remove patient command with option to remove matches but without patient ID result = runner.invoke( cli, ["remove", "patient", "-label", "350_1-test", "-remove_matches"]) # And make sure that it doesn't work assert "Please provide patient ID and not label to remove all its matches." in result.output # Test now the proper command to remove patient matches: result = runner.invoke( cli, ["remove", "patient", "-id", inserted_id, "-remove_matches"]) assert result.exit_code == 0 # And make sure that patient removal removed its matchings assert database["matches"].find_one({"data.patient.id": inserted_id }) is None
def test_mme_patient_gene_symbol(gpx4_patients, database): # Test format a patient with HGNC gene symbol test_patient = gpx4_patients[0] gene_name = test_patient["genomicFeatures"][0]["gene"]["id"] # "GPX4" # Before conversion patient's gene id is a gene symbol assert gene_name.startswith("ENSG") is False mme_formatted_patient = mme_patient(test_patient, True) # Convert gene symbol to Ensembl # After conversion formatted patient's gene id should be an Ensembl id assert mme_formatted_patient["genomicFeatures"][0]["gene"][ "id"].startswith("ENSG") assert mme_formatted_patient["genomicFeatures"][0]["gene"][ "_geneName"] == gene_name
def test_match_hgnc_symbol_patient(mock_app, gpx4_patients, test_client, database): """Testing matching patient with gene symbl against patientMatcher database (internal matching)""" # add an authorized client to database ok_token = test_client['auth_token'] add_node(mongo_db=mock_app.db, obj=test_client, is_client=True) query_patient = {'patient': gpx4_patients[0]} assert query_patient['patient']['genomicFeatures'][0]['gene'][ 'id'] == 'GPX4' # load 2 test patient in mock database assert len(gpx4_patients) == 2 inserted_ids = [] for pat in gpx4_patients: # convert patient in mme patient type (convert also gene to ensembl) mme_pat = mme_patient(pat, True) inserted_ids.append(backend_add_patient(database, mme_pat)) assert len(inserted_ids) == 2 # test the API response validator with non valid patient data: malformed_match_results = {'results': 'fakey_results'} assert validate_response(malformed_match_results) == 422 # make sure that there are no patient matches in the 'matches collection' assert database['matches'].find().count() == 0 # send a POST request to match patient with patients in database response = mock_app.test_client().post('/match', data=json.dumps(query_patient), headers=auth_headers(ok_token)) assert response.status_code == 200 # POST request should be successful data = json.loads(response.data) # data should contain results and the max number of results is as defined in the config file assert len(data['results']) == 2 assert type(data['results']) == list # which is a list assert 'patient' in data['results'][0] # of patients assert 'score' in data['results'][0] # with matching scores assert 'contact' in data['results'][0][ 'patient'] # contact info should be available as well # make sure that there are match object is created in db for this internal matching match = database['matches'].find_one() for res in match['results']: for pat in res['patients']: assert pat['patient'][ 'contact'] # each result should have a contact person assert pat['score']['patient'] > 0
def test_match_entrez_patient(mock_app, test_client, gpx4_patients, database): """Test matching patient with ensembl gene against patientMatcher database (internal matching)""" # add an authorized client to database ok_token = test_client['auth_token'] add_node(mongo_db=mock_app.db, obj=test_client, is_client=True) query_patient = gpx4_patients[0] query_patient = {'patient': gpx4_patients[0]} for feat in query_patient['patient']['genomicFeatures']: feat['gene']['id'] == "2879" # entrez id for GPX4 # load 2 test patient in mock database assert len(gpx4_patients) == 2 inserted_ids = [] for pat in gpx4_patients: # convert patient in mme patient type (convert also gene to ensembl) mme_pat = mme_patient(pat, True) inserted_ids.append(backend_add_patient(database, mme_pat)) assert len(inserted_ids) == 2 # make sure that there are no patient matches in the 'matches collection' assert database['matches'].find_one() is None # send a POST request to match patient with patients in database response = mock_app.test_client().post('/match', data=json.dumps(query_patient), headers=auth_headers(ok_token)) assert response.status_code == 200 # POST request should be successful data = json.loads(response.data) # data should contain results and the max number of results is as defined in the config file assert len(data['results']) == 2 assert type(data['results']) == list # which is a list assert 'patient' in data['results'][0] # of patients assert 'score' in data['results'][0] # with matching scores assert 'contact' in data['results'][0][ 'patient'] # contact info should be available as well # make sure that a match object is created in db for this internal matching match = database['matches'].find_one() for res in match['results']: for pat in res['patients']: assert pat['patient'][ 'contact'] # each result should have a contact person assert pat['score']['patient'] > 0 # and query patient should have hgnc gene symbol saved as non-standard _geneName field assert match['data']['patient']['genomicFeatures'][0]['gene'][ '_geneName'] == 'GPX4'
def test_cli_remove_patient(mock_app, database, gpx4_patients, match_objs): runner = mock_app.test_cli_runner() # add a test patient to database test_patient = mme_patient(gpx4_patients[0], True) # True --> convert gene symbols to ensembl inserted_id = mock_app.db['patients'].insert_one(test_patient).inserted_id assert inserted_id == gpx4_patients[0]['id'] # there is now 1 patient in database assert database['patients'].find().count() == 1 # test that without a valid id or label no patient is removed result = runner.invoke(cli, ['remove', 'patient', '-id', '', '-label', '']) assert 'Error' in result.output # Add mock patient matches objects to database database['matches'].insert_many(match_objs) # There should be 2 matches in database for this patient: assert database['matches'].find( {'data.patient.id' : inserted_id }).count() == 2 # involke cli command to remove the patient by id and label result = runner.invoke(cli, ['remove', 'patient', '-id', inserted_id, '-label', '350_1-test', '-leave_matches']) assert result.exit_code == 0 # check that the patient was removed from database assert database['patients'].find().count() == 0 # But matches are still there assert database['matches'].find( {'data.patient.id' : inserted_id }).count() == 2 # Run remove patient command with option to remove matches but without patient ID result = runner.invoke(cli, ['remove', 'patient', '-label', '350_1-test', '-remove_matches']) # And make sure that it doesn't work assert 'Please provide patient ID and not label to remove all its matches.' in result.output # Test now the proper command to remove patient matches: result = runner.invoke(cli, ['remove', 'patient', '-id', inserted_id, '-remove_matches']) assert result.exit_code == 0 # And make sure that patient removal removed its matchings assert database['matches'].find( {'data.patient.id' : inserted_id }).count() == 0
def test_match_async_request(mock_app, database, async_response_obj, json_patients, test_node): """This function tests the situation when this server is receiving a request containing results from an asynchronous server""" # send a POST request with no data to the async endpoint response = mock_app.test_client().post('/async_response', headers=unauth_headers()) # server should return a request data is not valid code == 400 assert response.status_code == 400 # provide data object not containing a query id key data = {'key1': 'value1'} response = mock_app.test_client().post('/async_response', data=json.dumps(data), headers=unauth_headers()) # server should return a not authorized response (401) assert response.status_code == 401 # provide data object with query id not previously saved in database data = { 'query_id': async_response_obj['query_id'], 'source': 'fakey node', 'response': { "results": [{ "score": { "patient": 0.8 }, "patient": json_patients[1], }] } } response = mock_app.test_client().post('/async_response', data=json.dumps(data), headers=unauth_headers()) # server should again return a not authorized response (401) assert response.status_code == 401 # save async_response_obj into database mock_app.db['async_responses'].insert_one(async_response_obj) assert mock_app.db['async_responses'].find().count() == 1 # send a response with valid data but query patient is not in database response = mock_app.test_client().post('/async_response', data=json.dumps(data), headers=unauth_headers()) # server should return ok code and an error message assert response.status_code == 200 resp_data = json.loads(response.data) assert resp_data[ 'message'] == 'Error: could not create a valid match object from request data' # convert json test patient in mongodb patient object test_patient = mme_patient(json_patients[0]) # save test patient in database mock_app.db['patients'].insert_one(test_patient) assert mock_app.db['patients'].find().count() == 1 # There should be no match object in database assert mock_app.db['matches'].find().count() == 0 # send a response with valid data # patient object is in database response = mock_app.test_client().post('/async_response', data=json.dumps(data), headers=unauth_headers()) assert response.status_code == 200 resp_data = json.loads(response.data) assert resp_data['message'] == 'results received, many thanks!' # make sure the async response entry was removed from database assert mock_app.db['async_responses'].find({ 'query_id': async_response_obj['query_id'] }).count() == 0 # and that match result was saved to server assert mock_app.db['matches'].find().count() == 1 # re-introduce async response in database for further testing mock_app.db['async_responses'].insert_one(async_response_obj) # test the enpoint by providing a request with no 'response' key data = { 'query_id': async_response_obj['query_id'], 'source': 'fakey node', } response = mock_app.test_client().post('/async_response', data=json.dumps(data), headers=unauth_headers()) # server should return code 400 (data is not valid) assert response.status_code == 400 # test the enpoint by providing a request with 'response' key containing # results not conforming to the API data = { 'query_id': async_response_obj['query_id'], 'source': 'fakey node', 'response': { 'results': ['malformed_result1', 'malformed_result2'] } } response = mock_app.test_client().post('/async_response', data=json.dumps(data), headers=unauth_headers()) # server should return status 422 (Patient data does not conform to API) assert response.status_code == 422
def test_match_external(mock_app, test_client, test_node, database, json_patients): """Testing the view that is sending post request to trigger matches on external nodes""" # add an authorized client to database ok_token = test_client["auth_token"] add_node(mongo_db=mock_app.db, obj=test_client, is_client=True) # required to trigger external matches a_patient = json_patients[0] parsed_patient = mme_patient(a_patient) # insert patient into mock database: assert database["patients"].find_one() is None inserted_id = database["patients"].insert_one(parsed_patient).inserted_id assert database["patients"].find_one() # send an un-authorized match request to server response = mock_app.test_client().post("".join( ["/match/external/", inserted_id])) # server should return 401 (not authorized) assert response.status_code == 401 # send an authorized request with a patient ID that doesn't exist on server: response = mock_app.test_client().post("".join( ["/match/external/", "not_a_valid_ID"]), headers=auth_headers(ok_token)) # Response is valid assert response.status_code == 200 data = json.loads(response.data) # but server returns error assert data[ "message"] == "ERROR. Could not find any patient with ID not_a_valid_ID in database" # there are no matches in mock database assert database["matches"].find_one() is None # after sending an authorized request with a patient ID that exists on database # Check that external matching doesn't work if there are no connected nodes: response = mock_app.test_client().post("".join( ["/match/external/", inserted_id]), headers=auth_headers(ok_token)) assert response.status_code == 200 data = json.loads(response.data) assert data[ "message"] == "Could not find any other node connected to this MatchMaker server" # Try to send a request for a match on a node that does not exist response = mock_app.test_client().post("".join( ["/match/external/", inserted_id, "?node=meh"]), headers=auth_headers(ok_token)) assert response.status_code == 200 data = json.loads(response.data) # And check that node not found is in response message assert data[ "message"] == "ERROR. Could not find any connected node with id meh in database" # insert a connected node add_node(mongo_db=mock_app.db, obj=test_node, is_client=False) # required for external matches # send a request to match patients against all nodes response = mock_app.test_client().post("".join( ["/match/external/", inserted_id]), headers=auth_headers(ok_token)) # Response should be valid assert response.status_code == 200 # And a new match should be created in matches collection assert database["matches"].find_one() # send a request to match patients against the specific existing node: response = mock_app.test_client().post( "".join(["/match/external/", inserted_id, "?node=", test_node["_id"]]), headers=auth_headers(ok_token), ) # Response should be valid assert response.status_code == 200 # And a new match should be created in matches collection. So total matches are 2 results = database["matches"].find() assert len(list(results)) == 2
def test_match_async_request(mock_app, database, async_response_obj, json_patients, test_node): """This function tests the situation when this server is receiving a request containing results from an asynchronous server""" # send a POST request with no data to the async endpoint response = mock_app.test_client().post("/async_response", headers=unauth_headers()) # server should return a request data is not valid code == 400 assert response.status_code == 400 # provide data object not containing a query id key data = {"key1": "value1"} response = mock_app.test_client().post("/async_response", data=json.dumps(data), headers=unauth_headers()) # server should return a not authorized response (401) assert response.status_code == 401 # provide data object with query id not previously saved in database data = { "query_id": async_response_obj["query_id"], "source": "fakey node", "response": { "results": [{ "score": { "patient": 0.8 }, "patient": json_patients[1], }] }, } response = mock_app.test_client().post("/async_response", data=json.dumps(data), headers=unauth_headers()) # server should again return a not authorized response (401) assert response.status_code == 401 # save async_response_obj into database assert mock_app.db["async_responses"].insert_one( async_response_obj).inserted_id # send a response with valid data but query patient is not in database response = mock_app.test_client().post("/async_response", data=json.dumps(data), headers=unauth_headers()) # server should return ok code and an error message assert response.status_code == 200 resp_data = json.loads(response.data) assert resp_data[ "message"] == "Error: could not create a valid match object from request data" # convert json test patient in mongodb patient object test_patient = mme_patient(json_patients[0]) # save test patient in database assert mock_app.db["patients"].insert_one(test_patient).inserted_id # There should be no match object in database assert mock_app.db["matches"].find_one() is None # send a response with valid data # patient object is in database response = mock_app.test_client().post("/async_response", data=json.dumps(data), headers=unauth_headers()) assert response.status_code == 200 resp_data = json.loads(response.data) assert resp_data["message"] == "results received, many thanks!" # make sure the async response entry was removed from database results = mock_app.db["async_responses"].find( {"query_id": async_response_obj["query_id"]}) assert len(list(results)) == 0 # and that match result was saved to server assert mock_app.db["matches"].find_one() # re-introduce async response in database for further testing mock_app.db["async_responses"].insert_one(async_response_obj) # test the enpoint by providing a request with no 'response' key data = { "query_id": async_response_obj["query_id"], "source": "fakey node", } response = mock_app.test_client().post("/async_response", data=json.dumps(data), headers=unauth_headers()) # server should return code 400 (data is not valid) assert response.status_code == 400 # test the enpoint by providing a request with 'response' key containing # results not conforming to the API data = { "query_id": async_response_obj["query_id"], "source": "fakey node", "response": { "results": ["malformed_result1", "malformed_result2"] }, } response = mock_app.test_client().post("/async_response", data=json.dumps(data), headers=unauth_headers()) # server should return status 422 (Patient data does not conform to API) assert response.status_code == 422